38 lines
1.2 KiB
JavaScript
38 lines
1.2 KiB
JavaScript
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 };
|
|
}
|