From 2328147658e5566e9a4a4bbaed786f37d6fa21f5 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 11 Sep 2026 07:54:52 +0200 Subject: [PATCH] --fingerprint dropped deviceScaleFactor, so the identity contradicted itself `playwright_context_kwargs` mapped the user agent, the locale, the timezone and the screen onto the browser context and ignored `deviceScaleFactor`, which the fingerprint API returns beside them. Measured 2026-09-11 against the live API and a live browser: a fingerprint stating `deviceScaleFactor: 1.25` produced a browser reporting `window.devicePixelRatio === 1`. That is the mismatch this flag exists to prevent, on an axis any fingerprinter reads for free and for nothing: the paid identity said one thing and the browser said another, on every run, silently. Same shape as the three defects the family notes already record for this file -- a key the API returns that nothing applies -- and found the same way, by comparing a live browser against the fingerprint instead of by reading the code. Playwright takes it as its own context option, so the fix is to pass it. Verified in a live browser: 1.25 requested, 1.25 reported, with the user agent, timezone and locale still matching. The check is pinned in the offline suite so it stays fixed. This repo had no check for fingerprint APPLICATION at all, which is how the gap survived, so the new test covers the user agent, locale, timezone and viewport as well. Found while auditing a new sibling repo against the family notes. All five repos in this family had it. Co-Authored-By: Claude Opus 5 (1M context) --- fingerprint_client.py | 14 ++++++++++++++ smoke_test.py | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/fingerprint_client.py b/fingerprint_client.py index 29c2ebc..11e295c 100644 --- a/fingerprint_client.py +++ b/fingerprint_client.py @@ -241,6 +241,20 @@ def playwright_context_kwargs(fp: dict) -> dict: kwargs["viewport"] = {"width": outer_w, "height": max(400, outer_h)} kwargs["screen"] = {"width": width, "height": height} + # The device pixel ratio, which Playwright takes as its own context + # option and which was previously dropped on the floor. Measured + # 2026-09-11 against the live API and a live browser: a fingerprint + # stating `deviceScaleFactor: 1.25` produced a browser reporting + # `window.devicePixelRatio === 1`, so the identity contradicted itself + # on an axis any fingerprinter reads for free -- and a contradiction is + # exactly what this flag exists to avoid. Same shape as the three + # defects the family notes already list for this file: a key the API + # returns that nothing applies. Found by comparing a live browser + # against the fingerprint rather than by reading the code. + scale = (fp.get("screen") or {}).get("deviceScaleFactor") + if isinstance(scale, (int, float)) and not isinstance(scale, bool) and scale > 0: + kwargs["device_scale_factor"] = float(scale) + intl = fp.get("intl") or {} # The fingerprint's OWN locale. This used to be built as # f"en-{country}", which produced "en-DE" for a German fingerprint — an diff --git a/smoke_test.py b/smoke_test.py index 19ea65a..80edf08 100644 --- a/smoke_test.py +++ b/smoke_test.py @@ -1417,6 +1417,46 @@ def test_ci_checks_is_actually_wired_up(): ok &= check("...and carries no second, narrower inline credential grep", "(ws|wss)://[^ " not in wf) + # THE FINGERPRINT IS APPLIED, not merely fetched. This repo had no + # check for that at all, which is how the gap below survived: the client + # mapped the user agent, the locale, the timezone and the screen onto the + # context and dropped `deviceScaleFactor` on the floor, so a fingerprint + # stating 1.25 produced a browser reporting `devicePixelRatio === 1` -- + # an identity contradicting itself on an axis a fingerprinter reads for + # free. Measured against the live API and a live browser on 2026-09-11, + # in a sibling repo, and found in this one by the same comparison. + import fingerprint_client as _fpc + fp = { + "id": 1000000, + "country": "US", + "userAgent": { + "userAgent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/146.0.0.0 Safari/537.36"), + "platform": "Windows", + "mobile": False, + }, + "intl": {"contentLocale": "en-US", + "languages": ["en-US", "en"], + "timeZone": "America/New_York"}, + "screen": {"width": 1920, "height": 1080, + "outerWidth": 1920, "outerHeight": 992, + "deviceScaleFactor": 1.25}, + } + kw = _fpc.playwright_context_kwargs(fp) + ok &= check("fingerprint: the user agent is the fingerprint's own", + kw.get("user_agent") == fp["userAgent"]["userAgent"]) + ok &= check("fingerprint: the locale is the fingerprint's own, " + "not en-", kw.get("locale") == "en-US") + ok &= check("fingerprint: the timezone is carried, so the browser " + "cannot contradict it", + kw.get("timezone_id") == "America/New_York") + ok &= check("fingerprint: the viewport is the window, not the screen", + kw.get("viewport", {}).get("height") == 992 + and kw.get("screen", {}).get("height") == 1080) + ok &= check("fingerprint: the device scale factor is carried", + kw.get("device_scale_factor") == 1.25) + # `--fp-tags` MUST DEFAULT TO ONE OS-FAMILY TAG. It shipped as # "Windows,Chrome,Desktop", which the fingerprint API rejects with HTTP # 400 — so --fingerprint failed on every invocation, while