From 4e8960e323897e042ffd794d7c472e7d3e9286b3 Mon Sep 17 00:00:00 2001 From: SGavrl <277843151+SGavrl@users.noreply.github.com> Date: Thu, 11 Jun 2026 22:01:41 +0000 Subject: [PATCH] stealth: add NetworkInformation and ContentIndex shims NetworkInformation class with downlinkMax on its prototype clears noDownlinkMax from the like-headless flag list. creepjs checks 'downlinkMax' in (window.NetworkInformation?.prototype || {}). ContentIndex stub on globalThis clears noContentIndex. creepjs checks 'ContentIndex' in window. navigator.connection is now a real NetworkInformation instance instead of a plain object literal. Result: 0% like-headless, 0% headless, 0% stealth on creepjs. 33/33 obstacle course unchanged. --- crates/obscura-js/js/bootstrap.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/crates/obscura-js/js/bootstrap.js b/crates/obscura-js/js/bootstrap.js index 5aa8116..ab41ffa 100644 --- a/crates/obscura-js/js/bootstrap.js +++ b/crates/obscura-js/js/bootstrap.js @@ -2588,6 +2588,23 @@ _markNative(PluginArray.prototype.item); _markNative(PluginArray.prototype.namedItem); _markNative(PluginArray.prototype.refresh); +class NetworkInformation { + get downlink() { return 10; } + get downlinkMax() { return Infinity; } + get effectiveType() { return '4g'; } + get rtt() { return 50; } + get saveData() { return false; } + get type() { return 'wifi'; } + get onchange() { return null; } + set onchange(v) {} + get ontypechange() { return null; } + set ontypechange(v) {} +} +_markNative(NetworkInformation); +globalThis.NetworkInformation = NetworkInformation; + +globalThis.ContentIndex = class ContentIndex {}; + globalThis.navigator = { get userAgent() { return globalThis.__obscura_ua || "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"; }, get appVersion() { return this.userAgent.replace('Mozilla/', ''); }, @@ -2597,7 +2614,7 @@ globalThis.navigator = { vendor: "Google Inc.", product: "Gecko", productSub: "20030107", doNotTrack: null, deviceMemory: 8, - connection: { effectiveType: "4g", type: "wifi", rtt: 50, downlink: 10, saveData: false, onchange: null, addEventListener(){}, removeEventListener(){}, dispatchEvent(){return true;} }, + connection: new NetworkInformation(), pdfViewerEnabled: true, get plugins() { const p = new PluginArray([