Prefer Chromium for turnstilePatch on headless servers

Google Chrome blocks --load-extension, so CF tokens stay empty under
Xvfb. Auto-select Chromium when the extension is present, install/
detect chromium in start.sh, and document browser_prefer overrides.
This commit is contained in:
chaos committed 2026-07-12 00:37:27 +08:00
1 parent cd4a2351ae
commit cf6c0d2b4d
7 files changed
+141 -45

No files matched your search

+61 -12
View File
@@ -58,6 +58,7 @@ DEFAULT_CONFIG = {
"cloudmail_password": "",
"cpa_gui_close_mint_browser": True,
"browser_headless": "auto",
"browser_prefer": "auto",
"browser_path": "",
"hotmail_accounts_file": "mail_credentials.txt",
"hotmail_alias_mode": "random",
@@ -772,16 +773,22 @@ def apply_headless_to_options(options, headless: bool = True) -> None:
except Exception:
pass
# Prefer Google Chrome for registration reliability (email delivery path).
# Chromium is fallback; turnstilePatch extension only loads on Chromium.
# On Chrome we inject the same patch via CDP add_init_js (see apply_stealth_patches).
BROWSER_CANDIDATES = (
"/usr/bin/google-chrome-stable",
"/usr/bin/google-chrome",
"/snap/bin/chromium",
# Browser discovery order is decided by resolve_browser_path():
# - default (auto): prefer Chromium so turnstilePatch can load (--load-extension)
# - Google Chrome blocks unpacked extensions; CDP stealth alone often fails CF on servers
# - config browser_prefer: auto | chromium | chrome
# - config browser_path: absolute override
CHROMIUM_CANDIDATES = (
"/usr/bin/chromium",
"/usr/bin/chromium-browser",
"/snap/bin/chromium",
)
CHROME_CANDIDATES = (
"/usr/bin/google-chrome-stable",
"/usr/bin/google-chrome",
)
# Legacy flat list (tests / external callers)
BROWSER_CANDIDATES = CHROMIUM_CANDIDATES + CHROME_CANDIDATES
# Minimal CDP stealth only. Aggressive patches (chrome.runtime delete, permissions
# monkeypatch, fake plugins/languages, postMessage spam) caused xAI UI to show
@@ -816,15 +823,54 @@ def _is_google_chrome_path(path: str | None) -> bool:
return "chrome" in base and "chromium" not in path
def _first_existing_browser(candidates) -> str | None:
for cand in candidates:
if cand and (os.path.isfile(cand) or os.path.islink(cand)):
return cand
return None
def resolve_browser_path():
"""Pick Chromium/Chrome for registration.
Priority:
1. config browser_path (absolute)
2. env BROWSER_PATH / CHROME_PATH
3. browser_prefer=chromium|chrome|auto
auto → Chromium first when turnstilePatch exists (needed for CF)
4. any remaining candidate
"""
# Optional override from config.json "browser_path"
override = str((config.get("browser_path") if isinstance(config, dict) else "") or "").strip()
if override and (os.path.isfile(override) or os.path.islink(override)):
return override
for cand in BROWSER_CANDIDATES:
if os.path.isfile(cand) or os.path.islink(cand):
return cand
return None
for env_key in ("BROWSER_PATH", "CHROME_PATH", "CHROMIUM_PATH"):
env_path = (os.environ.get(env_key) or "").strip()
if env_path and (os.path.isfile(env_path) or os.path.islink(env_path)):
return env_path
prefer = str((config.get("browser_prefer") if isinstance(config, dict) else "") or "auto").strip().lower()
if prefer in ("", "default", "detect"):
prefer = "auto"
# env override
env_pref = (os.environ.get("BROWSER_PREFER") or "").strip().lower()
if env_pref:
prefer = env_pref
has_ext = os.path.isdir(EXTENSION_PATH)
if prefer in ("chrome", "google-chrome", "google"):
order = list(CHROME_CANDIDATES) + list(CHROMIUM_CANDIDATES)
elif prefer in ("chromium", "chromeium"): # typo tolerant
order = list(CHROMIUM_CANDIDATES) + list(CHROME_CANDIDATES)
else:
# auto: extension needs Chromium; without extension Chrome is fine
if has_ext:
order = list(CHROMIUM_CANDIDATES) + list(CHROME_CANDIDATES)
else:
order = list(CHROME_CANDIDATES) + list(CHROMIUM_CANDIDATES)
path = _first_existing_browser(order)
return path
def apply_stealth_patches(page=None, log_callback=None) -> bool:
@@ -902,11 +948,14 @@ def create_browser_options(headless=None):
# Google Chrome blocks CLI unpacked extension loading; Chromium still allows it.
if _is_google_chrome_path(browser_path):
print(
" [ext] Chrome: minimal CDP stealth only (extension blocked)",
" [ext] Chrome: minimal CDP stealth only (extension blocked)\n"
" 建议安装 Chromium 或 config browser_prefer=chromium / browser_path=/usr/bin/chromium\n"
" 否则 Turnstile token 常为 0(无头/Xvfb 服务器上尤其明显)",
flush=True,
)
else:
options.add_extension(EXTENSION_PATH)
print(f" [ext] turnstilePatch loaded: {EXTENSION_PATH}", flush=True)
# Apply config.json "proxy" to Chromium. Without this, only HTTP helpers
# used get_proxies(); the browser itself fell through to system/env proxy.
proxy = (config.get("proxy") or "").strip()