/** * 宿主(如 CC)嵌入 /embed-demo 时的 SSO 查询参数解析。 * 例:/embed-demo?login_type=api_key&api_key=chj_xxx * /embed-demo?type=api_key&key=chj_xxx * /embed-demo?login_type=password&customer_id=CUST_001&password=*** * /embed-demo?...&module=MS_LOGGED_IN * /embed-demo?...&entry=ms_logged_in */ import { isChajiaModuleId, type ChajiaModuleId, } from "@/lib/embed/host-bridge"; export type EmbedSsoLoginType = "password" | "api_key"; export type EmbedSsoParams = | { mode: "api_key"; apiKey: string } | { mode: "password"; customerId: string; password: string } | { mode: "none" }; const SENSITIVE_QUERY_KEYS = [ "login_type", "type", "lt", "api_key", "key", "token", "password", "pwd", "customer_id", "customerId", ] as const; const ENTRY_ALIAS: Record = { ms_guest: "MS_GUEST", ms_logged_in: "MS_LOGGED_IN", mothership_guest: "MS_GUEST", mothership_logged_in: "MS_LOGGED_IN", flock_guest: "FLOCK_GUEST", flock_logged_in: "FLOCK_LOGGED_IN", }; function firstParam( params: URLSearchParams, keys: readonly string[], ): string { for (const k of keys) { const v = params.get(k)?.trim(); if (v) return v; } return ""; } function resolveLoginType(params: URLSearchParams): EmbedSsoLoginType | null { const raw = firstParam(params, ["login_type", "type", "lt"]).toLowerCase(); if (!raw) { // 有 key 无 type 时默认按 API Key if (firstParam(params, ["api_key", "key", "token"])) return "api_key"; if ( firstParam(params, ["customer_id", "customerId"]) && firstParam(params, ["password", "pwd"]) ) { return "password"; } return null; } if (raw === "api_key" || raw === "apikey" || raw === "key") return "api_key"; if (raw === "password" || raw === "pwd" || raw === "account") return "password"; return null; } /** 从 URLSearchParams 解析宿主直传凭证 */ export function parseEmbedSsoParams(params: URLSearchParams): EmbedSsoParams { const loginType = resolveLoginType(params); if (loginType === "api_key") { const apiKey = firstParam(params, ["api_key", "key", "token"]); if (!apiKey) return { mode: "none" }; return { mode: "api_key", apiKey }; } if (loginType === "password") { const customerId = firstParam(params, ["customer_id", "customerId"]); const password = firstParam(params, ["password", "pwd"]); if (!customerId || !password) return { mode: "none" }; return { mode: "password", customerId, password }; } return { mode: "none" }; } /** * 解析直进模块:`module=MS_LOGGED_IN` 或 `entry=ms_logged_in` * 登录成功后可跳过门户点选,直接进对应查价表单。 */ export function parseEmbedEntryModule( params: URLSearchParams, ): ChajiaModuleId | null { const moduleRaw = firstParam(params, ["module", "quote_module"]); if (moduleRaw) { const upper = moduleRaw.toUpperCase().replace(/-/g, "_"); if (isChajiaModuleId(upper)) return upper; const aliased = ENTRY_ALIAS[moduleRaw.toLowerCase()]; if (aliased) return aliased; } const entryRaw = firstParam(params, ["entry", "default_module"]); if (!entryRaw) return null; const aliased = ENTRY_ALIAS[entryRaw.toLowerCase().replace(/-/g, "_")]; if (aliased) return aliased; const upper = entryRaw.toUpperCase().replace(/-/g, "_"); return isChajiaModuleId(upper) ? upper : null; } /** 登录成功后从地址栏去掉敏感参数,避免 Key 留在历史记录(保留 module/entry) */ export function stripEmbedSsoQueryFromUrl(): void { if (typeof window === "undefined") return; const url = new URL(window.location.href); let changed = false; for (const key of SENSITIVE_QUERY_KEYS) { if (url.searchParams.has(key)) { url.searchParams.delete(key); changed = true; } } if (!changed) return; const next = `${url.pathname}${url.search}${url.hash}`; window.history.replaceState(window.history.state, "", next); } /** 是否宿主嵌入精简壳(隐藏退出等) */ export function isEmbedHostedShell(params: URLSearchParams): boolean { const flag = firstParam(params, ["embed", "hosted", "from_cc", "from_host"]); if (flag === "1" || flag === "true" || flag === "yes") return true; // 带 SSO 凭证进入亦视为宿主托管 return parseEmbedSsoParams(params).mode !== "none"; }