chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,398 @@
|
||||
/**
|
||||
* TokenExtractionConfig — Login & cookie extraction configs for web-cookie providers
|
||||
*
|
||||
* Each config describes how to:
|
||||
* 1. Open a browser window/navigate to the provider's login page
|
||||
* 2. Detect successful login (URL change + token presence)
|
||||
* 3. Extract session cookies / tokens from the browser context
|
||||
*
|
||||
* Used by InAppLoginService (Electron BrowserWindow path) and
|
||||
* the Playwright-based login flow (dashboard API).
|
||||
*/
|
||||
|
||||
// ─── Types ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Describes where to extract credential data from after login */
|
||||
export type TokenSource =
|
||||
| { type: "cookie"; name: string; domain?: string }
|
||||
| { type: "localStorage"; key: string }
|
||||
| { type: "sessionStorage"; key: string }
|
||||
| { type: "header"; name: string };
|
||||
|
||||
export interface PollingConfig {
|
||||
/** Milliseconds between extraction polls (default 1000) */
|
||||
pollInterval: number;
|
||||
/** Total timeout in ms (default 300000 = 5 min) */
|
||||
timeout: number;
|
||||
/** Minimum time in ms before first extraction attempt (default 5000) */
|
||||
minLoginTime: number;
|
||||
}
|
||||
|
||||
export interface TokenExtractionConfig {
|
||||
/** Matches the executor's provider ID (e.g. "claude-web", "gemini-web") */
|
||||
providerId: string;
|
||||
/** Human-readable name shown in dashboard UI */
|
||||
displayName: string;
|
||||
/** The URL to navigate to for login */
|
||||
loginUrl: string;
|
||||
/** The provider's home page URL (for cookie domain binding) */
|
||||
homeUrl: string;
|
||||
/** Optional regex. If current URL matches → login is likely complete */
|
||||
successUrlPattern?: RegExp;
|
||||
/** Sources to extract credentials from after login */
|
||||
tokenSources: TokenSource[];
|
||||
/** Polling behaviour */
|
||||
pollingConfig: PollingConfig;
|
||||
/** Short instructions shown to the user in the login modal */
|
||||
instructions: string;
|
||||
/** Optional: cookie domain override for cookie injection */
|
||||
cookieDomain?: string;
|
||||
}
|
||||
|
||||
// ─── Defaults ───────────────────────────────────────────────────────────────
|
||||
|
||||
const DEFAULT_POLLING: PollingConfig = {
|
||||
pollInterval: 1000,
|
||||
timeout: 300_000,
|
||||
minLoginTime: 5000,
|
||||
};
|
||||
|
||||
const QUICK_POLLING: PollingConfig = {
|
||||
pollInterval: 800,
|
||||
timeout: 120_000,
|
||||
minLoginTime: 3000,
|
||||
};
|
||||
|
||||
// ─── Helper ──────────────────────────────────────────────────────────────────
|
||||
|
||||
function config(
|
||||
providerId: string,
|
||||
displayName: string,
|
||||
loginUrl: string,
|
||||
homeUrl: string,
|
||||
tokenSources: TokenSource[],
|
||||
instructions: string,
|
||||
opts?: {
|
||||
successUrlPattern?: RegExp;
|
||||
pollingConfig?: Partial<PollingConfig>;
|
||||
cookieDomain?: string;
|
||||
}
|
||||
): TokenExtractionConfig {
|
||||
return {
|
||||
providerId,
|
||||
displayName,
|
||||
loginUrl,
|
||||
homeUrl,
|
||||
tokenSources,
|
||||
instructions,
|
||||
pollingConfig: { ...DEFAULT_POLLING, ...opts?.pollingConfig },
|
||||
successUrlPattern: opts?.successUrlPattern,
|
||||
cookieDomain: opts?.cookieDomain,
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Configuration Map ──────────────────────────────────────────────────────
|
||||
|
||||
const RAW_CONFIGS: TokenExtractionConfig[] = [
|
||||
// ── Claude Web ────────────────────────────────────────────
|
||||
config(
|
||||
"claude-web",
|
||||
"Claude Web",
|
||||
"https://claude.ai/login",
|
||||
"https://claude.ai",
|
||||
[{ type: "cookie", name: "sessionKey", domain: ".claude.ai" }],
|
||||
"Log in to your Claude account at claude.ai. After login, the session cookie will be extracted automatically."
|
||||
),
|
||||
|
||||
// ── ChatGPT Web ───────────────────────────────────────────
|
||||
config(
|
||||
"chatgpt-web",
|
||||
"ChatGPT Web",
|
||||
"https://chatgpt.com/auth/login",
|
||||
"https://chatgpt.com",
|
||||
[{ type: "cookie", name: "__Secure-next-auth.session-token", domain: ".chatgpt.com" }],
|
||||
"Log in to ChatGPT. The __Secure-next-auth.session-token cookie will be extracted after login."
|
||||
),
|
||||
|
||||
// ── Gemini Web ────────────────────────────────────────────
|
||||
config(
|
||||
"gemini-web",
|
||||
"Gemini Web",
|
||||
"https://gemini.google.com/app",
|
||||
"https://gemini.google.com",
|
||||
[
|
||||
{ type: "cookie", name: "__Secure-1PSID", domain: ".google.com" },
|
||||
{ type: "cookie", name: "__Secure-1PSIDTS", domain: ".google.com" },
|
||||
],
|
||||
"Log in to your Google account at gemini.google.com. Both __Secure-1PSID and __Secure-1PSIDTS cookies will be extracted.",
|
||||
{ cookieDomain: ".google.com" }
|
||||
),
|
||||
|
||||
// ── Grok Web ──────────────────────────────────────────────
|
||||
config(
|
||||
"grok-web",
|
||||
"Grok Web",
|
||||
"https://grok.com/login",
|
||||
"https://grok.com",
|
||||
[{ type: "cookie", name: "sso", domain: ".grok.com" }],
|
||||
"Log in to your xAI account at grok.com. The sso session cookie will be extracted."
|
||||
),
|
||||
|
||||
// ── Perplexity Web ────────────────────────────────────────
|
||||
config(
|
||||
"perplexity-web",
|
||||
"Perplexity Web",
|
||||
"https://www.perplexity.ai/login",
|
||||
"https://www.perplexity.ai",
|
||||
[{ type: "cookie", name: "__Secure-next-auth.session-token", domain: ".perplexity.ai" }],
|
||||
"Log in to Perplexity. The __Secure-next-auth.session-token cookie will be extracted.",
|
||||
{ cookieDomain: ".perplexity.ai" }
|
||||
),
|
||||
|
||||
// ── DeepSeek Web ──────────────────────────────────────────
|
||||
config(
|
||||
"deepseek-web",
|
||||
"DeepSeek Web",
|
||||
"https://chat.deepseek.com/sign_in",
|
||||
"https://chat.deepseek.com",
|
||||
[
|
||||
{ type: "cookie", name: "user-token", domain: ".deepseek.com" },
|
||||
{ type: "localStorage", key: "userToken" },
|
||||
],
|
||||
"Log in to DeepSeek at chat.deepseek.com. The user-token cookie will be extracted.",
|
||||
{ cookieDomain: ".deepseek.com" }
|
||||
),
|
||||
|
||||
// ── Qwen Web ──────────────────────────────────────────────
|
||||
// The v2 API sits behind Alibaba's "baxia" WAF, which needs the full browser
|
||||
// cookie jar (cna + ssxmod_itna/itna2 + token), not just the bearer token.
|
||||
// Capture the WAF cookies alongside the localStorage token (#3288).
|
||||
config(
|
||||
"qwen-web",
|
||||
"Qwen Web (Tongyi)",
|
||||
"https://chat.qwen.ai/",
|
||||
"https://chat.qwen.ai",
|
||||
[
|
||||
{ type: "localStorage", key: "token" },
|
||||
{ type: "cookie", name: "token", domain: ".chat.qwen.ai" },
|
||||
{ type: "cookie", name: "cna", domain: ".chat.qwen.ai" },
|
||||
{ type: "cookie", name: "ssxmod_itna", domain: ".chat.qwen.ai" },
|
||||
{ type: "cookie", name: "ssxmod_itna2", domain: ".chat.qwen.ai" },
|
||||
{ type: "cookie", name: "XSRF_TOKEN", domain: ".chat.qwen.ai" },
|
||||
],
|
||||
"Log in to Qwen at chat.qwen.ai using your Alibaba account. The session token and the " +
|
||||
"Alibaba WAF cookies (cna, ssxmod_itna) will be extracted — all are required by the v2 API.",
|
||||
{ cookieDomain: ".chat.qwen.ai" }
|
||||
),
|
||||
|
||||
// ── Kimi Web ──────────────────────────────────────────────
|
||||
config(
|
||||
"kimi-web",
|
||||
"Kimi (Moonshot)",
|
||||
"https://www.kimi.com/",
|
||||
"https://www.kimi.com",
|
||||
[{ type: "cookie", name: "kimi-auth", domain: ".kimi.com" }],
|
||||
"Log in to Kimi at www.kimi.com (international). The kimi-auth JWT cookie will be extracted.",
|
||||
{ cookieDomain: ".kimi.com" }
|
||||
),
|
||||
|
||||
// ── Blackbox Web ──────────────────────────────────────────
|
||||
config(
|
||||
"blackbox-web",
|
||||
"Blackbox AI",
|
||||
"https://app.blackbox.ai/login",
|
||||
"https://app.blackbox.ai",
|
||||
[
|
||||
{ type: "cookie", name: "connect.sid", domain: ".blackbox.ai" },
|
||||
{ type: "localStorage", key: "token" },
|
||||
],
|
||||
"Log in to Blackbox AI at app.blackbox.ai using Google/GitHub. The session cookie will be extracted.",
|
||||
{ cookieDomain: ".blackbox.ai" }
|
||||
),
|
||||
|
||||
// ── Poe Web ───────────────────────────────────────────────
|
||||
config(
|
||||
"poe-web",
|
||||
"Poe (Quora)",
|
||||
"https://poe.com/login",
|
||||
"https://poe.com",
|
||||
[{ type: "cookie", name: "p-b", domain: ".poe.com" }],
|
||||
"Log in to Poe at poe.com. The session cookie will be extracted.",
|
||||
{ cookieDomain: ".poe.com" }
|
||||
),
|
||||
|
||||
// ── Copilot Web ───────────────────────────────────────────
|
||||
config(
|
||||
"copilot-web",
|
||||
"Microsoft Copilot",
|
||||
"https://copilot.microsoft.com/",
|
||||
"https://copilot.microsoft.com",
|
||||
[{ type: "cookie", name: "RPSCAuth", domain: ".microsoft.com" }],
|
||||
"Log in with your Microsoft account at copilot.microsoft.com. The session auth cookie will be extracted.",
|
||||
{ cookieDomain: ".microsoft.com" }
|
||||
),
|
||||
|
||||
// ── DuckDuckGo Web ────────────────────────────────────────
|
||||
config(
|
||||
"duckduckgo-web",
|
||||
"DuckDuckGo AI Chat",
|
||||
"https://duckduckgo.com/?q=DuckDuckGo+AI+Chat&ia=chat&duckai=1",
|
||||
"https://duckduckgo.com",
|
||||
[{ type: "cookie", name: "duckai", domain: ".duckduckgo.com" }],
|
||||
"Open DuckDuckGo AI Chat. Some models may require a free account. The duckai cookie will be extracted.",
|
||||
{
|
||||
cookieDomain: ".duckduckgo.com",
|
||||
pollingConfig: QUICK_POLLING,
|
||||
}
|
||||
),
|
||||
|
||||
// ── Dola Web ──────────────────────────────────────────────
|
||||
config(
|
||||
"doubao-web",
|
||||
"Dola (ByteDance)",
|
||||
"https://www.dola.com/",
|
||||
"https://www.dola.com",
|
||||
[
|
||||
{ type: "cookie", name: "sessionid", domain: ".dola.com" },
|
||||
{ type: "cookie", name: "ttwid", domain: ".dola.com" },
|
||||
{ type: "cookie", name: "s_v_web_id", domain: ".dola.com" },
|
||||
],
|
||||
"Log in to Dola at www.dola.com with your ByteDance account. sessionid, ttwid, and s_v_web_id will be extracted.",
|
||||
{ cookieDomain: ".dola.com" }
|
||||
),
|
||||
|
||||
// ── T3 Chat Web ───────────────────────────────────────────
|
||||
config(
|
||||
"t3-chat-web",
|
||||
"T3 Chat",
|
||||
"https://t3.chat/login",
|
||||
"https://t3.chat",
|
||||
[{ type: "localStorage", key: "token" }],
|
||||
"Log in to T3 Chat at t3.chat using Google/GitHub. The token from localStorage will be extracted.",
|
||||
{ pollingConfig: QUICK_POLLING }
|
||||
),
|
||||
|
||||
// ── Venice Web ────────────────────────────────────────────
|
||||
config(
|
||||
"venice-web",
|
||||
"Venice AI",
|
||||
"https://venice.ai/login",
|
||||
"https://venice.ai",
|
||||
[
|
||||
{ type: "cookie", name: "venice_session", domain: ".venice.ai" },
|
||||
{ type: "localStorage", key: "token" },
|
||||
],
|
||||
"Log in to Venice AI at venice.ai. The session cookie will be extracted.",
|
||||
{ cookieDomain: ".venice.ai" }
|
||||
),
|
||||
|
||||
// ── v0 Dev Web ────────────────────────────────────────────
|
||||
config(
|
||||
"v0-vercel-web",
|
||||
"v0 by Vercel",
|
||||
"https://v0.dev/login",
|
||||
"https://v0.dev",
|
||||
[{ type: "cookie", name: "__Secure-next-auth.session-token", domain: ".v0.dev" }],
|
||||
"Log in to v0.dev with your Vercel/Google/GitHub account. The session cookie will be extracted.",
|
||||
{ cookieDomain: ".v0.dev" }
|
||||
),
|
||||
|
||||
// ── Muse / Spark Web ──────────────────────────────────────
|
||||
config(
|
||||
"muse-spark-web",
|
||||
"Meta AI (Muse)",
|
||||
"https://www.meta.ai/",
|
||||
"https://www.meta.ai",
|
||||
[{ type: "cookie", name: "session", domain: ".meta.ai" }],
|
||||
"Log in to Meta AI at meta.ai with your Facebook/Instagram account. The session cookie will be extracted.",
|
||||
{ cookieDomain: ".meta.ai" }
|
||||
),
|
||||
|
||||
// ── Adapta Web ────────────────────────────────────────────
|
||||
config(
|
||||
"adapta-web",
|
||||
"Adapta AI",
|
||||
"https://agent.adapta.one/login",
|
||||
"https://agent.adapta.one",
|
||||
[{ type: "cookie", name: "__session", domain: ".adapta.one" }],
|
||||
"Log in to Adapta at agent.adapta.one. The session token will be extracted.",
|
||||
{ cookieDomain: ".adapta.one" }
|
||||
),
|
||||
|
||||
// ── VeoAI Free Web ────────────────────────────────────────
|
||||
config(
|
||||
"veoaifree-web",
|
||||
"VeoAI Free",
|
||||
"https://veoaifree.com/",
|
||||
"https://veoaifree.com",
|
||||
[{ type: "cookie", name: "wordpress_logged_in", domain: ".veoaifree.com" }],
|
||||
"Log in to VeoAI Free at veoaifree.com. The WordPress session cookie will be extracted.",
|
||||
{
|
||||
cookieDomain: ".veoaifree.com",
|
||||
pollingConfig: QUICK_POLLING,
|
||||
}
|
||||
),
|
||||
|
||||
// ── Missing Provider: ChatGLM (Zhipu) ──────────────────────
|
||||
config(
|
||||
"chatglm-web",
|
||||
"ChatGLM (Zhipu AI)",
|
||||
"https://chatglm.cn/",
|
||||
"https://chatglm.cn",
|
||||
[
|
||||
{ type: "cookie", name: "chatglm_session", domain: ".chatglm.cn" },
|
||||
{ type: "localStorage", key: "token" },
|
||||
],
|
||||
"Log in to ChatGLM at chatglm.cn with your phone number. The session token will be extracted.",
|
||||
{ cookieDomain: ".chatglm.cn" }
|
||||
),
|
||||
|
||||
// ── Missing Provider: Xiaomi MiMo ──────────────────────────
|
||||
config(
|
||||
"xiaomimimo-web",
|
||||
"Xiaomi MiMo AI Studio",
|
||||
"https://aistudio.xiaomimimo.com/login",
|
||||
"https://aistudio.xiaomimimo.com",
|
||||
[
|
||||
{ type: "cookie", name: "session", domain: ".xiaomimimo.com" },
|
||||
{ type: "localStorage", key: "access_token" },
|
||||
],
|
||||
"Log in to Xiaomi MiMo AI Studio at aistudio.xiaomimimo.com. The session token will be extracted.",
|
||||
{ cookieDomain: ".xiaomimimo.com" }
|
||||
),
|
||||
|
||||
// ── Missing Provider: Manus ────────────────────────────────
|
||||
config(
|
||||
"manus-web",
|
||||
"Manus AI",
|
||||
"https://manus.im/login",
|
||||
"https://manus.im",
|
||||
[
|
||||
{ type: "cookie", name: "manus_session", domain: ".manus.im" },
|
||||
{ type: "localStorage", key: "auth_token" },
|
||||
],
|
||||
"Log in to Manus at manus.im. The session cookie will be extracted.",
|
||||
{ cookieDomain: ".manus.im" }
|
||||
),
|
||||
];
|
||||
|
||||
// ─── Registry ───────────────────────────────────────────────────────────────
|
||||
|
||||
const CONFIG_MAP = new Map<string, TokenExtractionConfig>();
|
||||
|
||||
for (const cfg of RAW_CONFIGS) {
|
||||
CONFIG_MAP.set(cfg.providerId, cfg);
|
||||
}
|
||||
|
||||
/** Get extraction config for a specific provider */
|
||||
export function getExtractionConfig(providerId: string): TokenExtractionConfig | undefined {
|
||||
return CONFIG_MAP.get(providerId);
|
||||
}
|
||||
|
||||
/** List all registered extraction configs */
|
||||
export function listExtractionConfigs(): TokenExtractionConfig[] {
|
||||
return [...RAW_CONFIGS];
|
||||
}
|
||||
|
||||
/** The shared config map — used by LoginManager and InAppLoginService */
|
||||
export const TOKEN_EXTRACTION_CONFIGS = CONFIG_MAP;
|
||||
Reference in New Issue
Block a user