fix: stock animations and speech by default; drop config keys that freeze live values

Three behaviours a page could detect, changed in one breaking release:

- **Animations run on stock timing.** no-css-animations.patch finished every
  finite animation at once by default, and any page could read it:
  `el.animate(frames, 1000).effect.getComputedTiming().duration` was 0, and a
  500ms transition reported 0. Measured on v152.0.4-beta.31. The speedup is
  now an opt-in, `instantAnimations: True`, which raises a LeakWarning.
  disableInstantAnimations is gone.
- **speak() on a spoofed voice works like a real voice.** It fired `error`
  after 3ms unless voices:fakeCompletion was set, and then start and end in
  the same tick. It now starts and ends after the text's duration at ~150
  words per minute. Both voices:fakeCompletion keys are gone, and so is a
  debug line printed to stderr on every call.
- **Keys removed:**
  - battery:* and window.scrollMinX/Y: Firefox keeps getBattery() and
    scrollMin* chrome-only, so no page could read them.
  - window.scrollMaxX/Y, screen.pageXOffset/pageYOffset,
    window.history.length and document.body.client*: each pinned a live value
    to a constant, so scrolling, navigating or re-laying out never changed it.
    fpgen.yml mapped pageYOffset, so about 15% of identities froze
    window.scrollY at a non-zero value.
  - The body keys' role as an undocumented alias for window.innerWidth/Height
    in browser-init and in the launcher.
  - MaskConfig::GetInt32Rect, which only the body keys used.

New guards, both of which fail on v152.0.4-beta.31:
tests/patches/animation-timing.py and tests/patches/spoofed-voice-speaks.py.
The decisions are recorded as animations-run-on-stock-timing and
spoofed-voices-speak. Every patch applies cleanly to a fresh tree, and the
result builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jake Writer
2026-09-25 20:33:21 -06:00
co-authored by Claude Opus 5.5
parent 676fb3f7c1
commit fb21b2e35a
17 changed files with 274 additions and 271 deletions
+7
View File
@@ -194,3 +194,10 @@ def test_config_overrides_reach_the_config_and_the_init_script():
context = fp.generate_context_fingerprint(os="linux", config_overrides={"audio:seed": 7})
assert context["config"]["audio:seed"] == 7
assert "setAudioFingerprintSeed(7)" in context["init_script"]
def test_instant_animations_warn_that_they_are_detectable():
from camoufox._warnings import LeakWarning
with pytest.warns(LeakWarning, match="getComputedTiming"):
launch(config={"instantAnimations": True}, i_know_what_im_doing=False)
-1
View File
@@ -22,7 +22,6 @@ def _opts(config_blob: str):
[
('{"window.outerWidth": 360}', True),
('{"window.innerHeight": 740}', True),
('{"document.body.clientWidth": 360}', True),
('{"screen.width": 360}', False),
('{"navigator.userAgent": "x"}', False),
("{}", False),