const LOOPBACK_HOSTS = new Set(["localhost", "127.0.0.1", "[::1]"]); export function parseMulticaCallbackUrl(value) { if (typeof value !== "string" || !value || value.length > 12_000) { throw new Error("请粘贴完整的 Multica 回调链接"); } let url; try { url = new URL(value); } catch { throw new Error("回调链接格式不正确"); } const port = Number(url.port); if (url.protocol !== "http:" || !LOOPBACK_HOSTS.has(url.hostname) || url.pathname !== "/callback") { throw new Error("只接受 Multica 生成的 localhost 回调链接"); } if (!Number.isInteger(port) || port < 1024 || port > 65535) { throw new Error("回调链接缺少有效端口"); } if (!url.searchParams.get("token") || !url.searchParams.get("state")) { throw new Error("回调链接缺少 token 或 state"); } return url; } export async function relayMulticaCallback(value, fetchImpl = fetch) { const url = parseMulticaCallbackUrl(value); const response = await fetchImpl(url, { method: "GET", redirect: "manual", signal: AbortSignal.timeout(8_000), }); if (!response.ok) throw new Error(`Multica 回调未被接受 (${response.status})`); return { ok: true }; }