Detect Cloudflare 403 on mint and retry alternate proxies.

- Clear CF block errors with egress label and config hint
- Log mint exit (direct/proxy); probe local proxy ports on 403
- Retry mint_proxy/proxy/pool candidates without browser mint
This commit is contained in:
chaos committed 2026-07-14 14:41:52 +08:00
1 parent cc0aa6a433
commit 7d6d52ac5d
2 files changed
+186 -17

No files matched your search

+48
View File
@@ -138,6 +138,39 @@ def _is_curl_tls_broken(exc: BaseException | str) -> bool:
return any(n in text for n in needles)
def is_cloudflare_block(
status: int | None = None,
body: str = "",
exc: BaseException | str | None = None,
) -> bool:
"""识别 auth.x.ai 被 Cloudflare 拦(常见直连 403 挑战页)。"""
text = f"{body or ''} {exc or ''}".lower()
if status == 403 and (
"<!doctype html" in text
or "cloudflare" in text
or "cf-ray" in text
or "attention required" in text
or "just a moment" in text
or "enable javascript" in text
or "oldie" in text
):
return True
if "authorize http 403" in text and (
"<!doctype" in text or "oldie" in text or "cloudflare" in text
):
return True
return "cloudflare" in text and ("403" in text or "blocked" in text)
def _cf_block_hint(proxy_label: str = "") -> str:
via = proxy_label or "(direct)"
return (
f"Cloudflare 拦截 auth.x.ai(出口={via})。"
"直连大陆/机房 IP 几乎必 403;请配置 mint_proxy / proxy,"
"或开启 proxy_pool_enabled 并保证代理能访问 auth.x.ai。"
)
def _make_std_session(proxy: str | None = None):
try:
import requests as std_requests
@@ -300,6 +333,10 @@ def open_authorize_page(session: Any, flow: AuthCodeFlow) -> str:
body = resp.text or ""
final = _final_url(resp)
if resp.status_code < 200 or resp.status_code >= 300:
if is_cloudflare_block(resp.status_code, body):
raise OAuthCodeError(
f"authorize HTTP {resp.status_code}: Cloudflare 拦截 — {_short(body, 80)}"
)
raise OAuthCodeError(
f"authorize HTTP {resp.status_code}: {_short(body)}"
)
@@ -478,11 +515,16 @@ def sso_to_token(
require_referrer: bool = True,
) -> TokenResult:
"""SSO cookie → 带 referrer=grok-build 的 OAuth token。"""
from .proxyutil import proxy_log_label, resolve_proxy
log = log or _noop_log
sso = normalize_sso_cookie(sso_cookie)
if not sso:
raise OAuthCodeError("sso cookie 为空")
resolved = resolve_proxy(proxy)
log(f"mint 出口={proxy_log_label(resolved) or '(direct)'}")
# 先 curl_cffi;若遇到 OpenSSL invalid library / curl(35),自动回退 std requests
session = _make_session(proxy, prefer="curl")
try:
@@ -495,6 +537,8 @@ def sso_to_token(
backend.startswith("curl_cffi") and "curl: (35)" in str(exc).lower()
)
if not can_fallback:
if is_cloudflare_block(exc=exc):
raise OAuthCodeError(_cf_block_hint(proxy_log_label(resolved))) from exc
raise
log(f"curl TLS 异常,回退标准 requests: {_short(str(exc), 160)}")
try:
@@ -506,6 +550,10 @@ def sso_to_token(
return _run_sso_flow(
sso, session=session, log=log, require_referrer=require_referrer
)
except Exception as exc2: # noqa: BLE001
if is_cloudflare_block(exc=exc2):
raise OAuthCodeError(_cf_block_hint(proxy_log_label(resolved))) from exc2
raise
finally:
try:
session.close()