Adds VPN-aware leak handling, chain testing UX improvements, hardened Firefox launch/profile management, privacy/device hardening modules, and tray/status upgrades so the app is production-ready as the new baseline. Co-authored-by: Cursor <cursoragent@cursor.com>
136 lines
5.4 KiB
Python
136 lines
5.4 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
|
|
|
|
@dataclass
|
|
class FirefoxHardening:
|
|
force_proxy: bool = True
|
|
disable_webrtc: bool = True
|
|
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
|
|
|
|
|
|
def _bool(v: bool) -> str:
|
|
return "true" if v else "false"
|
|
|
|
|
|
def build_user_js(
|
|
proxy_host: str,
|
|
proxy_port: int,
|
|
hard: FirefoxHardening,
|
|
) -> str:
|
|
lines: list[str] = [
|
|
"// Managed by Proxy God. Changes are overwritten on next launch.",
|
|
'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.peerconnection.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);',
|
|
'user_pref("webgl.disabled", false);',
|
|
'user_pref("webgl.enable-debug-renderer-info", false);',
|
|
]
|
|
if hard.force_proxy:
|
|
lines.extend(
|
|
[
|
|
'user_pref("network.proxy.type", 1);',
|
|
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)});',
|
|
f'user_pref("network.proxy.socks", "{proxy_host}");',
|
|
f'user_pref("network.proxy.socks_port", {int(proxy_port)});',
|
|
'user_pref("network.proxy.socks_version", 5);',
|
|
'user_pref("network.proxy.socks_remote_dns", true);',
|
|
'user_pref("network.proxy.no_proxies_on", "");',
|
|
]
|
|
)
|
|
if hard.disable_webrtc:
|
|
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);',
|
|
]
|
|
)
|
|
if hard.clear_on_shutdown:
|
|
lines.extend(
|
|
[
|
|
'user_pref("privacy.sanitize.sanitizeOnShutdown", true);',
|
|
'user_pref("privacy.clearOnShutdown.history", true);',
|
|
'user_pref("privacy.clearOnShutdown.cookies", true);',
|
|
'user_pref("privacy.clearOnShutdown.cache", true);',
|
|
'user_pref("privacy.clearOnShutdown.downloads", true);',
|
|
'user_pref("privacy.clearOnShutdown.formdata", true);',
|
|
'user_pref("privacy.clearOnShutdown.sessions", true);',
|
|
]
|
|
)
|
|
if hard.timezone_utc:
|
|
lines.append('user_pref("privacy.resistFingerprinting.reduceTimerPrecision", true);')
|
|
lines.append("")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def build_prefs_js_marker() -> str:
|
|
return (
|
|
"// Proxy God managed profile\n"
|
|
'// Do not edit manually; user.js is rewritten on launch.\n'
|
|
)
|
|
|
|
|
|
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",
|
|
)
|
|
(profile_dir / "prefs.js").write_text(build_prefs_js_marker(), encoding="utf-8")
|