mirror of
https://github.com/daijro/camoufox.git
synced 2026-10-04 08:00:19 +00:00
WebGL vendor, renderer, context attributes, extensions, parameters and shader precisions, for WebGL1 and WebGL2, now come from fpgen's recorded Firefox devices instead of webgl_data.db, which is deleted with the camoufox/webgl/ package. camoufox/webgl.py: - webgl_for_gpu() traces `webgl` given Firefox, the OS and the GPU, then `webgl2` given the chosen `webgl` too, and draws each with one seeded random.Random. The GPU and the webgl value are pinned by their fpgen lookup index: a dict condition is flattened into leaves that overwrite each other, so only the renderer applied and Linux "Mesa" and "AMD" Radeon HD 3200 devices came back mixed. - sample_webgl_for_screen() draws the GPU of a generated identity from fpgen's per-OS weights, filtering out software rasterisers, GPUs the OS cannot report, discrete GPUs behind a netbook screen and the resistFingerprinting "Mozilla" mask before the weighted choice, so there is no rejection loop. An empty pool raises. - The draft/host-dependent extension filter moves over unchanged. A preset's GPU and a caller's webgl_config pair are looked up as given; a pair fpgen has never seen from Firefox on that OS raises instead of falling back to another GPU. generate_context_fingerprint no longer falls back to the host GPU when the draw fails. For 10 of the 15 (GPU, OS) pairs the two sources share, one of fpgen's records converts to exactly the database row on every value the browser reads. The other five rows (Linux R9 200 and Radeon HD 3200, macOS Intel HD, and two software rasterisers) are devices fpgen does not carry; those GPUs now present fpgen's recorded devices instead. The Linux GTX 980 row is kept as a test fixture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
63 lines
2.7 KiB
Python
63 lines
2.7 KiB
Python
"""The data files that ship must not contain an identity we would refuse to use.
|
|
|
|
`camoufox.coherence` filters at draw time, so an impossible row can never reach
|
|
a page either way. This is the second filter, on the data itself: a row that
|
|
survives here is one a future refresh could ship, a consumer reading the JSON
|
|
directly would get, and a reviewer would take as real. Both filters run the same
|
|
rules -- `scripts/clean-fingerprint-data.py --write` is what makes these pass.
|
|
|
|
Dropped on 2026-09-17: 38 of 435 presets (26 with a GPU their OS cannot report,
|
|
7 pairing Apple Silicon with a core count Apple never shipped, 4 with a colour
|
|
depth their GPU contradicts, 3 with a phone viewport, 1 claiming 40 touch
|
|
points).
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
from os.path import dirname, join
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
sys.path.insert(0, join(dirname(__file__), ".."))
|
|
|
|
from camoufox import coherence # noqa: E402
|
|
from camoufox.fingerprints import from_preset # noqa: E402
|
|
|
|
DATA = Path(__file__).parent.parent / "camoufox"
|
|
PRESET_FILES = ("fingerprint-presets.json", "fingerprint-presets-v150.json")
|
|
OS_KEY = {"macos": "mac", "windows": "win", "linux": "lin"}
|
|
|
|
|
|
@pytest.mark.parametrize("filename", PRESET_FILES)
|
|
def test_every_bundled_preset_is_coherent_as_stored(filename):
|
|
presets = json.loads((DATA / filename).read_text())["presets"]
|
|
for os_name, entries in presets.items():
|
|
assert entries, f"{filename}/{os_name} has no presets left"
|
|
for index, preset in enumerate(entries):
|
|
config = from_preset(preset, "152")
|
|
violations = coherence.validate(config, OS_KEY[os_name])
|
|
assert violations == [], (
|
|
f"{filename} {os_name}[{index}]: "
|
|
+ "; ".join(v.detail for v in violations)
|
|
+ " -- run scripts/clean-fingerprint-data.py --write"
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize("filename", PRESET_FILES)
|
|
def test_every_preset_gpu_has_webgl_data(filename):
|
|
"""A preset records only its GPU's name; the WebGL parameters behind it come
|
|
from fpgen. A GPU fpgen has never seen Firefox report on that OS has none, so
|
|
launching it would pair the name with another device's parameters."""
|
|
from camoufox.webgl import firefox_gpus
|
|
|
|
presets = json.loads((DATA / filename).read_text())["presets"]
|
|
for os_name, entries in presets.items():
|
|
known = firefox_gpus(os_name)
|
|
for index, preset in enumerate(entries):
|
|
gpu = (preset["webgl"]["unmaskedVendor"], preset["webgl"]["unmaskedRenderer"])
|
|
assert gpu in known, (
|
|
f"{filename} {os_name}[{index}]: {gpu[1]!r} has no WebGL data"
|
|
" -- run scripts/clean-fingerprint-data.py --write"
|
|
)
|