feat(M4): FPP-forward farbling + dark mode unlock - #20
Conversation
Switch anti-fingerprinting from RFP (uniform, "stands out", per-read canvas randomization) to FPP (per-origin deterministic farbling), the roadmap's "convincing common fingerprint" posture. The three FP modes are mutually exclusive, so RFP must be off for FPP to run. assets/neonwolf.overrides.cfg: - privacy.resistFingerprinting=false, privacy.fingerprintingProtection=true, remoteOverrides.enabled=false. - fingerprintingProtection.overrides adds WebGL randomization, hw-concurrency pin, audio/font/timer protection on top of FPP's default canvas farbling. UA/screen uniform spoofs deliberately omitted (real-for-platform is more common); timezone left real (its JS override is RFP-pref-gated, and a timezone/IP mismatch is itself a tell). - webgl.disabled=false so WebGL is farbled (WebGL-off is a conspicuous tell). - layout.css.prefers-color-scheme.content-override=2 (auto). Verified locally (Marionette): canvas farbling deterministic per-origin (Brave-style), hardwareConcurrency pinned to 4, and DARK MODE unlocked (prefers-color-scheme honors the override under FPP; RFP was forcing light). NOT merged: per plan, ships only behind a full browserleaks/coveryourtracks + WebGL pass (needs a real GL context + network — headful), proving it's more convincing, not less protected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AI cowork.md (the Strong/Weak-AI playbook), GROK.md (the handoff artifact it prescribes), and docs/agents/ are local working scratch, never repo content. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Empirical validation of the FPP posture found WebGL still dead in content: LibreWolf's webgl-permission.patch gates context creation behind a per-site 'webgl' permission (librewolf.webgl.prompt, compiled default TRUE) and ships the doorhanger hidden — silent deny everywhere, the exact same conspicuous tell webgl.disabled=false was meant to remove. Turn the gate off; WebGL now runs farbled (+WebGLRandomization per-eTLD+1 readback noise, verified deterministic per-origin/per-session; +WebGLRenderInfo spoofs Mozilla/Mozilla). Full headful validation (Marionette on Wayland, real network): canvas + WebGL farble per-eTLD+1, stable across reloads, re-keyed per session, plain control identical across domains with all tiers off; hwConcurrency pinned 4; timezone/screen/UA real; dark mode honored; CoverYourTracks verdict 'strong protection against Web tracking'. Known gap: audio readback is NOT farbled (FPP has no audio randomization target — RFP-only protection; follow-up). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…scriptions UI Shields panel (M4 'integrate with Shields'): - fingerprinting toggle now drives privacy.fingerprintingProtection (the M4 posture pref), label 'Farble fingerprinting' - new per-site 'Farble on this site' subrow writing an -AllTargets entry to BOTH privacy.fingerprintingProtection.granularOverrides AND the baseline tier's granularOverrides (canvas farbling rides baseline FPP — verified empirically); foreign/webcompat entries are never touched, unreadable pref hides the row (all-or-nothing writes), PSL-hosted eTLD+1 edge documented Element picker (M5): real selector generator replacing the placeholder — unique #id fast path, bottom-up max-4-segment path with stable-class filtering (hashed CSS-module classes rejected), :nth-of-type disambiguation, document-uniqueness testing, simpleSelector fallback; pure DOM reads only. Lists page (M5): 'Subscribed lists' manager bound to neonwolf.shields.lists.subscriptions — https-only validation, dedupe, live pref observer, Remove per row, synthwave-styled via shared filters classes. Implemented by Grok (executor) from Claude's spec; line-by-line reviewed, staged into the built tree and Marionette-verified end-to-end (granular-pref roundtrip incl. corrupt-pref no-clobber, page render screenshot). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
UBONetFilter now compiles neonwolf.shields.lists.subscriptions (newline- separated https:// URLs, managed by the Shields lists/filters pages) as extra engine lists on every live refresh, and a pref observer triggers an immediate refresh on subscribe/unsubscribe. Fetch-only by design: no bundled fallback (a failed fetch drops that subscription until the next cycle), 1-byte floor (personal lists can be tiny) but a 20 MB cap so a hostile URL can't balloon the compile; invalid/non-https lines are ignored. No selfie write — like the bundled-list refresh, subscriptions apply in-memory after the first refresh of a session. Marionette-verified end-to-end against the built tree: subscribe to easylistgermany -> refresh fires -> adnx.de script blocked; unsubscribe -> refresh -> unblocked again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
M4 merge gate: PASSED (overnight validation run, headful Marionette on Wayland, real network, built tree)
Known gap for a follow-up: audio readback is not farbled (FPP has no audio noise target; that protection was RFP-only). 🤖 Generated with Claude Code |
…k gap First live adblock benchmark (adblock.turtlecute.org, the maintained d3ward replacement — d3ward is archived) scored 116/133. Engine-side probing of every test host pinned the shortfall to 9 tracker/ad network hosts unmatched by all ten bundled lists: TikTok ads/events APIs, Yahoo ad-tech + DMP, and the Yandex Metrika/AppMetrica apex (bundled lists only covered paths/subdomains). Add a curated assets/adblock/neonwolf-extra.txt (bundled-only, no fetch URL — served from the dump) with those 9 hosts as $third-party rules so first-party use of each console still works. Wired into gen-adblock-dump.py's LISTS, the list_names pref, and the lists-page display. Re-benchmarked against the rebuilt engine: 125/133 = 94%, all 131 network hosts now blocked (verified via direct matchRequest). The remaining 8 are cosmetic-filter + ad-script-loading checks — the known M2 scriptlet gap (scriptlets pref-disabled pending the document_start race fix), not a list gap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the archived d3ward metric with adblock.turtlecute.org throughout; record M4 (FPP-forward farbling, validated PR #20) and M5 (picker, custom filters, subscriptions) as functionally complete with 2026-07-08 progress notes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Follow-up shipped: adblock benchmark gap closed → 94%. d3ward is archived; benchmarked on adblock.turtlecute.org (the maintained d3ward-style replacement). First run was 116/133 (87%). Engine-side probing pinned the shortfall to 9 tracker/ad hosts unmatched by all ten bundled lists (TikTok ads/events APIs, Yahoo ad-tech + DMP, Yandex Metrika/AppMetrica apex). Added a curated bundled list Also refreshed PLAN_OF_ACTION.md (metric d3ward→turtlecute; M4/M5 marked shipped). 🤖 Generated with Claude Code |
Complete the Google Safe Browsing opt-out for this privacy-focused build. The LibreWolf baseline already disables the SB malware/phishing/blockedURIs/downloads features and blanks the google4 + legacy-google gethash/update URLs, but leaves the newer google5 provider (stock FF152 ships it enabled) and the google4 dataSharing toggle untouched — a residual safebrowsing.googleapis.com phone-home. Turn those off too so no Google SB lookup remains; malware/phishing coverage comes from the bundled uBO lists (ubo-badware et al.) via the native engine. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The notifier queried GitHub /releases/latest, which excludes prereleases and drafts. Beta builds ship as GitHub *prereleases*, so a beta tester would never be told a newer beta exists. Query /releases?per_page=30 instead and scan for the highest-version non-draft release (prereleases eligible, drafts skipped), reusing the existing _isNewer comparator and keeping the throttle, enable gate, and error handling unchanged. Verified against the live GitHub API: scans 5 releases, correctly picks 152.0.1-3, treats the 152.0.1-1 prerelease as eligible. Executor: Grok (worktree, no-commit); reviewed, tested, and captured by Claude. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ection Public-facing beta docs for Linux + Windows testers: download links, how to install the unsigned builds past SmartScreen / run the AppImage, how the notify-only update check works (no auto-update by design), and a Known Issues list (adblock ~94% pending scriptlets, audio not farbled, no macOS build, unsigned, no built-in password manager, Windows less-tested). README gains a short Beta downloads section linking it. Executor: Grok (worktree, no-commit, facts-only spec); reviewed line-by-line against the known facts and captured by Claude. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Switches anti-fingerprinting from RFP (uniform, detectable, per-read canvas randomization) to FPP (per-origin deterministic farbling) — the roadmap's 'convincing common fingerprint' posture. The FP modes are mutually exclusive, so RFP goes off.
Also unlocks dark mode (a stated adoption blocker): RFP was forcing
prefers-color-scheme: light; under FPP the native 'Website appearance' setting works.Verified locally (Marionette, no rebuild — runtime/startup prefs)
Merge gate (NOT done yet — needs headful GL + network)
browserleaks canvas/webgl/audio/fonts (site-varying, protected) + coveryourtracks (randomized, no privacy-browser tell). WebGL can't be tested headless (no GL context).
🤖 Generated with Claude Code