Files
agentdock/console/server/multica-oauth.js

37 lines
1.8 KiB
JavaScript

const LOGIN_URL_PATTERN = /https?:\/\/[^\s]+\/login\?[^\s]+/g;
const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]);
export function parseMulticaLoginOutput(output) {
const matches = String(output || "").match(LOGIN_URL_PATTERN) || [];
const loginUrl = new URL(matches.at(-1) || "");
const callbackUrl = new URL(loginUrl.searchParams.get("cli_callback") || "");
const state = loginUrl.searchParams.get("cli_state") || "";
const port = Number(callbackUrl.port);
if (callbackUrl.protocol !== "http:" || !LOOPBACK_HOSTS.has(callbackUrl.hostname) || callbackUrl.pathname !== "/callback") {
throw new Error("Multica 尚未生成有效的本机回调地址");
}
if (!Number.isInteger(port) || port < 1024 || port > 65535 || !state) {
throw new Error("Multica 登录链接缺少端口或 state");
}
return { loginUrl, callbackUrl, state };
}
export function buildManagedMulticaLoginUrl(output, publicOrigin, sessionId) {
const { loginUrl } = parseMulticaLoginOutput(output);
const managedCallback = new URL(`/api/integrations/multica/oauth/callback/${encodeURIComponent(sessionId)}`, publicOrigin);
loginUrl.searchParams.set("cli_callback", managedCallback.toString());
return loginUrl.toString();
}
export function buildLocalMulticaCallbackUrl(output, query) {
const { callbackUrl, state } = parseMulticaLoginOutput(output);
const returnedState = typeof query?.state === "string" ? query.state : "";
const token = typeof query?.token === "string" ? query.token : "";
if (!token || !returnedState || returnedState !== state) throw new Error("Multica 回调校验失败,请重新发起验证");
callbackUrl.search = "";
callbackUrl.searchParams.set("token", token);
callbackUrl.searchParams.set("state", returnedState);
return callbackUrl.toString();
}