Files
proxy-god/proxy_chain_manager/browser_profile.py
Dr Jones 01c19349ee feat: exhaustive feature expansion — cookie modes, DNS/WebRTC testers, map, Firefox fix
Cookie system:
- Expand from 5 to 12 fully-specified CookiePolicy modes in browser_identity.py
- Add CookiePolicy dataclass: behavior, lifetime, TCP partitioning, clearOnShutdown.*
- browser_profile.py emits full cookie pref set from policy object
- UI dropdown widened to 680px with live description label per mode

Firefox launch fix:
- Detect Firefox via Windows registry, AppData, and shutil.which
- Use DETACHED_PROCESS|CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP flags
- Wait up to 3s for firefox.exe in tasklist instead of polling parent pid
- taskkill on stop() to terminate all firefox.exe processes

DNS leak tester:
- dns_leak.py: FullDnsLeakReport dataclass, run_dns_leak_test comparing
  proxy DoH resolution vs direct system DNS

WebRTC tester:
- webrtc_check.py: STUN UDP probe, registry policy check, user.js pref check

Ban tester:
- Added SITES_SHOPPING, SITES_CRYPTO, SITES_DNS categories
- Parallel execution via ThreadPoolExecutor
- Expanded banned-text hint keywords

Fingerprint audit:
- OS identity checks: hostname, MAC, GUID, OS version, timezone, screen res
- Browser consistency analysis of user.js

Neon world map:
- world_map.png bundled; chain_map.py renders hop arcs over it with glow effect

Signup prep:
- Auto-save account on Open & Autofill; Copy Email / Copy Pass buttons
- Auto-fill custom URL when preset site selected
- PyInstaller-safe path resolution for signup_extension

Spec:
- Bundle signup_extension dir and world_map.png as PyInstaller data files

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 16:47:22 -07:00

272 lines
12 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
from pathlib import Path
from .browser_identity import (
CookiePolicy,
Persona,
cookie_behavior_value,
cookie_session_only,
get_cookie_policy,
get_persona,
is_blend_persona,
)
@dataclass
class FirefoxHardening:
# Proxy & network always-on
force_proxy: bool = True
disable_webrtc: bool = True # always strongly recommended; leaks real IP
# Hardened block mode — overrides persona spoofing
resist_fingerprinting: bool = True
disable_telemetry: bool = True
first_party_isolation: bool = True
strict_tracking_protection: bool = True
clear_on_shutdown: bool = True
timezone_utc: bool = True
# Persona / cookie selectors (added in "spoof when possible" mode)
persona_key: str = "custom" # see browser_identity.PERSONAS
cookie_mode: str = "block_third_party" # see browser_identity.COOKIE_MODES
# Optional Firefox-managed user-agent override even outside of a persona
user_agent_override: str = ""
# Filled in by ``apply_persona`` when persona_key starts with "blend_".
persona: Persona | None = field(default=None, repr=False, compare=False)
def apply_persona(hard: FirefoxHardening) -> FirefoxHardening:
"""Mutate hardening flags consistent with the persona choice.
Blend-in personas relax the "stand out" toggles (RFP, FPI, strict TP) but
keep the IP-leakers off (WebRTC, geolocation, etc.). Cookie mode is
honored. The result is a profile that looks like a normal browser.
"""
if hard.persona_key == "hardened":
hard.resist_fingerprinting = True
hard.first_party_isolation = True
hard.strict_tracking_protection = True
hard.timezone_utc = True
hard.persona = None
return hard
if is_blend_persona(hard.persona_key):
hard.resist_fingerprinting = False # RFP itself is a fingerprint
hard.first_party_isolation = False # breaks logins on many sites
hard.strict_tracking_protection = False # Firefox default ETP is enough
hard.timezone_utc = False
hard.persona = get_persona(hard.persona_key)
if hard.persona and not hard.user_agent_override:
hard.user_agent_override = hard.persona.user_agent
return hard
# custom — honor the individual flags as-is.
hard.persona = None
return hard
def _bool(v: bool) -> str:
return "true" if v else "false"
def build_user_js(
proxy_host: str,
proxy_port: int,
hard: FirefoxHardening,
) -> str:
hard = apply_persona(hard)
lines: list[str] = [
"// Managed by Proxy God. Changes are overwritten on next launch.",
# Always-on baseline (no UX cost)
'user_pref("app.normandy.enabled", false);',
'user_pref("app.shield.optoutstudies.enabled", false);',
'user_pref("browser.newtabpage.activity-stream.feeds.telemetry", false);',
'user_pref("browser.newtabpage.activity-stream.telemetry", false);',
'user_pref("browser.ping-centre.telemetry", false);',
'user_pref("toolkit.telemetry.archive.enabled", false);',
'user_pref("toolkit.telemetry.bhrPing.enabled", false);',
'user_pref("toolkit.telemetry.enabled", false);',
'user_pref("toolkit.telemetry.firstShutdownPing.enabled", false);',
'user_pref("toolkit.telemetry.hybridContent.enabled", false);',
'user_pref("toolkit.telemetry.newProfilePing.enabled", false);',
'user_pref("toolkit.telemetry.shutdownPingSender.enabled", false);',
'user_pref("toolkit.telemetry.unified", false);',
'user_pref("datareporting.healthreport.uploadEnabled", false);',
'user_pref("datareporting.policy.dataSubmissionEnabled", false);',
'user_pref("network.trr.mode", 5);',
'user_pref("network.captive-portal-service.enabled", false);',
'user_pref("geo.enabled", false);',
'user_pref("media.navigator.enabled", false);',
'user_pref("dom.battery.enabled", false);',
'user_pref("dom.gamepad.enabled", false);',
'user_pref("dom.netinfo.enabled", false);',
# WebGL allowed by default (blocking it makes you stand out massively)
'user_pref("webgl.enable-debug-renderer-info", false);',
]
if hard.force_proxy:
lines.extend(
[
'user_pref("network.proxy.type", 1);',
'user_pref("network.proxy.share_proxy_settings", true);',
f'user_pref("network.proxy.http", "{proxy_host}");',
f'user_pref("network.proxy.http_port", {int(proxy_port)});',
f'user_pref("network.proxy.ssl", "{proxy_host}");',
f'user_pref("network.proxy.ssl_port", {int(proxy_port)});',
'user_pref("network.proxy.ftp", "");',
'user_pref("network.proxy.ftp_port", 0);',
'user_pref("network.proxy.socks", "");',
'user_pref("network.proxy.socks_port", 0);',
'user_pref("network.proxy.socks_version", 5);',
'user_pref("network.proxy.socks_remote_dns", false);',
'user_pref("network.proxy.no_proxies_on", "");',
]
)
if hard.disable_webrtc:
# Off regardless of persona — WebRTC leaks real IP through STUN.
lines.extend(
[
'user_pref("media.peerconnection.enabled", false);',
'user_pref("media.peerconnection.ice.default_address_only", true);',
'user_pref("media.peerconnection.ice.no_host", true);',
]
)
if hard.resist_fingerprinting:
lines.extend(
[
'user_pref("privacy.resistFingerprinting", true);',
'user_pref("privacy.resistFingerprinting.letterboxing", true);',
'user_pref("privacy.window.maxInnerWidth", 1600);',
'user_pref("privacy.window.maxInnerHeight", 900);',
]
)
if hard.first_party_isolation:
lines.append('user_pref("privacy.firstparty.isolate", true);')
if hard.disable_telemetry:
lines.append('user_pref("browser.send_pings", false);')
if hard.strict_tracking_protection:
lines.extend(
[
'user_pref("privacy.trackingprotection.enabled", true);',
'user_pref("privacy.trackingprotection.pbmode.enabled", true);',
]
)
# Persona spoofing (UA, accept-language, screen, platform)
if hard.persona is not None:
p = hard.persona
lines.extend(
[
f'user_pref("general.useragent.override", "{p.user_agent}");',
f'user_pref("intl.accept_languages", "{p.accept_language}");',
f'user_pref("general.useragent.locale", "{p.locale}");',
'user_pref("javascript.use_us_english_locale", true);',
f'user_pref("privacy.window.maxInnerWidth", {int(p.screen_w)});',
f'user_pref("privacy.window.maxInnerHeight", {int(p.screen_h)});',
# Hint timezone — Firefox honors TZ env var at launch (set by
# the launcher) but this pref nudges some site detection too.
f'user_pref("intl.locale.requested", "{p.locale}");',
]
)
elif hard.user_agent_override:
lines.append(
f'user_pref("general.useragent.override", "{hard.user_agent_override}");'
)
# ── Cookie policy ────────────────────────────────────────────────────────
cp: CookiePolicy = get_cookie_policy(hard.cookie_mode)
lines.extend([
f'user_pref("network.cookie.cookieBehavior", {cp.behavior});',
# pbmode = private-browsing mode uses same behavior
f'user_pref("network.cookie.cookieBehavior.pbmode", {cp.behavior});',
# lifetime: 0 = normal, 2 = session-only
f'user_pref("network.cookie.lifetimePolicy", {cp.lifetime});',
])
# Total Cookie Protection (TCP / Firefox partitioning)
if cp.partition:
lines.extend([
'user_pref("network.cookie.cookieBehavior.optInPartitioning", true);',
# Also isolate cache, localStorage, IndexedDB per top-level site
'user_pref("privacy.partition.serviceWorkers", true);',
'user_pref("privacy.partition.network_state", true);',
'user_pref("privacy.partition.bloburl_by_default", true);',
])
else:
lines.extend([
'user_pref("network.cookie.cookieBehavior.optInPartitioning", false);',
])
# SameSite=None cookies must be Secure (good hygiene regardless of mode)
lines.append('user_pref("network.cookie.sameSite.noneRequiresSecure", true);')
# ── Sanitize-on-shutdown ─────────────────────────────────────────────────
# The CookiePolicy sanitize flag takes priority; the hard.clear_on_shutdown
# toggle acts as an additional override for cookies+cache even when the
# cookie mode doesn't request it.
do_sanitize = cp.sanitize or hard.clear_on_shutdown
if do_sanitize:
lines.append('user_pref("privacy.sanitize.sanitizeOnShutdown", true);')
# Cookies
lines.append(f'user_pref("privacy.clearOnShutdown.cookies", {_bool(cp.clear_cookies or hard.clear_on_shutdown)});')
# Cache
lines.append(f'user_pref("privacy.clearOnShutdown.cache", {_bool(cp.clear_cache or hard.clear_on_shutdown)});')
# History
lines.append(f'user_pref("privacy.clearOnShutdown.history", {_bool(cp.clear_history or hard.clear_on_shutdown)});')
# Downloads list
lines.append('user_pref("privacy.clearOnShutdown.downloads", true);')
# Form / search bar autofill data
lines.append(f'user_pref("privacy.clearOnShutdown.formdata", {_bool(cp.clear_formdata or hard.clear_on_shutdown)});')
# Active sessions (HTTP auth, logged-in sites)
lines.append('user_pref("privacy.clearOnShutdown.sessions", true);')
# localStorage + IndexedDB
lines.append(f'user_pref("privacy.clearOnShutdown.localStorage", {_bool(cp.clear_ls or hard.clear_on_shutdown)});')
lines.append(f'user_pref("privacy.clearOnShutdown.indexedDB", {_bool(cp.clear_ls or hard.clear_on_shutdown)});')
# Service worker registrations
lines.append('user_pref("privacy.clearOnShutdown.serviceWorkers", true);')
# Offline web app cache
lines.append('user_pref("privacy.clearOnShutdown.offlineApps", true);')
else:
lines.append('user_pref("privacy.sanitize.sanitizeOnShutdown", false);')
if hard.timezone_utc:
lines.append('user_pref("privacy.resistFingerprinting.reduceTimerPrecision", true);')
lines.append("")
return "\n".join(lines)
def persona_env(hard: FirefoxHardening) -> dict[str, str]:
"""Environment overrides applied when launching Firefox under a persona.
Only the timezone needs the OS-level env var (TZ) — Firefox reads it
even when running under Windows.
"""
hard = apply_persona(hard)
if hard.persona is None:
return {}
return {"TZ": hard.persona.timezone}
def ensure_firefox_profile(
profile_dir: Path,
proxy_host: str,
proxy_port: int,
hard: FirefoxHardening,
) -> None:
profile_dir.mkdir(parents=True, exist_ok=True)
(profile_dir / "user.js").write_text(
build_user_js(proxy_host, proxy_port, hard),
encoding="utf-8",
)