Uses a clean manual HTTP/SSL proxy configuration, clears conflicting SOCKS fields, and stops writing prefs.js so Firefox can manage runtime prefs correctly. Co-authored-by: Cursor <cursoragent@cursor.com>
131 lines
5.3 KiB
Python
131 lines
5.3 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);',
|
|
'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:
|
|
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 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",
|
|
)
|