jumpy-lion 0.1.5 → 0.1.6-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +13 -0
  2. package/dist/browser-controller.d.ts.map +1 -1
  3. package/dist/browser-controller.js +52 -2
  4. package/dist/browser-controller.js.map +1 -1
  5. package/dist/browser-plugin.d.ts +31 -0
  6. package/dist/browser-plugin.d.ts.map +1 -1
  7. package/dist/browser-plugin.js +76 -1
  8. package/dist/browser-plugin.js.map +1 -1
  9. package/dist/browser-process/anti-detect-browser.d.ts +56 -0
  10. package/dist/browser-process/anti-detect-browser.d.ts.map +1 -0
  11. package/dist/browser-process/anti-detect-browser.js +134 -0
  12. package/dist/browser-process/anti-detect-browser.js.map +1 -0
  13. package/dist/browser-process/anti-detect-config.d.ts +84 -0
  14. package/dist/browser-process/anti-detect-config.d.ts.map +1 -0
  15. package/dist/browser-process/anti-detect-config.js +178 -0
  16. package/dist/browser-process/anti-detect-config.js.map +1 -0
  17. package/dist/browser-process/browser.d.ts +19 -0
  18. package/dist/browser-process/browser.d.ts.map +1 -1
  19. package/dist/browser-process/browser.js +83 -4
  20. package/dist/browser-process/browser.js.map +1 -1
  21. package/dist/browser-process/get-chrome-executable.d.ts +7 -0
  22. package/dist/browser-process/get-chrome-executable.d.ts.map +1 -1
  23. package/dist/browser-process/get-chrome-executable.js +42 -0
  24. package/dist/browser-process/get-chrome-executable.js.map +1 -1
  25. package/dist/browser-process/index.d.ts +4 -1
  26. package/dist/browser-process/index.d.ts.map +1 -1
  27. package/dist/browser-process/index.js +3 -1
  28. package/dist/browser-process/index.js.map +1 -1
  29. package/dist/crawler.d.ts +2 -0
  30. package/dist/crawler.d.ts.map +1 -1
  31. package/dist/crawler.js +5 -2
  32. package/dist/crawler.js.map +1 -1
  33. package/dist/fingerprinting/fingerprint-injector.d.ts +39 -0
  34. package/dist/fingerprinting/fingerprint-injector.d.ts.map +1 -1
  35. package/dist/fingerprinting/fingerprint-injector.js +141 -50
  36. package/dist/fingerprinting/fingerprint-injector.js.map +1 -1
  37. package/dist/fingerprinting/fingerprint-overrides/audio-spoofing.d.ts.map +1 -1
  38. package/dist/fingerprinting/fingerprint-overrides/audio-spoofing.js +16 -0
  39. package/dist/fingerprinting/fingerprint-overrides/audio-spoofing.js.map +1 -1
  40. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.d.ts.map +1 -1
  41. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.js +3 -2
  42. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.js.map +1 -1
  43. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts.map +1 -1
  44. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js +18 -10
  45. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js.map +1 -1
  46. package/dist/fingerprinting/fingerprint-overrides/index.d.ts +1 -1
  47. package/dist/fingerprinting/fingerprint-overrides/index.d.ts.map +1 -1
  48. package/dist/fingerprinting/fingerprint-overrides/index.js +1 -1
  49. package/dist/fingerprinting/fingerprint-overrides/index.js.map +1 -1
  50. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.d.ts.map +1 -1
  51. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js +5 -8
  52. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js.map +1 -1
  53. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.d.ts +12 -1
  54. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.d.ts.map +1 -1
  55. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.js +27 -22
  56. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.js.map +1 -1
  57. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.d.ts.map +1 -1
  58. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js +86 -28
  59. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js.map +1 -1
  60. package/dist/fingerprinting/fingerprint-overrides/stealth-script.d.ts.map +1 -1
  61. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js +165 -33
  62. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js.map +1 -1
  63. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.d.ts.map +1 -1
  64. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.js +10 -8
  65. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.js.map +1 -1
  66. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.d.ts.map +1 -1
  67. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.js +9 -7
  68. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.js.map +1 -1
  69. package/dist/fingerprinting/fingerprint-overrides/ua-ch.js +6 -6
  70. package/dist/fingerprinting/fingerprint-overrides/utils.d.ts.map +1 -1
  71. package/dist/fingerprinting/fingerprint-overrides/utils.js +44 -1
  72. package/dist/fingerprinting/fingerprint-overrides/utils.js.map +1 -1
  73. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.d.ts.map +1 -1
  74. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js +43 -1
  75. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js.map +1 -1
  76. package/dist/fingerprinting/fingerprint-overrides/webgpu-spoofing.d.ts.map +1 -1
  77. package/dist/fingerprinting/fingerprint-overrides/webgpu-spoofing.js +9 -1
  78. package/dist/fingerprinting/fingerprint-overrides/webgpu-spoofing.js.map +1 -1
  79. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.d.ts.map +1 -1
  80. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.js +14 -3
  81. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.js.map +1 -1
  82. package/dist/fingerprinting/non-apify-fingerprint-generator.d.ts +32 -0
  83. package/dist/fingerprinting/non-apify-fingerprint-generator.d.ts.map +1 -0
  84. package/dist/fingerprinting/non-apify-fingerprint-generator.js +480 -0
  85. package/dist/fingerprinting/non-apify-fingerprint-generator.js.map +1 -0
  86. package/dist/tsconfig.build.tsbuildinfo +1 -1
  87. package/package.json +11 -2
  88. package/scripts/postinstall.cjs +242 -0
@@ -33,15 +33,18 @@ export const createStealthScript = () => {
33
33
  });
34
34
  };
35
35
 
36
- // Generate consistent session seed for stable values
37
- const generateSessionSeed = () => {
38
- const ua = navigator.userAgent || '';
39
- const screen = window.screen;
40
- const seed = ua.length + (screen.width || 0) + (screen.height || 0);
41
- return seed;
42
- };
43
-
44
- const sessionSeed = generateSessionSeed();
36
+ // Use centralized stable hash from __stealth store (set up by utils.ts preamble).
37
+ // Falls back to a UA+screen hash so the module works even if utils.ts somehow
38
+ // runs after this script (should not happen given injection order).
39
+ const _ss = typeof __stealth !== 'undefined' ? __stealth : {};
40
+ const sessionSeed = (_ss.stableHash
41
+ ? _ss.stableHash(0xCAFE9001)
42
+ : (() => {
43
+ const ua = navigator.userAgent || '';
44
+ const s = window.screen;
45
+ return ua.length + (s.width || 0) + (s.height || 0);
46
+ })()
47
+ );
45
48
 
46
49
  // Helper to safely define property with guards
47
50
  const safeDefineProperty = (obj, prop, descriptor) => {
@@ -84,11 +87,13 @@ export const createStealthScript = () => {
84
87
 
85
88
  // 3. WebDriver and Automation Flags Removal (2025)
86
89
  const removeAutomationFlags = () => {
87
- // Override webdriver to false (NOT undefined).
88
- // In real Chrome 89+, navigator.webdriver exists and is false.
89
- // Setting to undefined would make 'webdriver' in navigator return false,
90
- // which is itself a detection vector.
91
- safeDefineGetter(navigator, 'webdriver', () => false, true);
90
+ // NOTE: navigator.webdriver is NOT overridden here.
91
+ // The Chromium C++ patch (Anti-Detect 0006) makes navigator.webdriver
92
+ // unconditionally return false at the prototype level. Adding a JS own
93
+ // property here would make navigator.hasOwnProperty('webdriver') === true
94
+ // and Object.getOwnPropertyDescriptor(navigator,'webdriver') return a
95
+ // descriptor, both of which are detectable tells that don't exist in real
96
+ // Chrome. The C++ patch is the correct and sufficient fix.
92
97
 
93
98
  // Remove automation indicators
94
99
  const automationProperties = [
@@ -113,6 +118,10 @@ export const createStealthScript = () => {
113
118
  } catch (e) {}
114
119
  });
115
120
 
121
+ // Ensure Error.stackTraceLimit is the V8 default (10).
122
+ // Some automation frameworks change this value; FingerprintJS checks it.
123
+ try { if (typeof Error.stackTraceLimit !== 'undefined') Error.stackTraceLimit = 10; } catch (e) {}
124
+
116
125
  // Ensure window.chrome exists (handled more fully by spoofChromeRuntime)
117
126
  // NOTE: Removed stack-trace-based chrome getter that created new Error()
118
127
  // on every access - expensive and broken since stack sanitization removes
@@ -205,6 +214,8 @@ export const createStealthScript = () => {
205
214
  Object.defineProperty(arr, 'item', { value: (index) => arr[index] || null, writable: false, enumerable: false });
206
215
  Object.defineProperty(arr, 'namedItem', { value: (name) => arr[name] || null, writable: false, enumerable: false });
207
216
  Object.defineProperty(arr, 'refresh', { value: () => {}, writable: false, enumerable: false });
217
+ // Allow for...of iteration — checked by DataDome and FingerprintJS Pro
218
+ arr[Symbol.iterator] = function* () { for (let i = 0; i < fakePlugins.length; i++) yield arr[i]; };
208
219
  return arr;
209
220
  };
210
221
  safeDefineGetter(navigator, 'plugins', pluginsGetter);
@@ -317,13 +328,11 @@ export const createStealthScript = () => {
317
328
  getManifest: () => ({}),
318
329
  // Real Chrome extension IDs are 32 lowercase alpha chars (a-p, base16 with a-p)
319
330
  id: undefined,
320
- connect: () => ({
321
- name: '',
322
- disconnect: () => {},
323
- onDisconnect: { addListener: () => {}, removeListener: () => {} },
324
- onMessage: { addListener: () => {}, removeListener: () => {} },
325
- postMessage: () => {}
326
- }),
331
+ connect: function() {
332
+ // Real Chrome throws this exact error when no extension is receiving
333
+ // DataDome and PerimeterX specifically test this error message
334
+ throw new Error('Could not establish connection. Receiving end does not exist.');
335
+ },
327
336
  sendMessage: () => {},
328
337
  getURL: (path) => '',
329
338
  onConnect: { addListener: () => {}, removeListener: () => {} },
@@ -376,11 +385,17 @@ export const createStealthScript = () => {
376
385
  }
377
386
 
378
387
  // chrome.csi() - Chrome-specific, returns page load timing info
388
+ // Values are pre-computed from session seed so they're stable across calls.
389
+ // Real Chrome returns consistent timing per page load; Math.random() is detectable.
379
390
  if (window.chrome && !window.chrome.csi) {
391
+ const _csiRng = (_ss.createRNG ? _ss.createRNG(sessionSeed ^ 0x1001) : (() => { let x = sessionSeed ^ 0x1001; return () => { x = (x * 1664525 + 1013904223) >>> 0; return x / 4294967296; }; })());
392
+ const _csiLoadOffset = 500 + _csiRng() * 2000;
393
+ const _csiStartOffset = 1000 + _csiRng() * 3000;
380
394
  window.chrome.csi = function() {
395
+ const now = Date.now();
381
396
  return {
382
- onloadT: Date.now() - (Math.random() * 2000 + 500),
383
- startE: Date.now() - (Math.random() * 3000 + 1000),
397
+ onloadT: now - _csiLoadOffset,
398
+ startE: now - _csiStartOffset,
384
399
  pageT: performance.now(),
385
400
  tran: 15, // Normal navigation
386
401
  };
@@ -388,20 +403,30 @@ export const createStealthScript = () => {
388
403
  }
389
404
 
390
405
  // chrome.loadTimes() - Chrome-specific, returns load timing info
406
+ // Pre-computed offsets from session seed for stability across calls.
391
407
  if (window.chrome && !window.chrome.loadTimes) {
408
+ const _ltRng = (_ss.createRNG ? _ss.createRNG(sessionSeed ^ 0x1002) : (() => { let x = sessionSeed ^ 0x1002; return () => { x = (x * 1664525 + 1013904223) >>> 0; return x / 4294967296; }; })());
409
+ const _ltOffsets = {
410
+ commit: _ltRng() * 2,
411
+ finishDoc: _ltRng() * 1,
412
+ finishLoad: _ltRng() * 0.5,
413
+ firstPaint: _ltRng() * 1.5,
414
+ request: _ltRng() * 3,
415
+ startLoad: _ltRng() * 2.5,
416
+ };
392
417
  window.chrome.loadTimes = function() {
393
418
  const now = Date.now() / 1000;
394
419
  return {
395
- commitLoadTime: now - Math.random() * 2,
420
+ commitLoadTime: now - _ltOffsets.commit,
396
421
  connectionInfo: 'h2',
397
- finishDocumentLoadTime: now - Math.random(),
398
- finishLoadTime: now - Math.random() * 0.5,
422
+ finishDocumentLoadTime: now - _ltOffsets.finishDoc,
423
+ finishLoadTime: now - _ltOffsets.finishLoad,
399
424
  firstPaintAfterLoadTime: 0,
400
- firstPaintTime: now - Math.random() * 1.5,
425
+ firstPaintTime: now - _ltOffsets.firstPaint,
401
426
  navigationType: 'Other',
402
427
  npnNegotiatedProtocol: 'h2',
403
- requestTime: now - Math.random() * 3,
404
- startLoadTime: now - Math.random() * 2.5,
428
+ requestTime: now - _ltOffsets.request,
429
+ startLoadTime: now - _ltOffsets.startLoad,
405
430
  wasAlternateProtocolAvailable: false,
406
431
  wasFetchedViaSpdy: true,
407
432
  wasNpnNegotiated: true,
@@ -622,8 +647,10 @@ export const createStealthScript = () => {
622
647
  const originalGetGamepads = navigator.getGamepads;
623
648
  if (originalGetGamepads) {
624
649
  navigator.getGamepads = function() {
625
- // Return empty array like no gamepads connected
626
- return [];
650
+ // Real Chrome returns GamepadList with 4 null slots when no gamepads
651
+ // connected — NOT an empty array. [] vs [null,null,null,null] is a
652
+ // checked difference between headed Chrome and headless/Chromium.
653
+ return [null, null, null, null];
627
654
  };
628
655
  }
629
656
  };
@@ -922,10 +949,112 @@ export const createStealthScript = () => {
922
949
  if (_s5.utils) _s5.utils.registerNativeFunction(window.postMessage, 'postMessage');
923
950
  };
924
951
 
952
+ // 30. Document Visibility Spoofing
953
+ // hasFocus() and visibilityState were only patched inside datadome-bypass.ts,
954
+ // meaning Cloudflare / Akamai / PerimeterX saw raw headless values. Move them
955
+ // here so all crawls benefit.
956
+ const spoofDocumentVisibility = () => {
957
+ try {
958
+ Object.defineProperty(document, 'hidden', { get: () => false, configurable: true });
959
+ Object.defineProperty(document, 'visibilityState', { get: () => 'visible', configurable: true });
960
+ } catch (e) {}
961
+
962
+ document.hasFocus = function() { return true; };
963
+ try {
964
+ Object.defineProperty(document.hasFocus, 'toString', {
965
+ value: () => 'function hasFocus() { [native code] }',
966
+ configurable: true
967
+ });
968
+ } catch (e) {}
969
+
970
+ // Suppress CDP-lifecycle-driven visibilitychange events that expose headless state
971
+ const origAEL = document.addEventListener.bind(document);
972
+ const _hiddenEvtHandler = (e) => {
973
+ if (e.type === 'visibilitychange') { e.stopImmediatePropagation(); }
974
+ };
975
+ origAEL('visibilitychange', _hiddenEvtHandler, true);
976
+ };
977
+
978
+ // 31. Encrypted Media Extensions (Widevine) Spoofing
979
+ // Vanilla Chromium rejects requestMediaKeySystemAccess('com.widevine.alpha')
980
+ // with NotSupportedError. Real Chrome ships Widevine L3 and resolves.
981
+ // This is one of the most reliable Chrome-vs-Chromium signals (Cloudflare, FPjs, CreepJS).
982
+ const spoofEME = () => {
983
+ if (typeof navigator.requestMediaKeySystemAccess !== 'function') return;
984
+
985
+ const _origRMKSA = navigator.requestMediaKeySystemAccess.bind(navigator);
986
+
987
+ const _fakeRMKSA = function requestMediaKeySystemAccess(keySystem, configs) {
988
+ if (keySystem === 'com.widevine.alpha') {
989
+ const cfg = (Array.isArray(configs) && configs[0]) ? configs[0] : {};
990
+ const resolvedCfg = {
991
+ label: cfg.label || '',
992
+ initDataTypes: cfg.initDataTypes || ['cenc'],
993
+ audioCapabilities: cfg.audioCapabilities || [
994
+ { contentType: 'audio/mp4;codecs="mp4a.40.2"', robustness: '' }
995
+ ],
996
+ videoCapabilities: cfg.videoCapabilities || [
997
+ { contentType: 'video/mp4;codecs="avc1.42E01E"', robustness: '' }
998
+ ],
999
+ distinctiveIdentifier: 'not-allowed',
1000
+ persistentState: 'not-allowed',
1001
+ sessionTypes: ['temporary']
1002
+ };
1003
+
1004
+ const fakeMKS = {
1005
+ setServerCertificate: () => Promise.resolve(true),
1006
+ createSession: function(sessionType) {
1007
+ const sess = {
1008
+ sessionId: '',
1009
+ expiration: NaN,
1010
+ closed: new Promise(() => {}),
1011
+ keyStatuses: new Map(),
1012
+ onkeystatuseschange: null,
1013
+ onmessage: null,
1014
+ generateRequest: () => Promise.reject(new DOMException('InvalidStateError', 'InvalidStateError')),
1015
+ load: () => Promise.resolve(false),
1016
+ update: () => Promise.reject(new DOMException('InvalidStateError', 'InvalidStateError')),
1017
+ close: () => Promise.resolve(),
1018
+ remove: () => Promise.reject(new DOMException('InvalidStateError', 'InvalidStateError')),
1019
+ addEventListener: () => {},
1020
+ removeEventListener: () => {},
1021
+ dispatchEvent: () => true
1022
+ };
1023
+ return sess;
1024
+ }
1025
+ };
1026
+
1027
+ const fakeMKSA = {
1028
+ keySystem: 'com.widevine.alpha',
1029
+ getConfiguration: () => resolvedCfg,
1030
+ createMediaKeys: () => Promise.resolve(fakeMKS)
1031
+ };
1032
+
1033
+ return Promise.resolve(fakeMKSA);
1034
+ }
1035
+ // All other key systems fall through to native
1036
+ try { return _origRMKSA(keySystem, configs); }
1037
+ catch (e) { return Promise.reject(e); }
1038
+ };
1039
+
1040
+ // Override on both Navigator.prototype and the instance
1041
+ try {
1042
+ Object.defineProperty(Navigator.prototype, 'requestMediaKeySystemAccess', {
1043
+ value: _fakeRMKSA, writable: true, configurable: true
1044
+ });
1045
+ } catch (e) {
1046
+ try { navigator.requestMediaKeySystemAccess = _fakeRMKSA; } catch (e2) {}
1047
+ }
1048
+
1049
+ // Register for native-code toString masking
1050
+ const _s6 = typeof __stealth !== 'undefined' ? __stealth : {};
1051
+ if (_s6.utils) _s6.utils.registerNativeFunction(_fakeRMKSA, 'requestMediaKeySystemAccess');
1052
+ };
1053
+
925
1054
  // Initialize all protections
926
1055
  const DEBUG_PREFIX = '[CDP-FP-DEBUG]';
927
1056
  const ERROR_PREFIX = '[CDP-FP-ERROR]';
928
-
1057
+
929
1058
  console.log(DEBUG_PREFIX, 'Starting stealth protection injection...');
930
1059
 
931
1060
  const applyProtection = (name, fn) => {
@@ -972,7 +1101,10 @@ export const createStealthScript = () => {
972
1101
  applyProtection('Worker Constructor Protection', protectWorkerConstructor);
973
1102
  applyProtection('SharedWorker Protection', protectSharedWorkerConstructor);
974
1103
  applyProtection('PostMessage Protection', protectPostMessage);
975
-
1104
+ // Chrome authenticity patches — make Chromium look like real Chrome
1105
+ applyProtection('Document Visibility Spoofing', spoofDocumentVisibility);
1106
+ applyProtection('EME/Widevine Spoofing', spoofEME);
1107
+
976
1108
  console.log(DEBUG_PREFIX, '✓ All stealth protections applied successfully');
977
1109
  } catch (e) {
978
1110
  console.error(ERROR_PREFIX, '✗ Failed to apply stealth protections:', e);
@@ -1 +1 @@
1
- {"version":3,"file":"stealth-script.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/stealth-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAW,EAAE;IAC5C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAu8BL,CAAC;AACP,CAAC,CAAC"}
1
+ {"version":3,"file":"stealth-script.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/stealth-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAW,EAAE;IAC5C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2kCL,CAAC;AACP,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage-consistency.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/storage-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,8BAA8B,QAAO,MA6UjD,CAAC"}
1
+ {"version":3,"file":"storage-consistency.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/storage-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,8BAA8B,QAAO,MA+UjD,CAAC"}
@@ -18,14 +18,16 @@ export const createStorageConsistencyScript = () => {
18
18
  const spoofStorageAPIs = () => {
19
19
  const platform = navigator.platform || 'Win32';
20
20
 
21
- // Generate consistent seed for stable values
22
- const generateSeed = () => {
23
- const ua = navigator.userAgent || '';
24
- const screen = window.screen;
25
- return (ua.length * 17 + (screen.width || 0) * 31 + (screen.height || 0) * 13) % 1000000;
26
- };
27
-
28
- const sessionSeed = generateSeed();
21
+ // Use centralized stable hash (set up by utils.ts before this module runs).
22
+ const _ss = typeof __stealth !== 'undefined' ? __stealth : {};
23
+ const sessionSeed = (_ss.stableHash
24
+ ? _ss.stableHash(0xCAFE9002)
25
+ : (() => {
26
+ const ua = navigator.userAgent || '';
27
+ const s = window.screen;
28
+ return (ua.length * 17 + (s.width || 0) * 31 + (s.height || 0) * 13) % 1000000;
29
+ })()
30
+ );
29
31
 
30
32
  // Seeded PRNG (mulberry32) for consistent values
31
33
  const createSeededRNG = (seed) => {
@@ -1 +1 @@
1
- {"version":3,"file":"storage-consistency.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/storage-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAW,EAAE;IACvD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2UL,CAAC;AACP,CAAC,CAAC"}
1
+ {"version":3,"file":"storage-consistency.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/storage-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAW,EAAE;IACvD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA6UL,CAAC;AACP,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"timing-consistency.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/timing-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,6BAA6B,QAAO,MA2PhD,CAAC"}
1
+ {"version":3,"file":"timing-consistency.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/timing-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,6BAA6B,QAAO,MA6PhD,CAAC"}
@@ -24,13 +24,15 @@ export const createTimingConsistencyScript = () => {
24
24
  const originalDateNow = Date.now;
25
25
  const originalPerformanceNow = performance.now.bind(performance);
26
26
 
27
- // Generate session seed for consistent variations
28
- const generateSeed = () => {
29
- const ua = navigator.userAgent || '';
30
- return ua.length * 17 + (screen.width || 0) * 31;
31
- };
32
-
33
- const sessionSeed = generateSeed();
27
+ // Use centralized stable hash (set up by utils.ts before this module runs).
28
+ const _ss = typeof __stealth !== 'undefined' ? __stealth : {};
29
+ const sessionSeed = (_ss.stableHash
30
+ ? _ss.stableHash(0xCAFE9003)
31
+ : (() => {
32
+ const ua = navigator.userAgent || '';
33
+ return ua.length * 17 + (screen.width || 0) * 31;
34
+ })()
35
+ );
34
36
 
35
37
  // Seeded PRNG (mulberry32) for consistent values
36
38
  const seededRandom = (seed) => {
@@ -1 +1 @@
1
- {"version":3,"file":"timing-consistency.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/timing-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAW,EAAE;IACtD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAyPL,CAAC;AACP,CAAC,CAAC"}
1
+ {"version":3,"file":"timing-consistency.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/timing-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAW,EAAE;IACtD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2PL,CAAC;AACP,CAAC,CAAC"}
@@ -132,24 +132,24 @@ export const createUAClientHintsSpoofingScript = (platform = 'Win32', generatedU
132
132
  getHighEntropyValues: {
133
133
  value: function(hints) {
134
134
  return new Promise((resolve) => {
135
- // Simulate slight async delay like real browser
136
- setTimeout(() => {
135
+ // Real Chrome resolves getHighEntropyValues via IPC microtask, not a random setTimeout
136
+ Promise.resolve().then(() => {
137
137
  const result = {};
138
-
138
+
139
139
  if (!hints || !Array.isArray(hints)) {
140
140
  resolve(result);
141
141
  return;
142
142
  }
143
-
143
+
144
144
  // Return requested hints
145
145
  for (const hint of hints) {
146
146
  if (hint in highEntropyValues) {
147
147
  result[hint] = highEntropyValues[hint];
148
148
  }
149
149
  }
150
-
150
+
151
151
  resolve(result);
152
- }, 1 + Math.random() * 2);
152
+ });
153
153
  });
154
154
  },
155
155
  writable: false,
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,eAAO,MAAM,wBAAwB,QAAO,MAyf3C,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,eAAO,MAAM,wBAAwB,QAAO,MAoiB3C,CAAC"}
@@ -491,7 +491,50 @@ export const createStealthUtilsScript = () => {
491
491
 
492
492
  // Initialize toString patch immediately
493
493
  patchToString();
494
-
494
+
495
+ // ============================================
496
+ // SHARED SEED UTILITIES
497
+ // Exposed via __stealth so all override modules
498
+ // use the same deterministic hash instead of
499
+ // duplicating _stableHash in every file.
500
+ // ============================================
501
+
502
+ /**
503
+ * Deterministic hash that incorporates __stealth.seedKey + UA + screen.
504
+ * Every override module should call _s.stableHash(uniqueSalt) for its seed.
505
+ */
506
+ const _stableHashFn = (salt) => {
507
+ const key = _s.seedKey || '';
508
+ const ua = (typeof navigator !== 'undefined' && navigator.userAgent) || '';
509
+ const sw = (typeof screen !== 'undefined' && screen.width) || 0;
510
+ const sh = (typeof screen !== 'undefined' && screen.height) || 0;
511
+ const cd = (typeof screen !== 'undefined' && screen.colorDepth) || 0;
512
+ let h = salt | 0;
513
+ for (let i = 0; i < key.length; i++) h = (h << 5) - h + key.charCodeAt(i) | 0;
514
+ for (let i = 0; i < ua.length; i++) h = (h << 5) - h + ua.charCodeAt(i) | 0;
515
+ h = (h << 5) - h + sw | 0;
516
+ h = (h << 5) - h + sh | 0;
517
+ h = (h << 5) - h + cd | 0;
518
+ return h >>> 0;
519
+ };
520
+
521
+ /**
522
+ * Seeded PRNG factory (mulberry32).
523
+ * Usage: const rng = _s.createRNG(seed); rng() -> [0, 1)
524
+ */
525
+ const _createRNGFn = (seed) => {
526
+ let s = seed | 0;
527
+ return () => {
528
+ s = s + 0x6D2B79F5 | 0;
529
+ let t = Math.imul(s ^ s >>> 15, 1 | s);
530
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
531
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
532
+ };
533
+ };
534
+
535
+ _s.stableHash = _stableHashFn;
536
+ _s.createRNG = _createRNGFn;
537
+
495
538
  // Export utilities via shared stealth store (not on window - avoids detection)
496
539
  _s.utils = {
497
540
  makeNativeString,
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAW,EAAE;IACjD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAufV,CAAC;AACF,CAAC,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAW,EAAE;IACjD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkiBV,CAAC;AACF,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"webgl-spoofing.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webgl-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,yBAAyB,sBAAuB,WAAW,KAAG,MA8N1E,CAAC"}
1
+ {"version":3,"file":"webgl-spoofing.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webgl-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,yBAAyB,sBAAuB,WAAW,KAAG,MAwQ1E,CAAC"}
@@ -109,7 +109,12 @@ export const createWebGLSpoofingScript = (fingerprintWebGL) => {
109
109
 
110
110
  console.log('[CDP-FP-DEBUG] WebGL using platform:', platform, '- Vendor:', selectedVendor, 'Renderer:', selectedRenderer.substring(0, 60) + '...');
111
111
  `}
112
-
112
+
113
+ // Store selected GPU info on __stealth for cross-API consistency (WebGPU reads this)
114
+ if (typeof __stealth !== 'undefined') {
115
+ __stealth.webglRenderer = selectedRenderer;
116
+ }
117
+
113
118
  // Override getParameter
114
119
  WebGLRenderingContext.prototype.getParameter = function(param) {
115
120
  // UNMASKED_VENDOR_WEBGL
@@ -154,6 +159,43 @@ export const createWebGLSpoofingScript = (fingerprintWebGL) => {
154
159
  };
155
160
  }
156
161
 
162
+ // Override getShaderPrecisionFormat to prevent GPU cross-referencing.
163
+ // Anti-bot scripts can compare precision values against the claimed GPU/platform.
164
+ // These values match the standard IEEE 754 precision formats reported by modern
165
+ // D3D11/Metal/Vulkan drivers — consistent across NVIDIA, AMD, and Intel GPUs.
166
+ const _shaderPrecision = {
167
+ 35633: { // VERTEX_SHADER
168
+ 36336: { rangeMin: 1, rangeMax: 1, precision: 8 }, // LOW_FLOAT
169
+ 36337: { rangeMin: 14, rangeMax: 14, precision: 10 }, // MEDIUM_FLOAT
170
+ 36338: { rangeMin: 127, rangeMax: 127, precision: 23 }, // HIGH_FLOAT
171
+ 36339: { rangeMin: 8, rangeMax: 7, precision: 0 }, // LOW_INT
172
+ 36340: { rangeMin: 15, rangeMax: 14, precision: 0 }, // MEDIUM_INT
173
+ 36341: { rangeMin: 31, rangeMax: 30, precision: 0 }, // HIGH_INT
174
+ },
175
+ 35632: { // FRAGMENT_SHADER
176
+ 36336: { rangeMin: 1, rangeMax: 1, precision: 8 },
177
+ 36337: { rangeMin: 14, rangeMax: 14, precision: 10 },
178
+ 36338: { rangeMin: 127, rangeMax: 127, precision: 23 },
179
+ 36339: { rangeMin: 8, rangeMax: 7, precision: 0 },
180
+ 36340: { rangeMin: 15, rangeMax: 14, precision: 0 },
181
+ 36341: { rangeMin: 31, rangeMax: 30, precision: 0 },
182
+ },
183
+ };
184
+ const _origGetShaderPrecisionFormat = WebGLRenderingContext.prototype.getShaderPrecisionFormat;
185
+ WebGLRenderingContext.prototype.getShaderPrecisionFormat = function(shaderType, precisionType) {
186
+ const shaderFmts = _shaderPrecision[shaderType];
187
+ const fmt = shaderFmts && shaderFmts[precisionType];
188
+ if (fmt) {
189
+ // Return a plain object that mirrors WebGLShaderPrecisionFormat fields.
190
+ // Anti-bot scripts read .rangeMin/.rangeMax/.precision — instanceof is not checked.
191
+ return { rangeMin: fmt.rangeMin, rangeMax: fmt.rangeMax, precision: fmt.precision };
192
+ }
193
+ return _origGetShaderPrecisionFormat.apply(this, arguments);
194
+ };
195
+ if (typeof WebGL2RenderingContext !== 'undefined') {
196
+ WebGL2RenderingContext.prototype.getShaderPrecisionFormat = WebGLRenderingContext.prototype.getShaderPrecisionFormat;
197
+ }
198
+
157
199
  // Override getSupportedExtensions with platform-appropriate extensions
158
200
  const baseExtensions = [
159
201
  'ANGLE_instanced_arrays', 'EXT_blend_minmax', 'EXT_color_buffer_half_float',
@@ -1 +1 @@
1
- {"version":3,"file":"webgl-spoofing.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webgl-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,gBAA8B,EAAU,EAAE;IAChF,iFAAiF;IACjF,MAAM,cAAc,GAAG,gBAAgB,IAAI,CAAC,gBAAgB,CAAC,cAAc,IAAI,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;IAElH,OAAO;;;;;;;;;;UAUD,cAAc,CAAC,CAAC,CAAC;;oCAES,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC;;;;SAI3D,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAuFH;;;;;;;;;;;;;;yBAcgB,cAAc,IAAI,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,UAAU;;;yBAGxF,cAAc,IAAI,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,gBAAgB,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA2CjH,CAAC,cAAc,CAAC,CAAC,CAAC;;;;;;;;;SASnB,CAAC,CAAC,CAAC;;SAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2CH,CAAC;AACP,CAAC,CAAC"}
1
+ {"version":3,"file":"webgl-spoofing.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webgl-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,gBAA8B,EAAU,EAAE;IAChF,iFAAiF;IACjF,MAAM,cAAc,GAAG,gBAAgB,IAAI,CAAC,gBAAgB,CAAC,cAAc,IAAI,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;IAElH,OAAO;;;;;;;;;;UAUD,cAAc,CAAC,CAAC,CAAC;;oCAES,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC;;;;SAI3D,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;SAuFH;;;;;;;;;;;;;;;;;;;yBAmBgB,cAAc,IAAI,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,UAAU;;;yBAGxF,cAAc,IAAI,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,gBAAgB,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAgFjH,CAAC,cAAc,CAAC,CAAC,CAAC;;;;;;;;;SASnB,CAAC,CAAC,CAAC;;SAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA2CH,CAAC;AACP,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"webgpu-spoofing.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webgpu-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,0BAA0B,kCAA+B,MAkNrE,CAAC"}
1
+ {"version":3,"file":"webgpu-spoofing.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webgpu-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,0BAA0B,kCAA+B,MA0NrE,CAAC"}
@@ -64,7 +64,15 @@ export const createWebGPUSpoofingScript = (experimentalMode = false) => {
64
64
  return new Proxy(adapter, {
65
65
  get(adapterTarget, adapterProp) {
66
66
  if (adapterProp === 'name') {
67
- // Return a common GPU name based on platform
67
+ // Derive GPU name from WebGL renderer for cross-API consistency.
68
+ // webgl-spoofing.ts stores the selected renderer on __stealth.webglRenderer.
69
+ const _wglR = typeof __stealth !== 'undefined' && __stealth.webglRenderer;
70
+ if (_wglR) {
71
+ // Extract from "ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Direct3D11 ...)"
72
+ const _m = _wglR.match(/ANGLE \\(\\w+, ([^,]+?)(?:\\s+Direct3D|\\s+OpenGL|,)/);
73
+ if (_m) return _m[1].trim();
74
+ }
75
+ // Fallback: seeded pick from list
68
76
  const gpuNames = [
69
77
  'NVIDIA GeForce RTX 4060',
70
78
  'NVIDIA GeForce RTX 3060',
@@ -1 +1 @@
1
- {"version":3,"file":"webgpu-spoofing.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webgpu-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,gBAAgB,GAAG,KAAK,EAAU,EAAE;IAC3E,OAAO;;;;;;;UAOD,gBAAgB,CAAC,CAAC,CAAC;;;;;;;;;SASpB,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAgMR,CAAC;AACP,CAAC,CAAC"}
1
+ {"version":3,"file":"webgpu-spoofing.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webgpu-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,CAAC,gBAAgB,GAAG,KAAK,EAAU,EAAE;IAC3E,OAAO;;;;;;;UAOD,gBAAgB,CAAC,CAAC,CAAC;;;;;;;;;SASpB,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAwMR,CAAC;AACP,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"webrtc-spoofing.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webrtc-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,0BAA0B,QAAO,MAiM7C,CAAC;AAEF,eAAO,MAAM,yBAAyB,QAAO,MAgC5C,CAAC"}
1
+ {"version":3,"file":"webrtc-spoofing.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webrtc-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,0BAA0B,QAAO,MA4M7C,CAAC;AAEF,eAAO,MAAM,yBAAyB,QAAO,MAgC5C,CAAC"}
@@ -159,9 +159,20 @@ export const createWebRTCSpoofingScript = () => {
159
159
  if (cachedDeviceList) return Promise.resolve(cachedDeviceList);
160
160
 
161
161
  return originalEnumerateDevices.apply(this, arguments).then(devices => {
162
- // Replace device IDs with crypto-random ones, keep real device kinds/count
163
- // This preserves the natural device count from the actual browser
164
- // while preventing tracking via device IDs
162
+ // If the platform returns no devices (headless/server/CI), inject
163
+ // plausible fake devices so fingerprinters don't flag an empty list.
164
+ // A real desktop Chrome always has at least audioinput + audiooutput.
165
+ if (devices.length === 0) {
166
+ devices = [
167
+ { kind: 'audioinput', label: '', deviceId: 'default', groupId: 'default' },
168
+ { kind: 'audiooutput', label: '', deviceId: 'default', groupId: 'default' },
169
+ { kind: 'audioinput', label: '', deviceId: '', groupId: '' },
170
+ { kind: 'audiooutput', label: '', deviceId: '', groupId: '' },
171
+ ];
172
+ }
173
+
174
+ // Replace device IDs with deterministic session-keyed ones,
175
+ // keeping the real device count so repeated calls are consistent.
165
176
  const groupIds = {};
166
177
  cachedDeviceList = devices.map((device, index) => {
167
178
  const groupKey = device.kind.replace(/input|output/, '');
@@ -1 +1 @@
1
- {"version":3,"file":"webrtc-spoofing.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webrtc-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAW,EAAE;IACnD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA+LL,CAAC;AACP,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAW,EAAE;IAClD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA8BL,CAAC;AACP,CAAC,CAAC"}
1
+ {"version":3,"file":"webrtc-spoofing.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/webrtc-spoofing.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAW,EAAE;IACnD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA0ML,CAAC;AACP,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAW,EAAE;IAClD,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA8BL,CAAC;AACP,CAAC,CAAC"}