Files
OmniRoute/src/shared/constants/providers/web-cookie.ts
Jan Leon a99c795a67 Add native ChatGPT Web provider for Codex clients (#8949)
* Bypass proxy compaction for native Codex context

* Add native ChatGPT Web provider pipeline

* Add managed browser and tunnel deployment

* Add ChatGPT Web setup and doctor UI

* Document and test ChatGPT Web integration

* fix(security): register chatgpt-web-codex-doctor in LOCAL_ONLY_API_PATTERNS

The diagnostic route under /api/providers/{id}/chatgpt-web-codex-doctor
was not registered in the spawn-capable route guard. Adding it for
parity with the existing /login pattern.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(providers): route chatgpt-web-codex admin routes through a service boundary

The provider CRUD/doctor routes imported chatgpt-web-codex helpers
(finalizeValidatedChatGptWebCodexSecrets, encode/decodeChatGptWebCodexSecrets,
getChatGptWebCodexDoctorStatus) directly from open-sse/executors/**, which
no-restricted-imports (EXECUTOR_IMPORT_RESTRICTION) forbids for src/app/**
files — executor implementations must stay behind an open-sse handler or
service boundary.

Add open-sse/services/chatgptWebCodexAdmin.ts as a thin re-export boundary
(mirroring the existing tokenRefresh.ts re-export pattern) and import from
there instead. No behavior change.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
2026-08-11 09:53:39 -03:00

539 lines
21 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Provider catalog data — extracted from providers.ts (god-file decomposition).
* Pure data literal; re-exported by the providers.ts barrel. No behavior change.
*/
export const WEB_COOKIE_PROVIDERS = {
"chatgpt-web-codex": {
id: "chatgpt-web-codex",
alias: "cgpt-codex",
name: "ChatGPT Web (Codex)",
icon: "terminal",
color: "#10A37F",
textIcon: "CC",
website: "https://chatgpt.com",
authHint:
"Paste the full ChatGPT Cookie header. OmniRoute verifies it in an isolated headless browser profile.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
toolCalling: "native",
},
"chatgpt-web": {
id: "chatgpt-web",
alias: "cgpt-web",
name: "ChatGPT Web (Plus/Pro)",
icon: "auto_awesome",
color: "#10A37F",
textIcon: "CG",
website: "https://chatgpt.com",
authHint: "Paste your __Secure-next-auth.session-token cookie value from chatgpt.com",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
toolCalling: "emulated",
},
"grok-web": {
id: "grok-web",
alias: "gw",
name: "Grok Web (Subscription)",
icon: "auto_awesome",
color: "#1DA1F2",
textIcon: "GW",
website: "https://grok.com",
authHint:
"Paste the full grok.com cookie line from DevTools → Application → Cookies. Include both `sso` and `sso-rw` (e.g. `sso=...; sso-rw=...`) — Grok's anti-bot rejects `sso` on its own.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
"gemini-web": {
id: "gemini-web",
alias: "gweb",
name: "Gemini Web (Free)",
icon: "auto_awesome",
color: "#4285F4",
textIcon: "GWeb",
website: "https://gemini.google.com",
authHint:
"Paste your __Secure-1PSID cookie value from gemini.google.com. Optionally add __Secure-1PSIDTS separated by semicolon.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
// #7286 Level 2: tools[] is prompt-emulated via webTools.ts (parseToolCallsFromText).
toolCalling: "emulated",
},
"perplexity-web": {
id: "perplexity-web",
alias: "pplx-web",
name: "Perplexity Web (Pro/Max)",
icon: "search",
color: "#20808D",
textIcon: "PW",
website: "https://www.perplexity.ai",
authHint: "Paste your __Secure-next-auth.session-token cookie value from perplexity.ai",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
toolCalling: "emulated",
},
"blackbox-web": {
id: "blackbox-web",
alias: "bb-web",
name: "Blackbox Web (Subscription)",
icon: "view_in_ar",
color: "#1A1A2E",
textIcon: "BW",
website: "https://app.blackbox.ai",
authHint:
"Paste your __Secure-authjs.session-token value or full cookie header from app.blackbox.ai",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
toolCalling: "emulated",
},
"muse-spark-web": {
id: "muse-spark-web",
alias: "ms-web",
name: "Muse Spark Web (Meta AI)",
icon: "auto_awesome",
color: "#0866FF",
textIcon: "MS",
website: "https://www.meta.ai",
hasFree: true,
freeNote: "Free with login — Meta AI platform with Llama models.",
authHint:
"Paste your ecto_1_sess cookie AND the ecto1:... WS auth token from meta.ai. " +
"Capture the ecto1: token in DevTools → Network → WS → the clippy request's Authorization query param. " +
"Example: ecto_1_sess=4240a308...NVDg0; ecto1:ABCD...",
toolCalling: "emulated",
},
"claude-web": {
id: "claude-web",
alias: "cw",
name: "Claude Web",
icon: "auto_awesome",
color: "#D97757",
textIcon: "CW",
website: "https://claude.ai",
authHint: "Paste your session cookie from claude.ai",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
// #7286 Level 3 (deferred): still silently drops tools[] — getDefaultTools()
// is a fixed Claude.ai backend contract; needs an emulate-vs-native decision.
toolCalling: "none",
},
"deepseek-web": {
id: "deepseek-web",
alias: "ds-web",
name: "DeepSeek Web",
icon: "auto_awesome",
color: "#4D6BFE",
textIcon: "DS",
website: "https://chat.deepseek.com",
authHint:
"Paste your userToken from chat.deepseek.com — DevTools → Application → Local Storage → userToken",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
toolCalling: "emulated",
},
"copilot-web": {
id: "copilot-web",
alias: "copilot",
name: "Microsoft Copilot Web",
icon: "auto_awesome",
color: "#0078D4",
textIcon: "CP",
website: "https://copilot.microsoft.com",
authHint:
"Paste the access_token from an authenticated copilot.microsoft.com request (DevTools → Network → Authorization), or export a HAR while logged in",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
"copilot-m365-web": {
id: "copilot-m365-web",
alias: "m365copilot",
name: "Microsoft 365 Copilot (BizChat)",
icon: "business_center",
color: "#0078D4",
textIcon: "M365",
website: "https://m365.cloud.microsoft/chat",
authHint:
"Sign in at m365.cloud.microsoft/chat, then open DevTools → Network → filter 'WS' → click the Chathub WebSocket connection. Copy both the access_token query parameter AND the account-specific Chathub path segment from its request URL (wss://…/Chathub/<path>?…&access_token=…). It is NOT an Authorization: Bearer header on an XHR/Fetch request. The token is short-lived; this is an unofficial integration.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
"microsoft-designer-web": {
id: "microsoft-designer-web",
alias: "msdesigner",
name: "Microsoft Designer (Image Generation)",
icon: "auto_awesome",
color: "#0078D4",
textIcon: "MSD",
website: "https://designer.microsoft.com",
authHint:
"Sign in at designer.microsoft.com, then open DevTools → Network, generate an image, and find the request to DallE.ashx?action=GetDallEImagesCogSci. Copy the value of its Authorization: Bearer header (the access_token — no 'Bearer ' prefix). The token is short-lived; this is an unofficial, reverse-engineered integration.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
"t3-web": {
id: "t3-web",
alias: "t3chat",
name: "t3.chat (Pro/Free)",
icon: "auto_awesome",
color: "#7C3AED",
textIcon: "T3",
website: "https://t3.chat",
hasFree: true,
freeNote: "Free tier gives limited model access. Pro ($8/month) unlocks 50+ models.",
authHint:
"Open t3.chat in your browser, log in, then open DevTools → Application → Local Storage → https://t3.chat. " +
"Copy the value of 'convex-session-id'. Also open DevTools → Network, copy the Cookie header from any request. " +
"Paste both values here. See provider setup docs for a step-by-step guide.",
toolCalling: "emulated",
},
"inner-ai": {
id: "inner-ai",
alias: "in-ai",
name: "Inner.ai (Subscription)",
icon: "auto_awesome",
color: "#1A56DB",
textIcon: "IA",
website: "https://app.innerai.com",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
authHint:
"Paste your token cookie and email separated by a space: open DevTools → Application → Cookies → .innerai.com, copy the token value, then append a space and your Inner.ai login email. Example: eyJhbG... user@example.com",
toolCalling: "emulated",
},
"adapta-web": {
id: "adapta-web",
alias: "adp-web",
name: "Adapta.org (Adapta One Web)",
icon: "auto_awesome",
color: "#6E3AD3",
textIcon: "AW",
website: "https://agent.adapta.one",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
authHint:
"Paste your __client cookie value from .clerk.agent.adapta.one (DevTools → Application → Cookies)",
toolCalling: "emulated",
},
lmarena: {
// Wire id stays `lmarena` for DB/combo/model-prefix back-compat.
// Product rebranded LMArena → Arena (arena.ai) in Jan 2026.
id: "lmarena",
alias: "lma",
name: "Arena (Free)",
icon: "auto_awesome",
color: "#FF6B6B",
textIcon: "AR",
website: "https://arena.ai",
hasFree: true,
freeNote:
"Free model comparison platform (formerly LMArena) at arena.ai — Direct-chat catalog of chat models (GPT, Claude, Gemini, Llama, …). No subscription required.",
authHint:
"Paste the full Cookie header from arena.ai (DevTools → Network → request → Cookie). Include arena-auth-prod-v1.0/.1… and cf_clearance/__cf_bm when present. OmniRoute uses Chrome TLS impersonation; if Arena still 403s, set providerSpecificData.recaptchaV3Token from a live browser session.",
riskNoticeVariant: "webCookie",
},
"yuanbao-web": {
id: "yuanbao-web",
alias: "ybw",
name: "Tencent Yuanbao (Free)",
icon: "auto_awesome",
color: "#0052D9",
textIcon: "YB",
website: "https://yuanbao.tencent.com",
hasFree: true,
freeNote:
"Free consumer web session — DeepSeek V3/R1 and Hunyuan / Hunyuan-T1, optional web search. No subscription required. Rate limits apply.",
authHint:
"Log in to yuanbao.tencent.com, then paste the full Cookie header (DevTools → Network → any /api request → Request Headers → Cookie). It must contain hy_user and hy_token.",
riskNoticeVariant: "webCookie",
},
huggingchat: {
id: "huggingchat",
// "hc" belongs to the hackclub provider; huggingchat uses its own id as alias.
alias: "huggingchat",
name: "HuggingChat (Free)",
icon: "auto_awesome",
color: "#FFD21E",
textIcon: "HC",
website: "https://huggingface.co/chat",
hasFree: true,
freeNote: "Free LLM chat — no subscription required. Rate limits apply.",
authHint:
"Paste the full Cookie header from huggingface.co/chat (DevTools → Network → /chat/conversation → Request Headers → Cookie). It should include hf-chat and may also include token / aws-waf-token.",
riskNoticeVariant: "webCookie",
},
"poe-web": {
id: "poe-web",
alias: "poe",
name: "Poe Web (Subscription)",
icon: "auto_awesome",
color: "#6C3AED",
textIcon: "PW",
website: "https://poe.com",
authHint: "Paste your p-b cookie value from poe.com (DevTools → Application → Cookies → p-b)",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
"venice-web": {
id: "venice-web",
alias: "ven",
name: "Venice Web (Privacy)",
icon: "auto_awesome",
color: "#22C55E",
textIcon: "VW",
website: "https://venice.ai",
authHint: "Paste your session cookie from venice.ai (DevTools → Application → Cookies)",
riskNoticeVariant: "webCookie",
},
"v0-vercel-web": {
id: "v0-vercel-web",
// #6343: was "v0", colliding with the unrelated "v0-vercel" API-key provider's
// alias. Aliases resolve 1:1 to a provider id, so the dashboard's model-string
// routing always picked v0-vercel, silently hiding this provider's own
// credentials. Follows the established secondary-web-variant convention (see
// kimi-web / qwen-web / huggingchat in tests/unit/provider-alias-uniqueness.test.ts):
// the web/secondary variant uses its own id as alias instead of a short prefix.
alias: "v0-vercel-web",
name: "v0 Vercel Web (Code Gen)",
icon: "auto_awesome",
color: "#000000",
textIcon: "V0",
website: "https://v0.dev",
authHint: "Paste your session cookie from v0.dev (DevTools → Application → Cookies)",
riskNoticeVariant: "webCookie",
},
"kimi-web": {
id: "kimi-web",
// Legacy "kimi" API provider keeps the short alias; web variant uses its own id.
alias: "kimi-web",
name: "Kimi Web",
icon: "auto_awesome",
color: "#2563EB",
textIcon: "KW",
// Kimi official-partnership aff link (2026-07) — the "Kimi Coding Plan"
// tracking link (same origin as the plain www.kimi.com login flow below,
// so the "Open {host}" credential guide in WebSessionCredentialGuide.tsx /
// AddApiKeyModal.tsx is unaffected: origin, not path, decides localStorage
// access). Was `https://www.kimi.com` (no aff attribution).
website: "https://www.kimi.com/code?aff=omniroute",
authHint:
"Paste access_token from www.kimi.com DevTools → Application → Local Storage. A legacy kimi-auth cookie is also accepted.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
"doubao-web": {
id: "doubao-web",
alias: "db",
name: "Dola Web (ByteDance)",
icon: "auto_awesome",
color: "#3B82F6",
textIcon: "DA",
website: "https://www.dola.com",
authHint:
"Paste the full Cookie header from www.dola.com. It should include sessionid, ttwid, and s_v_web_id. If s_v_web_id is unavailable, fp=verify_... from a chat/completion request URL can be used as a fallback.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
"hailuo-web": {
id: "hailuo-web",
// Distinct alias: avoid colliding with the existing API-key "minimax"/
// "minimax-cn" providers (src/shared/constants/providers/apikey/regional.ts).
alias: "hailuo-web",
name: "Hailuo Web (MiniMax)",
icon: "auto_awesome",
color: "#5B21B6",
textIcon: "HL",
website: "https://hailuo.ai",
authHint:
"Open hailuo.ai, log in, then open DevTools → Application → Local Storage → copy the " +
'"_token" value. device_id/uuid fingerprint fields are derived automatically; if ' +
"requests fail, re-capture _token (sessions can expire).",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
"qwen-web": {
id: "qwen-web",
// The web variant uses its own id; the retired `qw` alias is not reassigned.
alias: "qwen-web",
name: "Qwen Web (Free)",
icon: "auto_awesome",
color: "#10B981",
textIcon: "QW",
website: "https://chat.qwen.ai",
hasFree: true,
freeNote: "Free — Qwen models via chat.qwen.ai with login token. No subscription required.",
authHint:
"Open chat.qwen.ai, log in, then open DevTools → Application → Local Storage → " +
'copy the "token" value (or use tongyi_sso_ticket cookie as Bearer token).',
toolCalling: "emulated",
},
"gemini-business": {
id: "gemini-business",
alias: "gembiz",
name: "Gemini Business (Enterprise)",
icon: "business_center",
color: "#4285F4",
textIcon: "GB",
website: "https://business.gemini.google",
hasFree: true,
freeNote:
"Free for Google Workspace enterprise accounts — enterprise Gemini models (Pro, Flash, image, video) via direct StreamGenerate HTTP API. No subscription required, just enterprise SSO.",
authHint:
"From your enterprise account: open business.gemini.google/home/cid/{your-cid}, then copy __Secure-1PSID and __Secure-1PSIDTS cookies from DevTools → Application → Cookies. Paste as a cookie header below.",
},
"zenmux-free": {
id: "zenmux-free",
alias: "zmf",
name: "ZenMux Free (Web)",
icon: "bolt",
color: "#667eea",
textIcon: "ZF",
website: "https://zenmux.ai",
hasFree: true,
freeNote:
"Free tier (5 Flows/5h, 38.64 Flows/week) — DeepSeek V3.2, GLM 4.7 Flash Free and more. No subscription required.",
authHint:
"Login at zenmux.ai, then export all cookies using EditThisCookie or Cookie-Editor and paste the full Cookie header string here. Refresh every ~30 days.",
},
"tinycms-web": {
id: "tinycms-web",
alias: "tcw",
name: "TinyCMS Web (Free/Sub)",
icon: "layers",
color: "#ED8936",
textIcon: "TC",
website: "https://site.tinycms.xyz",
hasFree: true,
freeNote:
"Free tier has access to GPT 5.4, Gemini 3.5, and Grok 4.20 models. No login required. Subscription grants 300 requests/day for advanced models.",
authHint:
"Go to site.tinycms.xyz, open DevTools → Application → Local Storage, copy the value of 'app-config-uuid' (starts with 'R'), and paste it here.",
},
"zai-web": {
id: "zai-web",
alias: "zw",
name: "Z.ai Web (Free)",
icon: "auto_awesome",
color: "#2563EB",
textIcon: "ZW",
website: "https://chat.z.ai",
hasFree: true,
freeNote:
"Free consumer web session — GLM chat models via chat.z.ai. Distinct from the API-key zai/glm providers. No subscription required.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
authHint: "Paste the full Cookie header from chat.z.ai (must include the token=<JWT> cookie)",
},
promptql: {
id: "promptql",
alias: "pql",
name: "PromptQL (Unofficial/Experimental)",
icon: "auto_awesome",
color: "#5B21B6",
textIcon: "PQL",
website: "https://prompt.ql.app",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
authHint:
"Paste the Bearer JWT from prompt.ql.app DevTools → Network → graphql → Authorization (token only). Optional projectId + session Cookie for refresh.",
},
"notion-web": {
id: "notion-web",
alias: "nw",
name: "Notion AI Web (Unofficial/Experimental)",
icon: "auto_awesome",
color: "#000000",
textIcon: "NW",
website: "https://www.notion.so",
// #6758: Notion has no public inference API (see closed request #3272) — this
// reverse-engineers the same undocumented internal endpoint two independent
// open-source projects already use. Undocumented endpoints can change without
// notice; label clearly so operators understand the risk before pasting a
// session cookie of an account they already pay for.
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
authHint:
"Paste only the token_v2 cookie VALUE from app.notion.com (DevTools → Application → Cookies → token_v2). " +
"Do not paste token_v2= or the full Cookie header. Workspace is auto-detected; space_id / notion_user_id are optional.",
},
"adobe-firefly": {
id: "adobe-firefly",
alias: "firefly",
name: "Adobe Firefly (Image/Video)",
icon: "auto_awesome",
color: "#EB1000",
textIcon: "FF",
website: "https://firefly.adobe.com",
authHint:
"RECOMMENDED: firefly.adobe.com signed-in → F12 → Network → click firefly-3p.ff.adobe.io (generate-async or models/discovery) → Request Headers → Authorization → copy the token AFTER 'Bearer ' (starts with eyJ…). Cookie-only from firefly.adobe.com mints a GUEST token → 401/403; only multi-domain IMS cookies (adobelogin.com) or that Bearer JWT work. Unofficial/experimental media + Limits.",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
},
hyperagent: {
id: "hyperagent",
alias: "ha",
name: "HyperAgent (Unofficial/Experimental)",
icon: "auto_awesome",
color: "#6C5CE7",
textIcon: "HA",
website: "https://hyperagent.com",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
authHint:
"Paste the full Cookie header from hyperagent.com (DevTools → Network → any request → Request Headers → Cookie). Session cookies power chat + billing usage.",
},
"conol-web": {
id: "conol-web",
alias: "cnl",
name: "Conol (Unofficial/Experimental)",
icon: "auto_awesome",
color: "#F6C945",
textIcon: "CO",
website: "https://conol.ai",
subscriptionRisk: true,
riskNoticeVariant: "webCookie",
authHint:
"Use browser sign-in, or paste the full Cookie header from conol.ai. The __Secure-better-auth.session_token cookie is required.",
},
};
/** Resolved public site for a web-session provider (href + display host). */
export interface WebProviderHostLink {
/** Full URL to open in a new tab (the provider's own `website`, or the origin
* derived from a registry baseUrl fallback). */
url: string;
/** Display host, e.g. `chatgpt.com` — used for the "Open host →" label. */
host: string;
}
/**
* Resolve the public website + display host for a web-session provider so the
* "Add session cookie" modal can render a prominent "Open host →" link.
*
* Primary source: `WEB_COOKIE_PROVIDERS[providerId].website`. When an entry has
* no `website` (or the provider is not in the catalog but the caller knows it is
* a web-session provider), the caller may pass its registry `baseUrl` as a
* fallback — only the origin is kept from it.
*
* Pure and React-free (unit-testable). Web-ness gating is the caller's
* responsibility: with no `fallbackBaseUrl`, a provider absent from
* `WEB_COOKIE_PROVIDERS` resolves to `null`.
*/
export function resolveWebProviderHost(
providerId: string | null | undefined,
fallbackBaseUrl?: string | null
): WebProviderHostLink | null {
if (!providerId) return null;
const entry = (WEB_COOKIE_PROVIDERS as Record<string, { website?: string }>)[providerId];
const website = entry?.website?.trim();
const fallback = fallbackBaseUrl?.trim();
const source = website || fallback;
if (!source) return null;
try {
const parsed = new URL(source);
// Keep the website URL verbatim (it may point at a specific path like
// `/chat`); for a registry baseUrl fallback, keep only the origin.
return { url: website ? source : parsed.origin, host: parsed.host };
} catch {
return null;
}
}