You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
3.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 宿主(如 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=***
*/
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;
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" };
}
/** 登录成功后从地址栏去掉敏感参数,避免 Key 留在历史记录 */
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";
}