Prefer SSO OAuth PKCE for CPA minting and sync latest accounts.

Switch CPA export to SSO→Authorization Code with referrer=grok-build, keep device-code as optional fallback, and capture new register/auth artifacts.
This commit is contained in:
chaos committed 2026-07-12 15:54:24 +08:00
1 parent 8b3664a2d5
commit ee151343e0
455 files changed
+9051 -59

No files matched your search

+106 -35
View File
@@ -1,12 +1,12 @@
"""注册成功钩子:铸造 Grok Build 设备码 OIDC → 写出 CPA (CLIProxyAPI) 的
xai-<email>.json → 推送到远端 CLIProxyAPI 导入。
"""注册成功钩子:SSO → OAuth Authorization Code(PKCE, referrer=grok-build)
→ 写出 CPA (CLIProxyAPI) 的 xai-<email>.json → 推送到远端 CLIProxyAPI 导入。
- 本地写盘目录:config['cpa_auth_dir'](默认 ./cpa_auths)
- 远端推送:POST config['cpa_remote_base'] + /v0/management/auth-files?name=...
认证 X-Management-Key: config['cpa_remote_secret']
免费 Grok 4.5 用 base_url=cli-chat-proxy;CLIProxyAPI 请求 grok 时自带
x-grok-client-version 头,免费号不会 426。
2026-07 起:设备码铸造的 token 缺 referrer=grok-build,cli-chat-proxy 不可用。
默认优先走 SSO cookie 的授权码流程;仅在无 sso 且允许时才回退设备码。
"""
from __future__ import annotations
@@ -37,19 +37,97 @@ def _record_failure(out_dir: Path, email: str, reason: str) -> None:
pass
def _resolve_proxy(cfg: dict) -> str | None:
from oidc_mint import resolve_proxy, set_runtime_proxy
proxy = (cfg.get("mint_proxy") or cfg.get("proxy") or "").strip()
if not proxy:
proxy = (
os.environ.get("https_proxy")
or os.environ.get("HTTPS_PROXY")
or os.environ.get("http_proxy")
or ""
).strip()
resolved = resolve_proxy(proxy or None)
set_runtime_proxy(resolved or None)
return resolved or None
def _mint_tokens(
*,
email: str,
password: str,
sso: str,
page: Any | None,
cfg: dict,
log: Callable[[str], None],
proxy: str | None,
) -> dict[str, Any]:
"""优先 SSO 授权码;可选回退设备码。"""
from oidc_mint.oauth_code import OAuthCodeError, mint_from_sso, normalize_sso_cookie
sso_token = normalize_sso_cookie(sso or "")
prefer_sso = bool(cfg.get("cpa_prefer_sso_oauth", True))
allow_device = bool(cfg.get("cpa_allow_device_fallback", False))
timeout = float(cfg.get("mint_timeout_sec", 300) or 300)
if prefer_sso and sso_token:
log("[cpa] 使用 SSO→OAuth(PKCE, referrer=grok-build)")
try:
return mint_from_sso(
sso_token,
proxy=proxy,
log=lambda m: log(f"[Debug] {m}"),
require_referrer=bool(cfg.get("cpa_require_referrer", True)),
)
except OAuthCodeError as exc:
log(f"[!] SSO→OAuth 失败: {exc}")
if not allow_device:
raise
log("[cpa] 回退设备码铸造(可能缺 referrer)")
except Exception as exc: # noqa: BLE001
log(f"[!] SSO→OAuth 异常: {exc}")
if not allow_device:
raise
log("[cpa] 回退设备码铸造(可能缺 referrer)")
if not allow_device and not sso_token:
raise RuntimeError("无 sso cookie,且已禁用设备码回退;无法铸造带 referrer 的 token")
# 设备码回退(旧路径,通常无 referrer)
from oidc_mint import mint_with_browser
if page is None and not (email and password):
raise RuntimeError("设备码回退需要 page 或 email/password")
log("[cpa] 使用设备码铸造(兼容路径)")
tokens = mint_with_browser(
email=email,
password=password,
page=page,
proxy=proxy,
browser_timeout_sec=timeout,
force_standalone=(page is None),
cookies=None,
poll_log=lambda m: log(f"[Debug] {m}"),
)
return tokens
# ── 主入口 ──
def export_cpa_for_account(
email: str,
password: str,
password: str = "",
*,
page: Any | None = None,
sso: str = "",
config: dict | None = None,
log_callback: Callable[[str], None] | None = None,
) -> dict:
"""在注册浏览器里铸造 OIDC → 写本地 xai-<email>.json → 推送远端 CLIProxyAPI。
"""铸造 OIDC → 写本地 xai-<email>.json → 推送远端 CLIProxyAPI。
复用注册成功后仍开着、且已登录 grok 的浏览器铸造,不另开浏览器。
优先使用 sso cookie 走 Authorization Code + referrer=grok-build。
返回 {ok, email, path, pushed, push_status?, error?}。
"""
cfg = config or {}
@@ -59,41 +137,26 @@ def export_cpa_for_account(
log("[cpa] 已关闭导出,跳过")
return {"ok": False, "skipped": True, "reason": "disabled"}
email = (email or "").strip()
if not email or not password:
return {"ok": False, "error": "缺少 email/password", "email": email}
if page is None:
log("[!] 无可复用的注册浏览器,跳过铸造")
return {"ok": False, "error": "no register browser page", "email": email}
if not email:
return {"ok": False, "error": "缺少 email", "email": email}
from oidc_mint import mint_with_browser, resolve_proxy, set_runtime_proxy
import cpa
from oidc_mint.oauth_code import normalize_sso_cookie
out_dir = _resolve_out_dir(cfg)
# 代理优先级:mint_proxy > proxy > 环境
proxy = (cfg.get("mint_proxy") or cfg.get("proxy") or "").strip()
if not proxy:
proxy = (
os.environ.get("https_proxy") or os.environ.get("HTTPS_PROXY")
or os.environ.get("http_proxy") or ""
).strip()
resolved = resolve_proxy(proxy or None)
set_runtime_proxy(resolved or None)
timeout = float(cfg.get("mint_timeout_sec", 300) or 300)
proxy = _resolve_proxy(cfg)
base_url = cfg.get("cpa_base_url") or cpa.CLI_BASE_URL
sso_token = normalize_sso_cookie(sso or "")
# 复用注册浏览器铸造:它已登录 grok,开设备码页直接确认,不另开浏览器
try:
tokens = mint_with_browser(
tokens = _mint_tokens(
email=email,
password=password,
password=password or "",
sso=sso_token,
page=page,
proxy=resolved or None,
browser_timeout_sec=timeout,
force_standalone=False,
cookies=None,
poll_log=lambda m: log(f"[Debug] {m}"),
cfg=cfg,
log=log,
proxy=proxy,
)
except Exception as exc: # noqa: BLE001
log(f"[!] 铸造失败: {exc}")
@@ -110,6 +173,7 @@ def export_cpa_for_account(
id_token=tokens.get("id_token"),
expires_in=tokens.get("expires_in"),
base_url=base_url,
sso=tokens.get("sso") or sso_token or None,
)
path = cpa.write_cpa_xai_auth(out_dir, payload)
filename = Path(path).name
@@ -120,8 +184,15 @@ def export_cpa_for_account(
raise
return {"ok": False, "error": str(exc), "email": email}
log(f"[Debug] 已写本地: {path}")
result: dict[str, Any] = {"ok": True, "email": email, "path": str(path), "pushed": False}
ref = payload.get("referrer") or tokens.get("referrer") or ""
log(f"[Debug] 已写本地: {path} referrer={ref or '(empty)'}")
result: dict[str, Any] = {
"ok": True,
"email": email,
"path": str(path),
"pushed": False,
"referrer": ref,
}
# 推送远端 CLIProxyAPI
if cfg.get("cpa_push_enabled", False):