Compare commits

...

1 Commits
main ... master

Author SHA1 Message Date
luo
d651b04e60 fix: complete source from ZIP + add hvigor configs + local debug signing
Some checks are pending
HarmonyOS CI/CD Pipeline / build (push) Waiting to run
HarmonyOS CI/CD Pipeline / publish (push) Blocked by required conditions
2026-06-09 23:44:44 +08:00
87 changed files with 345 additions and 41 deletions

View File

@ -4,7 +4,7 @@
"projectType": "hvigor",
"uri": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap"
},
"buildTask": "",
"extendConfigs": {
@ -13,12 +13,12 @@
},
"subProjects": [
{
"name": "electron",
"name": "web_engine",
"description": "",
"projectType": "hvigor",
"uri": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/electron"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/web_engine"
},
"buildTask": "",
"extendConfigs": {
@ -38,12 +38,12 @@
"dependencyProjects": []
},
{
"name": "web_engine",
"name": "electron",
"description": "",
"projectType": "hvigor",
"uri": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/web_engine"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/electron"
},
"buildTask": "",
"extendConfigs": {
@ -69,25 +69,25 @@
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/electron/src/main/ets"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/web_engine/src/main/ets"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/electron/src/ohosTest/ets"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/web_engine/src/ohosTest/ets"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/web_engine/src/main/ets"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/electron/src/main/ets"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/web_engine/src/ohosTest/ets"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/electron/src/ohosTest/ets"
}
}
],
@ -98,55 +98,55 @@
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/oh_modules"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/oh_modules"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/.hvigor"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/.hvigor"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/build"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/build"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/electron/.test"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/web_engine/.test"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/electron/oh_modules"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/web_engine/oh_modules"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/electron/build"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/web_engine/build"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/web_engine/.test"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/electron/.test"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/web_engine/oh_modules"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/electron/oh_modules"
}
},
{
"url": {
"$type": 1,
"data": "file:///storage/Users/currentUser/Desktop/projects/ohos_electron_hap/web_engine/build"
"data": "file:///storage/Users/currentUser/Desktop/project/ohos_electron_hap/electron/build"
}
}
]

0
AppScope/resources/base/media/app_icon.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

0
AppScope/resources/base/media/icon.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

0
AppScope/resources/base/media/product_logo_32.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

0
AppScope/resources/base/media/startIcon.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -22,21 +22,7 @@
"name": "release"
}
],
"signingConfigs": [
{
"name": "default",
"material": {
"storePassword": "00000020B042E2E9E6BBBB331A5D9B84B52B19468492B675BB26884B09AEB4EE1560934B2270ADBA486243A0BE443394",
"certpath": "/storage/Users/currentUser/appdata/el2/base/com.huawei.devecostudio/files/ohos/config/default_ohos_electron_hap4PU0PdQzlYYcUxXSOoQfdhrl0YhWODdaXilxiORE6vk.cer",
"keyAlias": "debugKey",
"keyPassword": "00000020B042E2E9E6BBBB331A5D9B84B52B19468492B675BB26884B09AEB4EE1560934B2270ADBA486243A0BE443394",
"profile": "/storage/Users/currentUser/appdata/el2/base/com.huawei.devecostudio/files/ohos/config/default_ohos_electron_hap4PU0PdQzlYYcUxXSOoQfdhrl0YhWODdaXilxiORE6vk.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "/storage/Users/currentUser/appdata/el2/base/com.huawei.devecostudio/files/ohos/config/default_ohos_electron_hap4PU0PdQzlYYcUxXSOoQfdhrl0YhWODdaXilxiORE6vk.p12"
},
"type": "HarmonyOS"
}
]
"signingConfigs": []
},
"modules": [
{

0
chromium/build-profile.json5 Executable file → Normal file
View File

0
chromium/hvigorfile.ts Executable file → Normal file
View File

0
chromium/obfuscation-rules.txt Executable file → Normal file
View File

0
chromium/oh-package.json5 Executable file → Normal file
View File

0
chromium/src/main/ets/Application/AbilityStage.ets Executable file → Normal file
View File

0
chromium/src/main/ets/entryability/BrowserAbility.ets Executable file → Normal file
View File

0
chromium/src/main/ets/entryability/EntryAbility.ets Executable file → Normal file
View File

View File

0
chromium/src/main/ets/pages/EmbeddedWindow.ets Executable file → Normal file
View File

0
chromium/src/main/ets/pages/Index.ets Executable file → Normal file
View File

0
chromium/src/main/ets/pages/SubWindow.ets Executable file → Normal file
View File

0
chromium/src/main/ets/pages/WindowNode.ets Executable file → Normal file
View File

0
chromium/src/main/ets/process/CustomChildProcess.ets Executable file → Normal file
View File

0
chromium/src/main/module.json5 Executable file → Normal file
View File

0
chromium/src/main/resources/base/element/color.json Executable file → Normal file
View File

0
chromium/src/main/resources/base/element/string.json Executable file → Normal file
View File

View File

0
chromium/src/main/resources/en_US/element/string.json Executable file → Normal file
View File

0
chromium/src/main/resources/zh_CN/element/string.json Executable file → Normal file
View File

0
chromium/src/ohosTest/ets/test/Ability.test.ets Executable file → Normal file
View File

0
chromium/src/ohosTest/ets/test/List.test.ets Executable file → Normal file
View File

0
chromium/src/ohosTest/ets/testability/TestAbility.ets Executable file → Normal file
View File

0
chromium/src/ohosTest/ets/testability/pages/Index.ets Executable file → Normal file
View File

View File

0
chromium/src/ohosTest/module.json5 Executable file → Normal file
View File

View File

View File

View File

0
chromium/src/test/List.test.ets Executable file → Normal file
View File

0
chromium/src/test/LocalUnit.test.ets Executable file → Normal file
View File

0
electron/build-profile.json5 Executable file → Normal file
View File

View File

@ -0,0 +1,7 @@
{
"modelVersion": "5.0.0",
"dependencies": {
},
"execution": {
}
}

0
electron/hvigorfile.ts Executable file → Normal file
View File

0
electron/libs/arm64-v8a/libadapter.so Executable file → Normal file
View File

0
electron/libs/arm64-v8a/libffmpeg.so Executable file → Normal file
View File

0
electron/obfuscation-rules.txt Executable file → Normal file
View File

0
electron/oh-package.json5 Executable file → Normal file
View File

0
electron/src/main/ets/Application/AbilityStage.ets Executable file → Normal file
View File

0
electron/src/main/ets/entryability/BrowserAbility.ets Executable file → Normal file
View File

0
electron/src/main/ets/entryability/EntryAbility.ets Executable file → Normal file
View File

View File

View File

0
electron/src/main/ets/pages/EmbeddedWindow.ets Executable file → Normal file
View File

0
electron/src/main/ets/pages/Index.ets Executable file → Normal file
View File

0
electron/src/main/ets/pages/StatusBarPage.ets Executable file → Normal file
View File

0
electron/src/main/ets/pages/SubWindow.ets Executable file → Normal file
View File

0
electron/src/main/ets/pages/WindowNode.ets Executable file → Normal file
View File

0
electron/src/main/ets/process/CustomChildProcess.ets Executable file → Normal file
View File

0
electron/src/main/module.json5 Executable file → Normal file
View File

0
electron/src/main/resources/base/element/color.json Executable file → Normal file
View File

0
electron/src/main/resources/base/element/string.json Executable file → Normal file
View File

View File

0
electron/src/ohosTest/ets/test/Ability.test.ets Executable file → Normal file
View File

0
electron/src/ohosTest/ets/test/List.test.ets Executable file → Normal file
View File

0
electron/src/ohosTest/ets/testability/TestAbility.ets Executable file → Normal file
View File

0
electron/src/ohosTest/ets/testability/pages/Index.ets Executable file → Normal file
View File

View File

0
electron/src/ohosTest/module.json5 Executable file → Normal file
View File

View File

View File

View File

0
electron/src/test/List.test.ets Executable file → Normal file
View File

0
electron/src/test/LocalUnit.test.ets Executable file → Normal file
View File

0
hvigor/hvigor-config.json5 Executable file → Normal file
View File

View File

@ -2,8 +2,8 @@
* Use these variables when you tailor your ArkTS code. They must be of the const type.
*/
export const HAR_VERSION = '1.0.0';
export const BUILD_MODE_NAME = 'debug';
export const DEBUG = true;
export const BUILD_MODE_NAME = 'release';
export const DEBUG = false;
export const TARGET_NAME = 'default';
/**

0
web_engine/childProcess.ets Executable file → Normal file
View File

View File

@ -0,0 +1,7 @@
{
"modelVersion": "5.0.0",
"dependencies": {
},
"execution": {
}
}

0
web_engine/src/main/ets/adapter/DialogAdapter.ets Executable file → Normal file
View File

0
web_engine/src/main/ets/adapter/ElectronAppAdapter.ets Executable file → Normal file
View File

0
web_engine/src/main/ets/adapter/StatusBarManager.ets Executable file → Normal file
View File

0
web_engine/src/main/ets/common/WindowStyle.ets Executable file → Normal file
View File

0
web_engine/src/main/ets/components/MessageBox.ets Executable file → Normal file
View File

View File

View File

View File

0
web_engine/src/main/resources/resfile/electron Executable file → Normal file
View File

View File

@ -81,6 +81,15 @@ async function listWindowsHiddenBasenames(dirPath) {
}
}
let _homeDirOverride = null;
/**
* Set a custom home directory (e.g., for HarmonyOS sandbox workaround)
*/
function init(deps) {
if (deps?.homeDir) _homeDirOverride = deps.homeDir;
}
/**
* List files in a local directory
* Properly handles symlinks by resolving their target type
@ -299,7 +308,7 @@ async function listLocalTree(event, payload) {
* Get the home directory
*/
async function getHomeDir() {
return os.homedir();
return _homeDirOverride || os.homedir();
}
/**
@ -316,7 +325,7 @@ async function getSystemInfo() {
* Read system known_hosts file
*/
async function readKnownHosts() {
const homeDir = os.homedir();
const homeDir = _homeDirOverride || os.homedir();
const knownHostsPaths = [];
if (process.platform === "win32") {
@ -366,6 +375,7 @@ function registerHandlers(ipcMain) {
}
module.exports = {
init,
registerHandlers,
listLocalDir,
readLocalFile,

View File

@ -16,12 +16,306 @@
// HarmonyOS: the full main.cjs startup (80+ bridge requires, GPU switches,
// protocol registration, etc.) causes SIGSEGV in V8. Use minimal init.
if (process.platform === 'ohos' || process.platform === 'openharmony') {
const { app, BrowserWindow } = require("electron");
const { app, BrowserWindow, protocol, dialog } = require("electron");
const path = require("path");
const fs = require("fs");
// HarmonyOS sandbox blocks os.homedir(). Use saved or picked path.
(() => {
const saveFile = path.join(app.getPath("userData"), "local_home.txt");
try {
const saved = fs.readFileSync(saveFile, "utf8").trim();
if (saved && fs.existsSync(saved)) {
process.env.HOME = saved;
console.log("OHOS: loaded saved HOME:", saved);
return;
}
} catch {}
// First run — use desktop path (may or may not work)
process.env.HOME = app.getPath("desktop");
console.log("OHOS: default HOME:", process.env.HOME);
})();
// Register ncapp:// protocol with CORS headers (needed for SPA routing)
const APP_HEADERS = {
"Cross-Origin-Opener-Policy": "same-origin",
"Cross-Origin-Embedder-Policy": "credentialless",
};
const MIME = {
".html": "text/html", ".js": "text/javascript", ".mjs": "text/javascript",
".css": "text/css", ".json": "application/json", ".png": "image/png",
".svg": "image/svg+xml", ".ico": "image/x-icon", ".woff2": "font/woff2",
".wasm": "application/wasm",
};
const distPath = path.join(__dirname, "..", "dist");
try {
protocol.handle("ncapp", async (req) => {
const u = new URL(req.url);
let p = u.pathname.replace(/^\/+/, "") || "index.html";
const full = path.join(distPath, p);
if (!full.startsWith(distPath)) return new Response("Forbidden", { status: 403 });
try {
const data = await fs.promises.readFile(full);
const ext = path.extname(full).toLowerCase();
return new Response(data, {
status: 200,
headers: { ...APP_HEADERS, "Content-Type": MIME[ext] || "application/octet-stream" },
});
} catch { return new Response("Not Found", { status: 404 }); }
});
} catch(e) { console.log("protocol.handle failed:", e.message); }
// === Bridge loading (same order as working version) ===
// Step 1: terminalBridge
console.log("OHOS: loading terminalBridge...");
try { require("./bridges/terminalBridge.cjs"); } catch(e) { console.log("terminalBridge FAILED:", e.message); }
console.log("OHOS: terminalBridge OK");
// Step 2: sshBridge
console.log("OHOS: loading sshBridge...");
try { require("./bridges/sshBridge.cjs"); } catch(e) { console.log("sshBridge FAILED:", e.message); }
console.log("OHOS: sshBridge OK");
// Step 3: sftpBridge
console.log("OHOS: loading sftpBridge...");
try { require("./bridges/sftpBridge.cjs"); } catch(e) { console.log("sftpBridge FAILED:", e.message); }
console.log("OHOS: sftpBridge OK");
// Step 4: localFsBridge
console.log("OHOS: loading localFsBridge...");
try { require("./bridges/localFsBridge.cjs"); } catch(e) { console.log("localFsBridge FAILED:", e.message); }
console.log("OHOS: localFsBridge OK");
// Step 5: transferBridge
console.log("OHOS: loading transferBridge...");
try { require("./bridges/transferBridge.cjs"); } catch(e) { console.log("transferBridge FAILED:", e.message); }
console.log("OHOS: transferBridge OK");
// Step 6: portForwardingBridge
console.log("OHOS: loading portForwardingBridge...");
try { require("./bridges/portForwardingBridge.cjs"); } catch(e) { console.log("portForwardingBridge FAILED:", e.message); }
console.log("OHOS: portForwardingBridge OK");
// Step 7: sessionLogStreamManager
console.log("OHOS: loading sessionLogStreamManager...");
try { require("./bridges/sessionLogStreamManager.cjs"); } catch(e) { console.log("sessionLogStreamManager FAILED:", e.message); }
console.log("OHOS: sessionLogStreamManager OK");
// Step 8: crashLogBridge
console.log("OHOS: loading crashLogBridge...");
try { require("./bridges/crashLogBridge.cjs"); } catch(e) { console.log("crashLogBridge FAILED:", e.message); }
console.log("OHOS: crashLogBridge OK");
// Step 9: ptyProcessTree
console.log("OHOS: loading ptyProcessTree...");
try { require("./bridges/ptyProcessTree.cjs"); } catch(e) { console.log("ptyProcessTree FAILED:", e.message); }
console.log("OHOS: ptyProcessTree OK");
// Step 10-24: remaining lazy bridges
const lazyBridges = [
"oauthBridge", "githubAuthBridge", "googleAuthBridge", "onedriveAuthBridge",
"cloudSyncBridge", "fileWatcherBridge", "tempDirBridge", "sessionLogsBridge",
"compressUploadBridge", "globalShortcutBridge", "credentialBridge",
"autoUpdateBridge", "aiBridge", "windowManager", "vaultBackupBridge",
];
for (const name of lazyBridges) {
console.log("OHOS: loading " + name + "...");
try { require("./bridges/" + name + ".cjs"); } catch(e) { console.log(name + " FAILED:", e.message); }
console.log("OHOS: " + name + " OK");
}
// === Bridge init + registerHandlers ===
const { ipcMain } = require("electron");
const { getCliDiscoveryFilePath } = require("./cli/discoveryPath.cjs");
const sessions = new Map();
const sftpClients = new Map();
const deps = {
sessions, sftpClients,
electronModule: require("electron"),
cliDiscoveryFilePath: getCliDiscoveryFilePath({ userDataDir: app.getPath("userData") }),
};
// sshBridge
const sshBridge = require("./bridges/sshBridge.cjs");
console.log("OHOS: sshBridge.init...");
try {
sshBridge.init(deps);
console.log("OHOS: sshBridge.init OK");
sshBridge.registerHandlers(ipcMain);
console.log("OHOS: sshBridge.registerHandlers OK");
} catch(e) { console.log("sshBridge init/register FAILED:", e.message); }
// sftpBridge
const sftpBridge = require("./bridges/sftpBridge.cjs");
console.log("OHOS: sftpBridge.init...");
try {
sftpBridge.init(deps);
console.log("OHOS: sftpBridge.init OK");
sftpBridge.registerHandlers(ipcMain);
console.log("OHOS: sftpBridge.registerHandlers OK");
} catch(e) { console.log("sftpBridge init/register FAILED:", e.message); }
// terminalBridge
const terminalBridge = require("./bridges/terminalBridge.cjs");
console.log("OHOS: terminalBridge.init...");
try {
terminalBridge.init(deps);
console.log("OHOS: terminalBridge.init OK");
terminalBridge.registerHandlers(ipcMain);
console.log("OHOS: terminalBridge.registerHandlers OK");
} catch(e) { console.log("terminalBridge init/register FAILED:", e.message); }
// transferBridge
const transferBridge = require("./bridges/transferBridge.cjs");
console.log("OHOS: transferBridge.init...");
try {
transferBridge.init(deps);
console.log("OHOS: transferBridge.init OK");
transferBridge.registerHandlers(ipcMain);
console.log("OHOS: transferBridge.registerHandlers OK");
} catch(e) { console.log("transferBridge init/register FAILED:", e.message); }
// localFsBridge — init with homeDir to work around OHOS sandbox
const localFsBridge = require("./bridges/localFsBridge.cjs");
console.log("OHOS: localFsBridge.init (homeDir)...");
try {
const homeDir = app.getPath("desktop");
console.log("OHOS: homeDir =", homeDir);
localFsBridge.init({ homeDir });
console.log("OHOS: localFsBridge.init OK");
} catch(e) { console.log("localFsBridge.init FAILED:", e.message); }
console.log("OHOS: localFsBridge.registerHandlers...");
try {
localFsBridge.registerHandlers(ipcMain);
console.log("OHOS: localFsBridge OK");
} catch(e) { console.log("localFsBridge FAILED:", e.message); }
// portForwardingBridge
const portForwardingBridge = require("./bridges/portForwardingBridge.cjs");
console.log("OHOS: portForwardingBridge.registerHandlers...");
try {
portForwardingBridge.registerHandlers(ipcMain);
console.log("OHOS: portForwardingBridge OK");
} catch(e) { console.log("portForwardingBridge FAILED:", e.message); }
// crashLogBridge
const crashLogBridge = require("./bridges/crashLogBridge.cjs");
console.log("OHOS: crashLogBridge.init...");
try {
crashLogBridge.init(deps);
console.log("OHOS: crashLogBridge.init OK");
crashLogBridge.registerHandlers(ipcMain);
console.log("OHOS: crashLogBridge.registerHandlers OK");
} catch(e) { console.log("crashLogBridge FAILED:", e.message); }
// Remaining bridges — registerHandlers only (matching working version)
const rem = [
["oauthBridge", (b) => b.setupOAuthBridge(ipcMain)],
["githubAuthBridge", (b) => b.registerHandlers(ipcMain)],
["googleAuthBridge", (b) => b.registerHandlers(ipcMain, { app, BrowserWindow })],
["onedriveAuthBridge",(b) => b.registerHandlers(ipcMain, { app, BrowserWindow })],
["cloudSyncBridge", (b) => b.registerHandlers(ipcMain)],
["fileWatcherBridge", (b) => b.registerHandlers(ipcMain)],
["tempDirBridge", (b) => b.registerHandlers(ipcMain, require("electron").shell)],
["sessionLogsBridge", (b) => b.registerHandlers(ipcMain)],
["compressUploadBridge", (b) => { b.init({...deps, transferBridge}); b.registerHandlers(ipcMain); }],
["globalShortcutBridge",(b) => b.registerHandlers(ipcMain)],
["credentialBridge", (b) => b.registerHandlers(ipcMain, { app, BrowserWindow })],
["autoUpdateBridge", (b) => { b.init(deps); b.registerHandlers(ipcMain); }],
["aiBridge", (b) => b.registerHandlers(ipcMain)],
["vaultBackupBridge", (b) => b.registerHandlers(ipcMain, { app, BrowserWindow })],
];
for (const [name, fn] of rem) {
console.log("OHOS: " + name + "...");
try {
const b = require("./bridges/" + name + ".cjs");
fn(b);
console.log("OHOS: " + name + " OK");
} catch(e) { console.log(name + " FAILED:", e.message); }
}
// windowManager handlers (theme, window controls)
const windowManager = require("./bridges/windowManager.cjs");
const { nativeTheme } = require("electron");
console.log("OHOS: windowManager.registerWindowHandlers...");
try {
windowManager.registerWindowHandlers(ipcMain, nativeTheme);
console.log("OHOS: windowManager OK");
} catch(e) { console.log("windowManager FAILED:", e.message); }
// app:getInfo — needed by frontend
ipcMain.handle("netcatty:app:getInfo", async () => ({
name: app.getName(),
version: app.getVersion(),
platform: process.platform,
}));
console.log("OHOS: app:getInfo registered");
// One-time home directory picker (triggers when local FS gets EPERM)
ipcMain.handle("netcatty:local:select-home", async () => {
const win = BrowserWindow.getAllWindows()[0];
if (!win) return { path: process.env.HOME };
const result = await dialog.showOpenDialog(win, {
properties: ["openDirectory"],
title: "选择本地文件根目录(选一次,以后记住)",
});
if (!result.canceled && result.filePaths.length > 0) {
const picked = result.filePaths[0];
process.env.HOME = picked;
try {
fs.writeFileSync(path.join(app.getPath("userData"), "local_home.txt"), picked);
} catch {}
console.log("OHOS: HOME updated to", picked);
return { path: picked };
}
return { path: process.env.HOME };
});
console.log("OHOS: local:select-home registered");
app.whenReady().then(() => {
const distIndex = path.join(__dirname, "..", "dist", "index.html");
const win = new BrowserWindow({ width: 1280, height: 800, show: true });
const preload = path.join(__dirname, "preload.cjs");
const win = new BrowserWindow({
width: 1280, height: 800, show: true,
frame: false,
webPreferences: {
preload: preload,
nodeIntegration: false,
contextIsolation: true,
sandbox: false,
},
});
win.webContents.openDevTools();
win.loadURL("file://" + distIndex);
// Auto-detect: if HOME is not accessible, show one-time file picker
win.webContents.on("did-finish-load", async () => {
try {
await fs.promises.readdir(process.env.HOME);
console.log("OHOS: HOME accessible:", process.env.HOME);
} catch (e) {
if (e.code === "EPERM" || e.code === "ENOENT") {
console.log("OHOS: HOME blocked, showing picker...");
const result = await dialog.showOpenDialog(win, {
properties: ["openDirectory"],
title: "选择本地文件根目录(选一次,以后记住)",
});
if (!result.canceled && result.filePaths.length > 0) {
process.env.HOME = result.filePaths[0];
try {
fs.writeFileSync(path.join(app.getPath("userData"), "local_home.txt"), result.filePaths[0]);
} catch {}
console.log("OHOS: HOME updated to", process.env.HOME);
win.webContents.reload();
}
}
}
});
});
return;
}

View File

@ -1514,7 +1514,7 @@ const figSpecApi = {
const existing = (typeof window !== "undefined" && window.netcatty) ? window.netcatty : {};
function getAllowedRendererOrigins() {
const origins = new Set(["app://netcatty"]);
const origins = new Set(["app://netcatty", "file://", "null"]);
const devServerUrl = process.env.VITE_DEV_SERVER_URL;
if (typeof devServerUrl === "string" && devServerUrl.length > 0) {
try {

View File