Files
Termix/electron/c2s-auth.cjs

79 lines
2.4 KiB
JavaScript

const { randomUUID } = require("node:crypto");
function createC2SAuthBridge(ipcMain, getWindow) {
const pending = new Map();
ipcMain.handle("answer-c2s-auth", (event, id, answer) => {
const item = pending.get(id);
if (!item || item.sender !== event.sender) return false;
if (answer !== null && (typeof answer !== "string" || answer.length > 8192))
return false;
item.finish(answer);
return true;
});
return function attach(ws, tunnelName) {
const active = new Set();
const close = () => {
for (const id of active) pending.get(id)?.finish(null);
ws.off("message", onMessage);
ws.off("close", close);
ws.off("error", close);
};
const onMessage = (raw, binary) => {
if (binary) return;
let message;
try {
message = JSON.parse(raw.toString());
} catch {
return;
}
if (message.type !== "auth-prompt") return;
const window = getWindow();
if (
!window ||
window.isDestroyed() ||
active.size ||
typeof message.requestId !== "string" ||
!["totp", "input", "browser"].includes(message.request?.kind) // plugin-id-ok: SSH prompt kind, not the plugin
) {
ws.close();
return;
}
const sender = window.webContents;
const id = randomUUID();
const finish = (answer) => {
if (!pending.delete(id)) return;
active.delete(id);
clearTimeout(timer);
sender.off("destroyed", cancelled);
sender.off("did-start-loading", cancelled);
if (!sender.isDestroyed())
sender.send("c2s-auth-prompt", { id, closed: true });
if (ws.readyState === 1)
ws.send(
JSON.stringify({
type: "auth-response",
requestId: message.requestId,
answer,
}),
);
if (answer === null) ws.close();
};
const cancelled = () => finish(null);
const timer = setTimeout(cancelled, 60_000);
active.add(id);
pending.set(id, { sender, finish });
sender.once("destroyed", cancelled);
sender.once("did-start-loading", cancelled);
sender.send("c2s-auth-prompt", {
id,
tunnelName,
request: message.request,
});
};
ws.on("message", onMessage);
ws.once("close", close);
ws.once("error", close);
};
}
module.exports = { createC2SAuthBridge };