mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-15 04:43:36 +00:00
v2.3.0
This commit is contained in:
+77
-6
@@ -423,6 +423,7 @@ app.commandLine.appendSwitch("--enable-features=NetworkService");
|
||||
|
||||
let mainWindow = null;
|
||||
let backendProcess = null;
|
||||
let backendStartFailed = false;
|
||||
let tray = null;
|
||||
let isQuitting = false;
|
||||
|
||||
@@ -563,12 +564,21 @@ async function clearElectronJwtCookiesAtStartup() {
|
||||
function getBackendPaths() {
|
||||
if (isDev) {
|
||||
const backendDir = path.join(appRoot, "dist", "backend", "backend");
|
||||
return { entryPath: path.join(backendDir, "starter.js"), backendCwd: backendDir };
|
||||
return {
|
||||
entryPath: path.join(backendDir, "starter.js"),
|
||||
backendCwd: backendDir,
|
||||
};
|
||||
}
|
||||
// fork() does not go through Electron's asar redirector — use the unpacked path
|
||||
const unpackedRoot = appRoot.replace("app.asar", "app.asar.unpacked");
|
||||
const unpackedRoot = appRoot.replace(
|
||||
/app\.asar(?!\.unpacked)/,
|
||||
"app.asar.unpacked",
|
||||
);
|
||||
const backendDir = path.join(unpackedRoot, "dist", "backend", "backend");
|
||||
return { entryPath: path.join(backendDir, "starter.js"), backendCwd: backendDir };
|
||||
return {
|
||||
entryPath: path.join(backendDir, "starter.js"),
|
||||
backendCwd: backendDir,
|
||||
};
|
||||
}
|
||||
|
||||
function getBackendDataDir() {
|
||||
@@ -606,7 +616,10 @@ function startBackendServer() {
|
||||
logToFile(" backendCwd exists:", fs.existsSync(backendCwd));
|
||||
|
||||
backendProcess = fork(entryPath, [], {
|
||||
cwd: backendCwd,
|
||||
cwd:
|
||||
fs.existsSync(backendCwd) && fs.statSync(backendCwd).isDirectory()
|
||||
? backendCwd
|
||||
: dataDir,
|
||||
env: {
|
||||
...process.env,
|
||||
DATA_DIR: dataDir,
|
||||
@@ -645,6 +658,9 @@ function startBackendServer() {
|
||||
|
||||
backendProcess.on("exit", (code, signal) => {
|
||||
logToFile(`Backend process exited with code ${code}, signal ${signal}`);
|
||||
if (!resolved && code !== 0) {
|
||||
backendStartFailed = true;
|
||||
}
|
||||
backendProcess = null;
|
||||
if (!resolved) {
|
||||
resolved = true;
|
||||
@@ -953,7 +969,14 @@ function createWindow() {
|
||||
});
|
||||
|
||||
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
||||
shell.openExternal(url);
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
|
||||
shell.openExternal(url);
|
||||
}
|
||||
} catch {
|
||||
// invalid URL, ignore
|
||||
}
|
||||
return { action: "deny" };
|
||||
});
|
||||
}
|
||||
@@ -1073,12 +1096,60 @@ ipcMain.handle("get-platform", () => {
|
||||
|
||||
ipcMain.handle("get-embedded-server-status", () => {
|
||||
return {
|
||||
running: backendProcess !== null && !backendProcess.killed,
|
||||
running:
|
||||
backendProcess !== null && !backendProcess.killed && !backendStartFailed,
|
||||
embedded: !isDev,
|
||||
dataDir: isDev ? null : getBackendDataDir(),
|
||||
};
|
||||
});
|
||||
|
||||
// OIDC System Browser Authentication (RFC 8252)
|
||||
ipcMain.handle(
|
||||
"oidc-system-browser-auth",
|
||||
async (_event, authUrl, callbackPort) => {
|
||||
const http = require("http");
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const server = http.createServer((req, res) => {
|
||||
const url = new URL(req.url, `http://localhost:${callbackPort}`);
|
||||
if (url.pathname === "/oidc-callback") {
|
||||
const success = url.searchParams.get("success");
|
||||
const error = url.searchParams.get("error");
|
||||
const token = url.searchParams.get("token");
|
||||
|
||||
res.writeHead(200, { "Content-Type": "text/html" });
|
||||
res.end(
|
||||
`<html><body><h2>${success === "true" ? "Authentication successful!" : "Authentication failed."}</h2><p>You can close this tab and return to Termix.</p><script>window.close()</script></body></html>`,
|
||||
);
|
||||
|
||||
server.close();
|
||||
if (success === "true") {
|
||||
resolve({ success: true, token });
|
||||
} else {
|
||||
resolve({
|
||||
success: false,
|
||||
error: error || "Authentication failed",
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(callbackPort, "127.0.0.1", () => {
|
||||
shell.openExternal(authUrl);
|
||||
});
|
||||
|
||||
// Timeout after 5 minutes
|
||||
setTimeout(
|
||||
() => {
|
||||
server.close();
|
||||
reject(new Error("OIDC authentication timed out"));
|
||||
},
|
||||
5 * 60 * 1000,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
ipcMain.handle("get-server-config", () => {
|
||||
try {
|
||||
const userDataPath = app.getPath("userData");
|
||||
|
||||
@@ -43,6 +43,9 @@ contextBridge.exposeInMainWorld("electronAPI", {
|
||||
timeoutMs,
|
||||
),
|
||||
|
||||
oidcSystemBrowserAuth: (authUrl, callbackPort) =>
|
||||
ipcRenderer.invoke("oidc-system-browser-auth", authUrl, callbackPort),
|
||||
|
||||
invoke: (channel, ...args) => ipcRenderer.invoke(channel, ...args),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user