From 24105829601a9cc66f3cad784a081f745251b608 Mon Sep 17 00:00:00 2001 From: feder-cr <85809106+feder-cr@users.noreply.github.com> Date: Tue, 9 Jun 2026 18:02:36 +0200 Subject: [PATCH] test: drop the 15 hand-rolled test_botd_* (real BotD now runs on CI) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These mirrored BotD's individual detectors (webdriver/appVersion/userAgent/ functionBind/productSub/process/evalLength/languages/plugins/mimeTypes/ distinctive-props/documentAttributes/windowSize/webGL) — our reverse-engineering of BotD from before we ran the real library. Now that test_detectors_e2e.py runs the actual @fingerprintjs/botd against the binary on CI (asserts bot===false), they're redundant. Kept the complementary/unique tests: fpjs-surface, pinning, sannysoft + fpscanner (which mimic detectors we do NOT run, so not covered by BotD/FpJS), and the determinism/consistency suite. --- tests/test_fingerprint_surface.py | 164 ------------------------------ 1 file changed, 164 deletions(-) diff --git a/tests/test_fingerprint_surface.py b/tests/test_fingerprint_surface.py index bd263cf..1de5d39 100644 --- a/tests/test_fingerprint_surface.py +++ b/tests/test_fingerprint_surface.py @@ -71,170 +71,6 @@ def _ev(page, expr): return page.evaluate(expr) -# =========================================================================== -# BotD detectors (github.com/fingerprintjs/BotD/tree/main/src/detectors) -# Each detector becomes one pytest. The failure name maps to the BotKind -# constant BotD would emit on the wire. -# =========================================================================== - - -@pytest.mark.e2e -def test_botd_webdriver_property_is_falsey(page): - """BotD: navigator.webdriver === true → HeadlessChrome verdict.""" - assert not _ev(page, "navigator.webdriver"), ( - "navigator.webdriver is truthy — instant HeadlessChrome verdict" - ) - - -@pytest.mark.e2e -def test_botd_app_version_no_headless_token(page): - """BotD detectAppVersion: /headless|electron|slimerjs/i in appVersion.""" - av = _ev(page, "navigator.appVersion") - for token in ("headless", "electron", "slimerjs"): - assert not re.search(token, av, re.I), ( - f"navigator.appVersion contains {token!r}: {av!r}" - ) - - -@pytest.mark.e2e -def test_botd_user_agent_no_headless_or_selenium_token(page): - """BotD: /headless|selenium|phantom/i in UA.""" - ua = _ev(page, "navigator.userAgent") - for token in ("headless", "selenium", "phantom"): - assert not re.search(token, ua, re.I), ( - f"navigator.userAgent contains {token!r}: {ua!r}" - ) - - -@pytest.mark.e2e -def test_botd_function_bind_is_function(page): - """BotD detectFunctionBind: missing Function.prototype.bind = PhantomJS.""" - assert _ev(page, "typeof Function.prototype.bind === 'function'") - - -@pytest.mark.e2e -def test_botd_product_sub_is_gecko_value(page): - """BotD detectProductSub: Firefox must return '20100101'; '20030107' - on a Firefox UA = Chrome-stub leaked under spoof.""" - assert _ev(page, "navigator.productSub") == "20100101", ( - "navigator.productSub must be '20100101' on Firefox" - ) - - -@pytest.mark.e2e -def test_botd_no_process_global(page): - """BotD detectProcess: window.process indicates Electron.""" - assert not _ev(page, - "typeof window.process !== 'undefined' && " - "window.process.type === 'renderer'" - ) - assert not _ev(page, - "typeof window.process !== 'undefined' && " - "window.process.versions != null && " - "typeof window.process.versions.electron !== 'undefined'" - ) - - -@pytest.mark.e2e -def test_botd_eval_length_matches_engine(page): - """BotD detectEvalLengthInconsistency: `eval.toString().length` must be - 37 on Gecko (33 on Chromium, 39 on IE). Mismatch = engine spoof.""" - assert _ev(page, "eval.toString().length") == 37 - - -@pytest.mark.e2e -def test_botd_languages_array_non_empty(page): - """BotD detectLanguagesLengthInconsistency: empty navigator.languages - is the classic HeadlessChrome tell.""" - assert _ev(page, "navigator.languages.length") > 0 - - -@pytest.mark.e2e -def test_botd_plugins_instance_of_PluginArray(page): - """BotD detectPluginsArray: navigator.plugins must be a real PluginArray.""" - assert _ev(page, "navigator.plugins instanceof PluginArray") - - -@pytest.mark.e2e -def test_botd_mime_types_consistent_prototype_chain(page): - """BotD areMimeTypesConsistent: navigator.mimeTypes and each entry - must have proper prototype chain. Spoofers using plain arrays fail.""" - consistent = _ev(page, """() => { - if (typeof navigator.mimeTypes === 'undefined' || - typeof MimeTypeArray === 'undefined') return false; - let ok = Object.getPrototypeOf(navigator.mimeTypes) === MimeTypeArray.prototype; - for (let i = 0; i < navigator.mimeTypes.length; i++) { - ok = ok && Object.getPrototypeOf(navigator.mimeTypes[i]) === MimeType.prototype; - } - return ok; - }""") - assert consistent, "navigator.mimeTypes prototype chain inconsistent" - - -@pytest.mark.e2e -def test_botd_no_distinctive_window_props(page): - """BotD checkDistinctiveProperties: scan window for automation globals.""" - DISTINCTIVE = [ - "awesomium", "RunPerfTest", "CefSharp", "fmget_targets", "geb", - "__nightmare", "nightmare", "__phantomas", "callPhantom", "_phantom", - "wdioElectron", "__webdriverFunc", "_WEBDRIVER_ELEM_CACHE", - "ChromeDriverw", "domAutomation", "domAutomationController", - ] - leaks = [n for n in DISTINCTIVE - if _ev(page, f"typeof window[{n!r}] !== 'undefined'")] - assert not leaks, f"Distinctive bot globals leaked: {leaks}" - - -@pytest.mark.e2e -def test_botd_no_distinctive_document_props(page): - """BotD: document-side automation globals (webdriver/selenium/cdc).""" - DOC_LEAKS = [ - "__webdriver_evaluate", "__selenium_evaluate", - "__webdriver_script_function", "__webdriver_script_func", - "__webdriver_script_fn", "__fxdriver_evaluate", - "__driver_unwrapped", "__webdriver_unwrapped", - "__driver_evaluate", "__selenium_unwrapped", - "__fxdriver_unwrapped", - "$cdc_asdjflasutopfhvcZLmcf", "$cdc_asdjflasutopfhvcZLmcfl_", - "$chrome_asyncScriptInfo", "__$webdriverAsyncExecutor", - ] - leaks = [n for n in DOC_LEAKS - if _ev(page, f"typeof document[{n!r}] !== 'undefined'")] - assert not leaks, f"document carries automation property names: {leaks}" - - -@pytest.mark.e2e -def test_botd_document_html_attributes_clean(page): - """BotD detectDocumentAttributes: html element attrs contain 'selenium' - / 'webdriver' / 'driver' → Selenium verdict.""" - attrs = _ev(page, - "Array.from(document.documentElement.attributes).map(a => a.name + '=' + a.value)") - bad = [a for a in attrs if any(t in a.lower() - for t in ("selenium", "webdriver", "driver"))] - assert not bad, f"HTML attributes contain bot tokens: {bad}" - - -@pytest.mark.e2e -def test_botd_window_size_nonzero(page): - """BotD detectWindowSize: headless without window manager → 0x0.""" - ow = _ev(page, "window.outerWidth") - oh = _ev(page, "window.outerHeight") - assert ow > 0 and oh > 0, ( - f"outerWidth/Height = {ow}/{oh} — headless without window manager" - ) - - -@pytest.mark.e2e -def test_botd_webgl_debug_renderer_info_available(page): - """BotD detectWebGL: WEBGL_debug_renderer_info extension must exist.""" - has_ext = _ev(page, """() => { - const c = document.createElement('canvas'); - const gl = c.getContext('webgl') || c.getContext('experimental-webgl'); - return !!gl && !!gl.getExtension('WEBGL_debug_renderer_info'); - }""") - assert has_ext - - # =========================================================================== # sannysoft.com — classic Puppeteer detection harness # ===========================================================================