feat: rewrite cloakserve as CDP multiplexer with per-connection fingerprint seeds

Spawns a separate Chrome process per unique fingerprint seed, all behind
a single port (9222). Clients specify seeds and fingerprint params via
query string on the CDP URL:

  connect_over_cdp("http://host:9222?fingerprint=12345&timezone=Asia/Tokyo")

Supports all --fingerprint-* flags as query params, geoip=true for
auto timezone/locale from proxy IP, and proxy= for per-process proxies.

- Rewrite bin/cloakserve from 57-line wrapper to aiohttp CDP multiplexer
- Add ChromePool with per-seed process management and port allocation
- Bidirectional WebSocket proxy for CDP traffic
- URL rewriting for /json/version, /json/list, and WS paths
- Rename _build_args -> build_args, _maybe_resolve_geoip -> maybe_resolve_geoip
- Add aiohttp + websockets to serve optional deps
- Dockerfile installs .[serve] extras
- Add 20 unit tests for cloakserve (param parsing, CLI args, URL rewriting)
This commit is contained in:
CloakHQ
2026-04-05 22:30:18 +02:00
committed by Durafen
parent c58b691f1c
commit 03a0ad732f
12 changed files with 795 additions and 87 deletions
+15 -15
View File
@@ -1,24 +1,24 @@
"""Unit tests for _build_args timezone/locale injection and timezone alias."""
"""Unit tests for build_args timezone/locale injection and timezone alias."""
from cloakbrowser.browser import _build_args, _resolve_timezone
from cloakbrowser.browser import build_args, _resolve_timezone
def test_timezone_injected():
"""--fingerprint-timezone flag should appear when timezone is set."""
args = _build_args(stealth_args=True, extra_args=None, timezone="America/New_York")
args = build_args(stealth_args=True, extra_args=None, timezone="America/New_York")
assert "--fingerprint-timezone=America/New_York" in args
def test_locale_injected():
"""--lang and --fingerprint-locale flags should appear when locale is set."""
args = _build_args(stealth_args=True, extra_args=None, locale="en-US")
args = build_args(stealth_args=True, extra_args=None, locale="en-US")
assert "--lang=en-US" in args
assert "--fingerprint-locale=en-US" in args
def test_both_injected():
"""Both flags should appear when both are set."""
args = _build_args(stealth_args=True, extra_args=None, timezone="Europe/Berlin", locale="de-DE")
args = build_args(stealth_args=True, extra_args=None, timezone="Europe/Berlin", locale="de-DE")
assert "--fingerprint-timezone=Europe/Berlin" in args
assert "--lang=de-DE" in args
assert "--fingerprint-locale=de-DE" in args
@@ -26,7 +26,7 @@ def test_both_injected():
def test_timezone_independent_of_stealth_args():
"""--fingerprint-timezone should be injected even when stealth_args=False."""
args = _build_args(stealth_args=False, extra_args=None, timezone="America/New_York", locale="en-US")
args = build_args(stealth_args=False, extra_args=None, timezone="America/New_York", locale="en-US")
assert "--fingerprint-timezone=America/New_York" in args
assert "--lang=en-US" in args
assert "--fingerprint-locale=en-US" in args
@@ -36,7 +36,7 @@ def test_timezone_independent_of_stealth_args():
def test_no_flags_when_not_set():
"""No timezone/lang/fingerprint-locale flags when params are None."""
args = _build_args(stealth_args=True, extra_args=None)
args = build_args(stealth_args=True, extra_args=None)
assert not any(a.startswith("--fingerprint-timezone=") for a in args)
assert not any(a.startswith("--lang=") for a in args)
assert not any(a.startswith("--fingerprint-locale=") for a in args)
@@ -44,7 +44,7 @@ def test_no_flags_when_not_set():
def test_extra_args_preserved():
"""Extra args should still be included alongside timezone/locale."""
args = _build_args(stealth_args=True, extra_args=["--disable-gpu"], timezone="Asia/Tokyo", locale="ja-JP")
args = build_args(stealth_args=True, extra_args=["--disable-gpu"], timezone="Asia/Tokyo", locale="ja-JP")
assert "--disable-gpu" in args
assert "--fingerprint-timezone=Asia/Tokyo" in args
assert "--lang=ja-JP" in args
@@ -90,7 +90,7 @@ def test_resolve_both_none():
def test_user_fingerprint_overrides_default():
"""User --fingerprint should override the random default seed."""
args = _build_args(stealth_args=True, extra_args=["--fingerprint=99887"])
args = build_args(stealth_args=True, extra_args=["--fingerprint=99887"])
fingerprint_args = [a for a in args if a.startswith("--fingerprint=")]
assert len(fingerprint_args) == 1
assert fingerprint_args[0] == "--fingerprint=99887"
@@ -98,7 +98,7 @@ def test_user_fingerprint_overrides_default():
def test_user_platform_overrides_default():
"""User --fingerprint-platform should override the default."""
args = _build_args(stealth_args=True, extra_args=["--fingerprint-platform=linux"])
args = build_args(stealth_args=True, extra_args=["--fingerprint-platform=linux"])
platform_args = [a for a in args if a.startswith("--fingerprint-platform=")]
assert len(platform_args) == 1
assert platform_args[0] == "--fingerprint-platform=linux"
@@ -106,7 +106,7 @@ def test_user_platform_overrides_default():
def test_timezone_param_overrides_user_arg():
"""Dedicated timezone param should override user arg."""
args = _build_args(
args = build_args(
stealth_args=True,
extra_args=["--fingerprint-timezone=Europe/London"],
timezone="America/New_York",
@@ -118,7 +118,7 @@ def test_timezone_param_overrides_user_arg():
def test_locale_param_overrides_user_arg():
"""Dedicated locale param should override user --lang and --fingerprint-locale args."""
args = _build_args(
args = build_args(
stealth_args=True,
extra_args=["--lang=de-DE", "--fingerprint-locale=de-DE"],
locale="en-US",
@@ -133,7 +133,7 @@ def test_locale_param_overrides_user_arg():
def test_no_duplicate_flags():
"""No flag key should appear more than once in the output."""
args = _build_args(
args = build_args(
stealth_args=True,
extra_args=["--fingerprint=99887", "--fingerprint-timezone=UTC", "--lang=fr-FR"],
timezone="Europe/Berlin",
@@ -145,7 +145,7 @@ def test_no_duplicate_flags():
def test_non_value_flags_preserved():
"""Flags without = should be preserved without dedup issues."""
args = _build_args(stealth_args=True, extra_args=["--disable-gpu", "--no-zygote"])
args = build_args(stealth_args=True, extra_args=["--disable-gpu", "--no-zygote"])
assert "--disable-gpu" in args
assert "--no-zygote" in args
assert "--no-sandbox" in args
@@ -156,5 +156,5 @@ def test_override_logs_debug(caplog):
import logging
with caplog.at_level(logging.DEBUG, logger="cloakbrowser"):
_build_args(stealth_args=True, extra_args=["--fingerprint=99887"])
build_args(stealth_args=True, extra_args=["--fingerprint=99887"])
assert any("--fingerprint=" in r.message and "99887" in r.message for r in caplog.records)