jumpy-lion 0.0.41 → 0.0.43

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 (127) hide show
  1. package/dist/browser-controller.d.ts.map +1 -1
  2. package/dist/browser-controller.js +102 -16
  3. package/dist/browser-controller.js.map +1 -1
  4. package/dist/browser-plugin.d.ts +20 -1
  5. package/dist/browser-plugin.d.ts.map +1 -1
  6. package/dist/browser-plugin.js +21 -1
  7. package/dist/browser-plugin.js.map +1 -1
  8. package/dist/browser-process/browser.d.ts +22 -1
  9. package/dist/browser-process/browser.d.ts.map +1 -1
  10. package/dist/browser-process/browser.js +77 -5
  11. package/dist/browser-process/browser.js.map +1 -1
  12. package/dist/browser-profiles/chrome/default.d.ts +116 -0
  13. package/dist/browser-profiles/chrome/default.d.ts.map +1 -1
  14. package/dist/browser-profiles/chrome/default.js +118 -1
  15. package/dist/browser-profiles/chrome/default.js.map +1 -1
  16. package/dist/browser-profiles/chrome/populate-profile.d.ts +76 -0
  17. package/dist/browser-profiles/chrome/populate-profile.d.ts.map +1 -0
  18. package/dist/browser-profiles/chrome/populate-profile.js +300 -0
  19. package/dist/browser-profiles/chrome/populate-profile.js.map +1 -0
  20. package/dist/browser-profiles/index.d.ts +1 -0
  21. package/dist/browser-profiles/index.d.ts.map +1 -1
  22. package/dist/browser-profiles/index.js +2 -0
  23. package/dist/browser-profiles/index.js.map +1 -1
  24. package/dist/crawler.d.ts +32 -1
  25. package/dist/crawler.d.ts.map +1 -1
  26. package/dist/crawler.js +7 -0
  27. package/dist/crawler.js.map +1 -1
  28. package/dist/fingerprinting/custom-fingerprint-injector.d.ts +87 -0
  29. package/dist/fingerprinting/custom-fingerprint-injector.d.ts.map +1 -0
  30. package/dist/fingerprinting/custom-fingerprint-injector.js +342 -0
  31. package/dist/fingerprinting/custom-fingerprint-injector.js.map +1 -0
  32. package/dist/fingerprinting/fingerprint-injector.d.ts +40 -2
  33. package/dist/fingerprinting/fingerprint-injector.d.ts.map +1 -1
  34. package/dist/fingerprinting/fingerprint-injector.js +452 -44
  35. package/dist/fingerprinting/fingerprint-injector.js.map +1 -1
  36. package/dist/fingerprinting/fingerprint-overrides/audio-spoofing.d.ts.map +1 -1
  37. package/dist/fingerprinting/fingerprint-overrides/audio-spoofing.js +11 -1
  38. package/dist/fingerprinting/fingerprint-overrides/audio-spoofing.js.map +1 -1
  39. package/dist/fingerprinting/fingerprint-overrides/canvas-protection.d.ts.map +1 -1
  40. package/dist/fingerprinting/fingerprint-overrides/canvas-protection.js +11 -1
  41. package/dist/fingerprinting/fingerprint-overrides/canvas-protection.js.map +1 -1
  42. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.d.ts +14 -0
  43. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.d.ts.map +1 -0
  44. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.js +776 -0
  45. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.js.map +1 -0
  46. package/dist/fingerprinting/fingerprint-overrides/client-rect-spoofing.d.ts.map +1 -1
  47. package/dist/fingerprinting/fingerprint-overrides/client-rect-spoofing.js +11 -1
  48. package/dist/fingerprinting/fingerprint-overrides/client-rect-spoofing.js.map +1 -1
  49. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts +14 -0
  50. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts.map +1 -0
  51. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js +643 -0
  52. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js.map +1 -0
  53. package/dist/fingerprinting/fingerprint-overrides/font-spoofing.d.ts.map +1 -1
  54. package/dist/fingerprinting/fingerprint-overrides/font-spoofing.js +11 -1
  55. package/dist/fingerprinting/fingerprint-overrides/font-spoofing.js.map +1 -1
  56. package/dist/fingerprinting/fingerprint-overrides/index.d.ts +17 -1
  57. package/dist/fingerprinting/fingerprint-overrides/index.d.ts.map +1 -1
  58. package/dist/fingerprinting/fingerprint-overrides/index.js +21 -1
  59. package/dist/fingerprinting/fingerprint-overrides/index.js.map +1 -1
  60. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.d.ts +45 -0
  61. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.d.ts.map +1 -0
  62. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.js +291 -0
  63. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.js.map +1 -0
  64. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.d.ts.map +1 -1
  65. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js +153 -90
  66. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js.map +1 -1
  67. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.d.ts.map +1 -1
  68. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.js +4 -5
  69. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.js.map +1 -1
  70. package/dist/fingerprinting/fingerprint-overrides/performance-spoofing.d.ts.map +1 -1
  71. package/dist/fingerprinting/fingerprint-overrides/performance-spoofing.js +11 -1
  72. package/dist/fingerprinting/fingerprint-overrides/performance-spoofing.js.map +1 -1
  73. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.d.ts +13 -0
  74. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.d.ts.map +1 -1
  75. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js +413 -70
  76. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js.map +1 -1
  77. package/dist/fingerprinting/fingerprint-overrides/prototype-integrity.d.ts +13 -0
  78. package/dist/fingerprinting/fingerprint-overrides/prototype-integrity.d.ts.map +1 -0
  79. package/dist/fingerprinting/fingerprint-overrides/prototype-integrity.js +355 -0
  80. package/dist/fingerprinting/fingerprint-overrides/prototype-integrity.js.map +1 -0
  81. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.d.ts +12 -3
  82. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.d.ts.map +1 -1
  83. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.js +261 -71
  84. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.js.map +1 -1
  85. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.d.ts +55 -0
  86. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.d.ts.map +1 -0
  87. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.js +380 -0
  88. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.js.map +1 -0
  89. package/dist/fingerprinting/fingerprint-overrides/stealth-script.d.ts +8 -0
  90. package/dist/fingerprinting/fingerprint-overrides/stealth-script.d.ts.map +1 -1
  91. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js +756 -71
  92. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js.map +1 -1
  93. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.d.ts +13 -0
  94. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.d.ts.map +1 -0
  95. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.js +368 -0
  96. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.js.map +1 -0
  97. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.d.ts +13 -0
  98. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.d.ts.map +1 -0
  99. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.js +438 -0
  100. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.js.map +1 -0
  101. package/dist/fingerprinting/fingerprint-overrides/ua-ch.d.ts +7 -1
  102. package/dist/fingerprinting/fingerprint-overrides/ua-ch.d.ts.map +1 -1
  103. package/dist/fingerprinting/fingerprint-overrides/ua-ch.js +158 -58
  104. package/dist/fingerprinting/fingerprint-overrides/ua-ch.js.map +1 -1
  105. package/dist/fingerprinting/fingerprint-overrides/utils.d.ts +12 -0
  106. package/dist/fingerprinting/fingerprint-overrides/utils.d.ts.map +1 -0
  107. package/dist/fingerprinting/fingerprint-overrides/utils.js +517 -0
  108. package/dist/fingerprinting/fingerprint-overrides/utils.js.map +1 -0
  109. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.d.ts.map +1 -1
  110. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js +51 -10
  111. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js.map +1 -1
  112. package/dist/fingerprinting/fingerprint-overrides/webgpu-spoofing.d.ts.map +1 -1
  113. package/dist/fingerprinting/fingerprint-overrides/webgpu-spoofing.js +11 -1
  114. package/dist/fingerprinting/fingerprint-overrides/webgpu-spoofing.js.map +1 -1
  115. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.d.ts.map +1 -1
  116. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.js +11 -1
  117. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.js.map +1 -1
  118. package/dist/page.d.ts +12 -0
  119. package/dist/page.d.ts.map +1 -1
  120. package/dist/page.js +35 -3
  121. package/dist/page.js.map +1 -1
  122. package/dist/tsconfig.build.tsbuildinfo +1 -1
  123. package/package.json +4 -4
  124. package/dist/fingerprinting/canvas-fingerprint.d.ts +0 -4
  125. package/dist/fingerprinting/canvas-fingerprint.d.ts.map +0 -1
  126. package/dist/fingerprinting/canvas-fingerprint.js +0 -60
  127. package/dist/fingerprinting/canvas-fingerprint.js.map +0 -1
@@ -1,13 +1,21 @@
1
1
  /**
2
2
  * Base stealth script for hiding automation indicators
3
3
  * Includes error stack hiding, console patching, and automation flags removal
4
+ *
5
+ * 2024-2025 Enhancements:
6
+ * - deviceMemory spoofing
7
+ * - pdfViewerEnabled consistency
8
+ * - Notification.permission handling
9
+ * - Bluetooth/USB/Serial API masking
10
+ * - Speech synthesis voice spoofing
11
+ * - Credentials API consistency
4
12
  */
5
13
  export const createStealthScript = () => {
6
14
  return `
7
15
  (() => {
8
16
  'use strict';
9
17
 
10
- // Enhanced stealth script for 2025 - July
18
+ // Enhanced stealth script for 2025 - December
11
19
 
12
20
  // Helper functions
13
21
  const wrapNative = (fnName) => {
@@ -24,6 +32,42 @@ export const createStealthScript = () => {
24
32
  }
25
33
  });
26
34
  };
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();
45
+
46
+ // Helper to safely define property with guards
47
+ const safeDefineProperty = (obj, prop, descriptor) => {
48
+ try {
49
+ const existing = Object.getOwnPropertyDescriptor(obj, prop);
50
+ if (existing && existing.configurable === false) {
51
+ return false; // Cannot redefine
52
+ }
53
+ // Always use configurable: true to allow other scripts to modify
54
+ Object.defineProperty(obj, prop, {
55
+ ...descriptor,
56
+ configurable: true
57
+ });
58
+ return true;
59
+ } catch (e) {
60
+ return false;
61
+ }
62
+ };
63
+
64
+ // Helper to safely define getter property
65
+ const safeDefineGetter = (obj, prop, getter, enumerable = true) => {
66
+ return safeDefineProperty(obj, prop, {
67
+ get: getter,
68
+ enumerable: enumerable
69
+ });
70
+ };
27
71
 
28
72
  // 1. Enhanced Error Stack Hiding (2025)
29
73
  const hideErrorStack = () => {
@@ -98,9 +142,8 @@ export const createStealthScript = () => {
98
142
  });
99
143
 
100
144
  try {
101
- Object.defineProperty(window, 'console', {
145
+ safeDefineProperty(window, 'console', {
102
146
  value: consoleProxy,
103
- configurable: false,
104
147
  writable: false,
105
148
  enumerable: true
106
149
  });
@@ -112,12 +155,9 @@ export const createStealthScript = () => {
112
155
 
113
156
  // 3. WebDriver and Automation Flags Removal (2025)
114
157
  const removeAutomationFlags = () => {
115
- // Remove webdriver
158
+ // Remove webdriver (with guard)
116
159
  if (navigator.webdriver) {
117
- Object.defineProperty(navigator, 'webdriver', {
118
- get: () => undefined,
119
- configurable: false
120
- });
160
+ safeDefineGetter(navigator, 'webdriver', () => undefined, false);
121
161
  }
122
162
 
123
163
  // Remove automation indicators
@@ -143,17 +183,16 @@ export const createStealthScript = () => {
143
183
  } catch (e) {}
144
184
  });
145
185
 
146
- // Remove CDP specific properties
186
+ // Remove CDP specific properties (with guard)
147
187
  if (window.chrome) {
148
188
  const originalChrome = window.chrome;
149
- Object.defineProperty(window, 'chrome', {
150
- get() {
189
+ safeDefineGetter(window, 'chrome', () => {
190
+ try {
151
191
  if (new Error().stack.includes('evaluateOnNewDocument')) {
152
192
  return undefined;
153
193
  }
154
- return originalChrome;
155
- },
156
- configurable: false
194
+ } catch (e) {}
195
+ return originalChrome;
157
196
  });
158
197
  }
159
198
  };
@@ -178,7 +217,7 @@ export const createStealthScript = () => {
178
217
 
179
218
  // Patch Error constructor to prevent stack trace manipulation
180
219
  const OriginalError = Error;
181
- window.Error = new Proxy(OriginalError, {
220
+ const ErrorProxy = new Proxy(OriginalError, {
182
221
  construct(target, args) {
183
222
  const error = Reflect.construct(target, args);
184
223
 
@@ -194,9 +233,35 @@ export const createStealthScript = () => {
194
233
  });
195
234
 
196
235
  return error;
236
+ },
237
+ get(target, prop) {
238
+ // Return the original prototype when accessing .prototype
239
+ if (prop === 'prototype') {
240
+ return OriginalError.prototype;
241
+ }
242
+ return Reflect.get(target, prop);
243
+ },
244
+ set(target, prop, value) {
245
+ // Prevent setting prototype or other frozen properties
246
+ if (prop === 'prototype') {
247
+ return true; // Silently ignore
248
+ }
249
+ return Reflect.set(target, prop, value);
197
250
  }
198
251
  });
199
- window.Error.prototype = OriginalError.prototype;
252
+
253
+ // Use defineProperty to replace Error without modifying frozen prototype
254
+ try {
255
+ Object.defineProperty(window, 'Error', {
256
+ value: ErrorProxy,
257
+ writable: true,
258
+ enumerable: false,
259
+ configurable: true
260
+ });
261
+ } catch (e) {
262
+ // If we can't redefine, just assign
263
+ window.Error = ErrorProxy;
264
+ }
200
265
  };
201
266
 
202
267
  // 5. Plugin and MimeType Spoofing (2025)
@@ -237,62 +302,58 @@ export const createStealthScript = () => {
237
302
  }
238
303
  ];
239
304
 
240
- // Create fake plugins
305
+ // Create fake plugins using Object.defineProperty for read-only properties
241
306
  const fakePlugins = pluginData.map((p, index) => {
242
307
  const plugin = Object.create(Plugin.prototype);
243
- plugin.name = p.name;
244
- plugin.filename = p.filename;
245
- plugin.description = p.description;
246
- plugin.length = 1;
308
+ Object.defineProperty(plugin, 'name', { value: p.name, writable: false, enumerable: true });
309
+ Object.defineProperty(plugin, 'filename', { value: p.filename, writable: false, enumerable: true });
310
+ Object.defineProperty(plugin, 'description', { value: p.description, writable: false, enumerable: true });
311
+ Object.defineProperty(plugin, 'length', { value: 1, writable: false, enumerable: true });
247
312
  plugin[0] = mimeData[index] || mimeData[0];
248
313
  return plugin;
249
314
  });
250
315
 
251
- // Create fake mimeTypes
316
+ // Create fake mimeTypes using Object.defineProperty for read-only properties
252
317
  const fakeMimeTypes = mimeData.map((m, index) => {
253
318
  const mimeType = Object.create(MimeType.prototype);
254
- mimeType.type = m.type;
255
- mimeType.suffixes = m.suffixes;
256
- mimeType.description = m.description;
257
- mimeType.enabledPlugin = fakePlugins[0];
319
+ Object.defineProperty(mimeType, 'type', { value: m.type, writable: false, enumerable: true });
320
+ Object.defineProperty(mimeType, 'suffixes', { value: m.suffixes, writable: false, enumerable: true });
321
+ Object.defineProperty(mimeType, 'description', { value: m.description, writable: false, enumerable: true });
322
+ Object.defineProperty(mimeType, 'enabledPlugin', { value: fakePlugins[0], writable: false, enumerable: true });
258
323
  return mimeType;
259
324
  });
260
325
 
261
- // Override navigator.plugins
326
+ // Override navigator.plugins (with guard)
262
327
  try {
263
- Object.defineProperty(navigator, 'plugins', {
264
- get: () => {
265
- const arr = Object.create(PluginArray.prototype);
266
- fakePlugins.forEach((p, i) => {
267
- arr[i] = p;
268
- arr[p.name] = p;
269
- });
270
- arr.length = fakePlugins.length;
271
- arr.item = (index) => arr[index] || null;
272
- arr.namedItem = (name) => arr[name] || null;
273
- arr.refresh = () => {};
274
- return arr;
275
- },
276
- configurable: false,
277
- enumerable: true
278
- });
328
+ const pluginsGetter = () => {
329
+ const arr = Object.create(PluginArray.prototype);
330
+ fakePlugins.forEach((p, i) => {
331
+ arr[i] = p;
332
+ arr[p.name] = p;
333
+ });
334
+ // Use Object.defineProperty for read-only properties
335
+ Object.defineProperty(arr, 'length', { value: fakePlugins.length, writable: false, enumerable: true });
336
+ Object.defineProperty(arr, 'item', { value: (index) => arr[index] || null, writable: false, enumerable: false });
337
+ Object.defineProperty(arr, 'namedItem', { value: (name) => arr[name] || null, writable: false, enumerable: false });
338
+ Object.defineProperty(arr, 'refresh', { value: () => {}, writable: false, enumerable: false });
339
+ return arr;
340
+ };
341
+ safeDefineGetter(navigator, 'plugins', pluginsGetter);
279
342
 
280
- // Override navigator.mimeTypes
281
- Object.defineProperty(navigator, 'mimeTypes', {
282
- get: () => {
283
- const arr = Object.create(MimeTypeArray.prototype);
284
- fakeMimeTypes.forEach((m, i) => {
285
- arr[i] = m;
286
- arr[m.type] = m;
287
- });
288
- arr.length = fakeMimeTypes.length;
289
- arr.item = (index) => arr[index] || null;
290
- arr.namedItem = (name) => arr[name] || null;
291
- return arr;
292
- },
293
- configurable: false,
294
- enumerable: true
295
- });
343
+ // Override navigator.mimeTypes (with guard)
344
+ const mimeTypesGetter = () => {
345
+ const arr = Object.create(MimeTypeArray.prototype);
346
+ fakeMimeTypes.forEach((m, i) => {
347
+ arr[i] = m;
348
+ arr[m.type] = m;
349
+ });
350
+ // Use Object.defineProperty for read-only properties
351
+ Object.defineProperty(arr, 'length', { value: fakeMimeTypes.length, writable: false, enumerable: true });
352
+ Object.defineProperty(arr, 'item', { value: (index) => arr[index] || null, writable: false, enumerable: false });
353
+ Object.defineProperty(arr, 'namedItem', { value: (name) => arr[name] || null, writable: false, enumerable: false });
354
+ return arr;
355
+ };
356
+ safeDefineGetter(navigator, 'mimeTypes', mimeTypesGetter);
296
357
  } catch (e) {}
297
358
  };
298
359
 
@@ -412,28 +473,652 @@ export const createStealthScript = () => {
412
473
  };
413
474
 
414
475
  if (!window.chrome) window.chrome = {};
415
- Object.defineProperty(window.chrome, 'runtime', {
476
+ safeDefineProperty(window.chrome, 'runtime', {
416
477
  value: runtime,
417
- configurable: false,
418
478
  enumerable: true,
419
479
  writable: false
420
480
  });
421
481
  }
422
482
  };
423
483
 
484
+ // 10. Device Memory Spoofing (2024-2025)
485
+ const spoofDeviceMemory = () => {
486
+ const platform = navigator.platform || 'Win32';
487
+
488
+ // Platform-appropriate device memory values
489
+ const memoryConfig = {
490
+ 'Win32': [4, 8, 16], // Most Windows PCs have 4-16GB
491
+ 'MacIntel': [8, 16], // Macs typically have 8-16GB
492
+ 'Linux x86_64': [4, 8, 16]
493
+ };
494
+
495
+ const memories = memoryConfig[platform] || memoryConfig['Win32'];
496
+ // Use session seed for consistency
497
+ const selectedMemory = memories[sessionSeed % memories.length];
498
+
499
+ // Use guard to avoid conflicts with other scripts
500
+ if ('deviceMemory' in navigator) {
501
+ safeDefineGetter(navigator, 'deviceMemory', () => selectedMemory);
502
+ }
503
+ };
504
+
505
+ // 11. PDF Viewer Enabled Spoofing (2024-2025)
506
+ const spoofPdfViewerEnabled = () => {
507
+ // Chrome always has PDF viewer enabled (use guard)
508
+ safeDefineGetter(navigator, 'pdfViewerEnabled', () => true);
509
+ };
510
+
511
+ // 12. Notification Permission Spoofing (2024-2025)
512
+ const spoofNotificationPermission = () => {
513
+ if ('Notification' in window) {
514
+ // Override the permission property to return 'default' (user hasn't been asked) - with guard
515
+ safeDefineGetter(Notification, 'permission', () => 'default');
516
+
517
+ // Override requestPermission to behave normally
518
+ const originalRequestPermission = Notification.requestPermission;
519
+ Notification.requestPermission = function(callback) {
520
+ // Return a promise that resolves to 'default' or 'denied'
521
+ const result = Promise.resolve('default');
522
+ if (callback && typeof callback === 'function') {
523
+ result.then(callback);
524
+ }
525
+ return result;
526
+ };
527
+ }
528
+ };
529
+
530
+ // 13. Bluetooth API Spoofing (2024-2025)
531
+ const spoofBluetoothAPI = () => {
532
+ if ('bluetooth' in navigator) {
533
+ // Make bluetooth appear available but return empty results
534
+ const fakeBluetooth = {
535
+ getAvailability: () => Promise.resolve(true),
536
+ requestDevice: () => Promise.reject(new DOMException('User cancelled the requestDevice() chooser.', 'NotFoundError')),
537
+ getDevices: () => Promise.resolve([]),
538
+ addEventListener: () => {},
539
+ removeEventListener: () => {},
540
+ dispatchEvent: () => true
541
+ };
542
+
543
+ safeDefineGetter(navigator, 'bluetooth', () => fakeBluetooth);
544
+ }
545
+ };
546
+
547
+ // 14. USB API Spoofing (2024-2025)
548
+ const spoofUSBAPI = () => {
549
+ if ('usb' in navigator) {
550
+ const fakeUSB = {
551
+ getDevices: () => Promise.resolve([]),
552
+ requestDevice: () => Promise.reject(new DOMException('No device selected.', 'NotFoundError')),
553
+ addEventListener: () => {},
554
+ removeEventListener: () => {},
555
+ dispatchEvent: () => true,
556
+ onconnect: null,
557
+ ondisconnect: null
558
+ };
559
+
560
+ safeDefineGetter(navigator, 'usb', () => fakeUSB);
561
+ }
562
+ };
563
+
564
+ // 15. Serial API Spoofing (2024-2025)
565
+ const spoofSerialAPI = () => {
566
+ if ('serial' in navigator) {
567
+ const fakeSerial = {
568
+ getPorts: () => Promise.resolve([]),
569
+ requestPort: () => Promise.reject(new DOMException('No port selected.', 'NotFoundError')),
570
+ addEventListener: () => {},
571
+ removeEventListener: () => {},
572
+ dispatchEvent: () => true,
573
+ onconnect: null,
574
+ ondisconnect: null
575
+ };
576
+
577
+ safeDefineGetter(navigator, 'serial', () => fakeSerial);
578
+ }
579
+ };
580
+
581
+ // 16. Speech Synthesis Voices Spoofing (2024-2025)
582
+ const spoofSpeechSynthesis = () => {
583
+ if ('speechSynthesis' in window) {
584
+ const platform = navigator.platform || 'Win32';
585
+
586
+ // Platform-specific voices
587
+ const voiceConfigs = {
588
+ 'Win32': [
589
+ { name: 'Microsoft David - English (United States)', lang: 'en-US', localService: true, default: true },
590
+ { name: 'Microsoft Zira - English (United States)', lang: 'en-US', localService: true, default: false },
591
+ { name: 'Microsoft Mark - English (United States)', lang: 'en-US', localService: true, default: false },
592
+ { name: 'Google US English', lang: 'en-US', localService: false, default: false },
593
+ { name: 'Google UK English Female', lang: 'en-GB', localService: false, default: false },
594
+ { name: 'Google UK English Male', lang: 'en-GB', localService: false, default: false }
595
+ ],
596
+ 'MacIntel': [
597
+ { name: 'Alex', lang: 'en-US', localService: true, default: true },
598
+ { name: 'Samantha', lang: 'en-US', localService: true, default: false },
599
+ { name: 'Daniel', lang: 'en-GB', localService: true, default: false },
600
+ { name: 'Google US English', lang: 'en-US', localService: false, default: false }
601
+ ],
602
+ 'Linux x86_64': [
603
+ { name: 'Google US English', lang: 'en-US', localService: false, default: true },
604
+ { name: 'Google UK English Female', lang: 'en-GB', localService: false, default: false }
605
+ ]
606
+ };
607
+
608
+ const voices = voiceConfigs[platform] || voiceConfigs['Win32'];
609
+
610
+ // Create SpeechSynthesisVoice-like objects
611
+ const fakeVoices = voices.map(v => ({
612
+ voiceURI: v.name,
613
+ name: v.name,
614
+ lang: v.lang,
615
+ localService: v.localService,
616
+ default: v.default
617
+ }));
618
+
619
+ // Override getVoices
620
+ const originalGetVoices = speechSynthesis.getVoices;
621
+ speechSynthesis.getVoices = function() {
622
+ // Return our platform-appropriate voices
623
+ return fakeVoices;
624
+ };
625
+
626
+ // Trigger voiceschanged event after a delay to simulate loading
627
+ setTimeout(() => {
628
+ try {
629
+ const event = new Event('voiceschanged');
630
+ speechSynthesis.dispatchEvent(event);
631
+ } catch (e) {}
632
+ }, 100);
633
+ }
634
+ };
635
+
636
+ // 17. Credentials API Spoofing (2024-2025)
637
+ const spoofCredentialsAPI = () => {
638
+ if ('credentials' in navigator) {
639
+ const originalGet = navigator.credentials.get;
640
+ const originalCreate = navigator.credentials.create;
641
+ const originalStore = navigator.credentials.store;
642
+
643
+ // Make credentials API behave like a normal browser
644
+ navigator.credentials.get = function(options) {
645
+ // For publicKey (WebAuthn), reject like a normal user cancellation
646
+ if (options && options.publicKey) {
647
+ return Promise.reject(new DOMException(
648
+ 'The operation either timed out or was not allowed.',
649
+ 'NotAllowedError'
650
+ ));
651
+ }
652
+ // For password credentials, return null (no saved credentials)
653
+ return Promise.resolve(null);
654
+ };
655
+
656
+ navigator.credentials.create = function(options) {
657
+ if (options && options.publicKey) {
658
+ return Promise.reject(new DOMException(
659
+ 'The operation either timed out or was not allowed.',
660
+ 'NotAllowedError'
661
+ ));
662
+ }
663
+ return originalCreate.apply(this, arguments);
664
+ };
665
+
666
+ navigator.credentials.store = function(credential) {
667
+ // Accept but don't actually store
668
+ return Promise.resolve(credential);
669
+ };
670
+ }
671
+ };
672
+
673
+ // 18. HID API Spoofing (2024-2025)
674
+ const spoofHIDAPI = () => {
675
+ if ('hid' in navigator) {
676
+ const fakeHID = {
677
+ getDevices: () => Promise.resolve([]),
678
+ requestDevice: () => Promise.reject(new DOMException('No device selected.', 'NotFoundError')),
679
+ addEventListener: () => {},
680
+ removeEventListener: () => {},
681
+ dispatchEvent: () => true,
682
+ onconnect: null,
683
+ ondisconnect: null
684
+ };
685
+
686
+ safeDefineGetter(navigator, 'hid', () => fakeHID);
687
+ }
688
+ };
689
+
690
+ // 19. Gamepad API Spoofing (2024-2025)
691
+ const spoofGamepadAPI = () => {
692
+ // Return empty array for getGamepads
693
+ const originalGetGamepads = navigator.getGamepads;
694
+ if (originalGetGamepads) {
695
+ navigator.getGamepads = function() {
696
+ // Return empty array like no gamepads connected
697
+ return [];
698
+ };
699
+ }
700
+ };
701
+
702
+ // 20. Clipboard API Protection (2024-2025)
703
+ const spoofClipboardAPI = () => {
704
+ if (navigator.clipboard) {
705
+ const originalReadText = navigator.clipboard.readText;
706
+ const originalRead = navigator.clipboard.read;
707
+
708
+ // Make clipboard read behave like permission not granted
709
+ navigator.clipboard.readText = function() {
710
+ return Promise.reject(new DOMException(
711
+ 'Read permission denied.',
712
+ 'NotAllowedError'
713
+ ));
714
+ };
715
+
716
+ navigator.clipboard.read = function() {
717
+ return Promise.reject(new DOMException(
718
+ 'Read permission denied.',
719
+ 'NotAllowedError'
720
+ ));
721
+ };
722
+ }
723
+ };
724
+
725
+ // 21. Do Not Track Spoofing (2024-2025)
726
+ const spoofDoNotTrack = () => {
727
+ // Most real users have DNT disabled or not set
728
+ safeDefineGetter(navigator, 'doNotTrack', () => null);
729
+ };
730
+
731
+ // 22. Global Privacy Control Spoofing (2024-2025)
732
+ const spoofGlobalPrivacyControl = () => {
733
+ // Most users don't have GPC enabled
734
+ safeDefineGetter(navigator, 'globalPrivacyControl', () => false);
735
+ };
736
+
737
+ // 23. Keyboard API Spoofing (2024-2025) - DataDome checks getLayoutMap()
738
+ const spoofKeyboardAPI = () => {
739
+ // Full US QWERTY keyboard layout map
740
+ const qwertyLayoutMap = new Map([
741
+ ['Backquote', '\`'], ['Digit1', '1'], ['Digit2', '2'], ['Digit3', '3'],
742
+ ['Digit4', '4'], ['Digit5', '5'], ['Digit6', '6'], ['Digit7', '7'],
743
+ ['Digit8', '8'], ['Digit9', '9'], ['Digit0', '0'], ['Minus', '-'],
744
+ ['Equal', '='], ['Backspace', ''], ['Tab', ''], ['KeyQ', 'q'],
745
+ ['KeyW', 'w'], ['KeyE', 'e'], ['KeyR', 'r'], ['KeyT', 't'],
746
+ ['KeyY', 'y'], ['KeyU', 'u'], ['KeyI', 'i'], ['KeyO', 'o'],
747
+ ['KeyP', 'p'], ['BracketLeft', '['], ['BracketRight', ']'],
748
+ ['Backslash', '\\\\'], ['CapsLock', ''], ['KeyA', 'a'], ['KeyS', 's'],
749
+ ['KeyD', 'd'], ['KeyF', 'f'], ['KeyG', 'g'], ['KeyH', 'h'],
750
+ ['KeyJ', 'j'], ['KeyK', 'k'], ['KeyL', 'l'], ['Semicolon', ';'],
751
+ ['Quote', "'"], ['Enter', ''], ['ShiftLeft', ''], ['KeyZ', 'z'],
752
+ ['KeyX', 'x'], ['KeyC', 'c'], ['KeyV', 'v'], ['KeyB', 'b'],
753
+ ['KeyN', 'n'], ['KeyM', 'm'], ['Comma', ','], ['Period', '.'],
754
+ ['Slash', '/'], ['ShiftRight', ''], ['ControlLeft', ''],
755
+ ['AltLeft', ''], ['Space', ' '], ['AltRight', ''], ['ControlRight', ''],
756
+ ['ArrowLeft', ''], ['ArrowUp', ''], ['ArrowDown', ''], ['ArrowRight', ''],
757
+ ['NumpadDivide', '/'], ['NumpadMultiply', '*'], ['NumpadSubtract', '-'],
758
+ ['Numpad7', '7'], ['Numpad8', '8'], ['Numpad9', '9'], ['NumpadAdd', '+'],
759
+ ['Numpad4', '4'], ['Numpad5', '5'], ['Numpad6', '6'], ['Numpad1', '1'],
760
+ ['Numpad2', '2'], ['Numpad3', '3'], ['NumpadEnter', ''], ['Numpad0', '0'],
761
+ ['NumpadDecimal', '.']
762
+ ]);
763
+
764
+ // Create a KeyboardLayoutMap-like object
765
+ const createLayoutMap = () => {
766
+ const map = {
767
+ entries: function* () { yield* qwertyLayoutMap.entries(); },
768
+ keys: function* () { yield* qwertyLayoutMap.keys(); },
769
+ values: function* () { yield* qwertyLayoutMap.values(); },
770
+ forEach: (callback) => qwertyLayoutMap.forEach(callback),
771
+ get: (key) => qwertyLayoutMap.get(key),
772
+ has: (key) => qwertyLayoutMap.has(key),
773
+ size: qwertyLayoutMap.size,
774
+ [Symbol.iterator]: function* () { yield* qwertyLayoutMap.entries(); }
775
+ };
776
+
777
+ // Make it look like a KeyboardLayoutMap
778
+ Object.defineProperty(map, Symbol.toStringTag, {
779
+ value: 'KeyboardLayoutMap',
780
+ configurable: true
781
+ });
782
+
783
+ return map;
784
+ };
785
+
786
+ // Cache the layout map promise for consistency (DataDome may check promise identity)
787
+ let cachedLayoutMapPromise = null;
788
+
789
+ const fakeKeyboard = {
790
+ getLayoutMap: function() {
791
+ if (!cachedLayoutMapPromise) {
792
+ cachedLayoutMapPromise = Promise.resolve(createLayoutMap());
793
+ }
794
+ return cachedLayoutMapPromise;
795
+ },
796
+ lock: function() { return Promise.resolve(); },
797
+ unlock: function() {}
798
+ };
799
+
800
+ // Make methods look native
801
+ Object.defineProperty(fakeKeyboard.getLayoutMap, 'toString', {
802
+ value: () => 'function getLayoutMap() { [native code] }',
803
+ configurable: false
804
+ });
805
+
806
+ safeDefineGetter(navigator, 'keyboard', () => fakeKeyboard);
807
+ };
808
+
809
+ // 24. MediaDevices API Spoofing (2024-2025) - DataDome checks enumerateDevices()
810
+ const spoofMediaDevicesAPI = () => {
811
+ if (!navigator.mediaDevices) return;
812
+
813
+ const originalEnumerateDevices = navigator.mediaDevices.enumerateDevices;
814
+
815
+ // Cache the promise for consistency
816
+ let cachedDevicesPromise = null;
817
+
818
+ // Create realistic but empty device list (user hasn't granted permissions)
819
+ const createDeviceList = () => {
820
+ const devices = [
821
+ {
822
+ deviceId: '',
823
+ groupId: '',
824
+ kind: 'audioinput',
825
+ label: '',
826
+ toJSON: function() { return { deviceId: '', groupId: '', kind: 'audioinput', label: '' }; }
827
+ },
828
+ {
829
+ deviceId: '',
830
+ groupId: '',
831
+ kind: 'videoinput',
832
+ label: '',
833
+ toJSON: function() { return { deviceId: '', groupId: '', kind: 'videoinput', label: '' }; }
834
+ },
835
+ {
836
+ deviceId: '',
837
+ groupId: '',
838
+ kind: 'audiooutput',
839
+ label: '',
840
+ toJSON: function() { return { deviceId: '', groupId: '', kind: 'audiooutput', label: '' }; }
841
+ }
842
+ ];
843
+
844
+ // Set prototypes to MediaDeviceInfo
845
+ devices.forEach(device => {
846
+ if (typeof MediaDeviceInfo !== 'undefined') {
847
+ try {
848
+ Object.setPrototypeOf(device, MediaDeviceInfo.prototype);
849
+ } catch (e) {}
850
+ }
851
+ });
852
+
853
+ return devices;
854
+ };
855
+
856
+ navigator.mediaDevices.enumerateDevices = function() {
857
+ if (!cachedDevicesPromise) {
858
+ cachedDevicesPromise = Promise.resolve(createDeviceList());
859
+ }
860
+ return cachedDevicesPromise;
861
+ };
862
+
863
+ // Make it look native
864
+ Object.defineProperty(navigator.mediaDevices.enumerateDevices, 'toString', {
865
+ value: () => 'function enumerateDevices() { [native code] }',
866
+ configurable: false
867
+ });
868
+ };
869
+
870
+ // 25. ServiceWorker API Protection (2024-2025) - DataDome checks ready/register
871
+ const spoofServiceWorkerAPI = () => {
872
+ if (!navigator.serviceWorker) return;
873
+
874
+ const sw = navigator.serviceWorker;
875
+
876
+ // Wrap register to work normally but look native
877
+ const originalRegister = sw.register;
878
+ if (originalRegister) {
879
+ sw.register = function(scriptURL, options) {
880
+ return originalRegister.apply(this, arguments);
881
+ };
882
+
883
+ Object.defineProperty(sw.register, 'toString', {
884
+ value: () => 'function register() { [native code] }',
885
+ configurable: false
886
+ });
887
+ }
888
+
889
+ // Ensure ready returns a proper promise
890
+ // Note: ready is a getter, we shouldn't override it as it's already a promise
891
+ };
892
+
893
+ // 26. Undefined Navigator Properties (2024-2025) - DataDome checks these
894
+ const spoofUndefinedNavigatorProps = () => {
895
+ // navigator.brave - Only present in Brave browser, must be undefined for Chrome
896
+ safeDefineGetter(navigator, 'brave', () => undefined);
897
+
898
+ // navigator.buildID - Firefox-specific, undefined for Chrome
899
+ safeDefineGetter(navigator, 'buildID', () => undefined);
900
+
901
+ // navigator.contacts - Not widely supported, should be undefined
902
+ safeDefineGetter(navigator, 'contacts', () => undefined);
903
+
904
+ // navigator.cookieDeprecationLabel - Chrome 120+ API, undefined in most cases
905
+ safeDefineGetter(navigator, 'cookieDeprecationLabel', () => undefined);
906
+
907
+ // navigator.loadPurpose - Should be undefined
908
+ safeDefineGetter(navigator, 'loadPurpose', () => undefined);
909
+ };
910
+
911
+ // 27. Worker Constructor Protection - Prevent fingerprint leakage in worker contexts
912
+ const protectWorkerConstructor = () => {
913
+ if (typeof Worker === 'undefined') return;
914
+
915
+ // Cache fingerprint values to inject into workers
916
+ const fingerprintValues = {
917
+ userAgent: navigator.userAgent,
918
+ platform: navigator.platform,
919
+ vendor: navigator.vendor || '',
920
+ language: navigator.language,
921
+ languages: JSON.stringify(navigator.languages || ['en-US']),
922
+ hardwareConcurrency: navigator.hardwareConcurrency || 8,
923
+ deviceMemory: navigator.deviceMemory || 8,
924
+ };
925
+
926
+ // Create the worker override script
927
+ const workerOverrideScript = \`
928
+ // Worker fingerprint consistency overrides
929
+ (function() {
930
+ const fingerprintValues = \${JSON.stringify(fingerprintValues)};
931
+
932
+ // Override navigator properties in worker context
933
+ if (typeof WorkerNavigator !== 'undefined' && self.navigator) {
934
+ try {
935
+ Object.defineProperty(self.navigator, 'userAgent', { get: () => fingerprintValues.userAgent });
936
+ Object.defineProperty(self.navigator, 'platform', { get: () => fingerprintValues.platform });
937
+ Object.defineProperty(self.navigator, 'vendor', { get: () => fingerprintValues.vendor });
938
+ Object.defineProperty(self.navigator, 'language', { get: () => fingerprintValues.language });
939
+ Object.defineProperty(self.navigator, 'languages', { get: () => JSON.parse(fingerprintValues.languages) });
940
+ Object.defineProperty(self.navigator, 'hardwareConcurrency', { get: () => fingerprintValues.hardwareConcurrency });
941
+ Object.defineProperty(self.navigator, 'deviceMemory', { get: () => fingerprintValues.deviceMemory });
942
+ } catch (e) {}
943
+ }
944
+ })();
945
+ \`;
946
+
947
+ const OriginalWorker = Worker;
948
+
949
+ window.Worker = function(scriptURL, options) {
950
+ // For blob URLs, we can try to prepend our overrides
951
+ if (typeof scriptURL === 'string' && scriptURL.startsWith('blob:')) {
952
+ // Can't modify blob URLs easily, but the worker will still get our overrides
953
+ // if it was created from same-origin code
954
+ }
955
+
956
+ // Create the worker normally
957
+ const worker = new OriginalWorker(scriptURL, options);
958
+
959
+ // Intercept postMessage to detect fingerprint requests
960
+ const originalPostMessage = worker.postMessage.bind(worker);
961
+ worker.postMessage = function(message, transfer) {
962
+ return originalPostMessage(message, transfer);
963
+ };
964
+
965
+ return worker;
966
+ };
967
+
968
+ // Copy static properties
969
+ window.Worker.prototype = OriginalWorker.prototype;
970
+
971
+ // Make Worker constructor look native
972
+ Object.defineProperty(window.Worker, 'toString', {
973
+ value: () => 'function Worker() { [native code] }',
974
+ configurable: false
975
+ });
976
+
977
+ Object.defineProperty(window.Worker, 'name', {
978
+ value: 'Worker',
979
+ configurable: true
980
+ });
981
+ };
982
+
983
+ // 28. SharedWorker Protection - Similar to Worker
984
+ const protectSharedWorkerConstructor = () => {
985
+ if (typeof SharedWorker === 'undefined') return;
986
+
987
+ const OriginalSharedWorker = SharedWorker;
988
+
989
+ window.SharedWorker = function(scriptURL, options) {
990
+ const worker = new OriginalSharedWorker(scriptURL, options);
991
+ return worker;
992
+ };
993
+
994
+ // Copy prototype
995
+ window.SharedWorker.prototype = OriginalSharedWorker.prototype;
996
+
997
+ // Make SharedWorker constructor look native
998
+ Object.defineProperty(window.SharedWorker, 'toString', {
999
+ value: () => 'function SharedWorker() { [native code] }',
1000
+ configurable: false
1001
+ });
1002
+
1003
+ Object.defineProperty(window.SharedWorker, 'name', {
1004
+ value: 'SharedWorker',
1005
+ configurable: true
1006
+ });
1007
+ };
1008
+
1009
+ // 29. PostMessage Fingerprint Protection - Prevent cross-context fingerprint detection
1010
+ const protectPostMessage = () => {
1011
+ // Cache consistent fingerprint values
1012
+ const consistentFingerprint = {
1013
+ navigator: {
1014
+ userAgent: navigator.userAgent,
1015
+ platform: navigator.platform,
1016
+ vendor: navigator.vendor,
1017
+ language: navigator.language,
1018
+ languages: navigator.languages ? [...navigator.languages] : ['en-US'],
1019
+ hardwareConcurrency: navigator.hardwareConcurrency,
1020
+ deviceMemory: navigator.deviceMemory,
1021
+ maxTouchPoints: navigator.maxTouchPoints,
1022
+ webdriver: undefined,
1023
+ },
1024
+ screen: {
1025
+ width: screen.width,
1026
+ height: screen.height,
1027
+ availWidth: screen.availWidth,
1028
+ availHeight: screen.availHeight,
1029
+ colorDepth: screen.colorDepth,
1030
+ pixelDepth: screen.pixelDepth,
1031
+ }
1032
+ };
1033
+
1034
+ // Listen for fingerprint requests from iframes/workers
1035
+ window.addEventListener('message', function(event) {
1036
+ // Detect common fingerprint request patterns
1037
+ if (event.data && typeof event.data === 'object') {
1038
+ // If message looks like a fingerprint request, respond with consistent values
1039
+ if (event.data.type === 'fingerprintRequest' ||
1040
+ event.data.action === 'getFingerprint' ||
1041
+ event.data.cmd === 'getNavigator') {
1042
+
1043
+ if (event.source) {
1044
+ try {
1045
+ event.source.postMessage({
1046
+ type: 'fingerprintResponse',
1047
+ data: consistentFingerprint
1048
+ }, event.origin || '*');
1049
+ } catch (e) {}
1050
+ }
1051
+ }
1052
+ }
1053
+ }, false);
1054
+
1055
+ // Wrap postMessage to ensure consistent data
1056
+ const originalPostMessage = window.postMessage.bind(window);
1057
+ window.postMessage = function(message, targetOrigin, transfer) {
1058
+ return originalPostMessage(message, targetOrigin, transfer);
1059
+ };
1060
+
1061
+ Object.defineProperty(window.postMessage, 'toString', {
1062
+ value: () => 'function postMessage() { [native code] }',
1063
+ configurable: false
1064
+ });
1065
+ };
1066
+
424
1067
  // Initialize all protections
1068
+ const DEBUG_PREFIX = '[CDP-FP-DEBUG]';
1069
+ const ERROR_PREFIX = '[CDP-FP-ERROR]';
1070
+
1071
+ console.log(DEBUG_PREFIX, 'Starting stealth protection injection...');
1072
+
1073
+ const applyProtection = (name, fn) => {
1074
+ try {
1075
+ fn();
1076
+ console.log(DEBUG_PREFIX, \`✓ Applied \${name}\`);
1077
+ return true;
1078
+ } catch (e) {
1079
+ console.error(ERROR_PREFIX, \`✗ Failed to apply \${name}:\`, e);
1080
+ throw e; // Rethrow to make errors visible
1081
+ }
1082
+ };
1083
+
425
1084
  try {
426
- hideErrorStack();
427
- patchConsole();
428
- removeAutomationFlags();
429
- preventRuntimeEnableDetection();
430
- spoofPlugins();
431
- spoofPermissions();
432
- spoofBatteryAPI();
433
- spoofConnectionAPI();
434
- spoofChromeRuntime(); // NEW
1085
+ applyProtection('Error Stack Hiding', hideErrorStack);
1086
+ applyProtection('Console Patching', patchConsole);
1087
+ applyProtection('Automation Flags Removal', removeAutomationFlags);
1088
+ applyProtection('Runtime.enable Detection Prevention', preventRuntimeEnableDetection);
1089
+ applyProtection('Plugin Spoofing', spoofPlugins);
1090
+ applyProtection('Permissions API Spoofing', spoofPermissions);
1091
+ applyProtection('Battery API Spoofing', spoofBatteryAPI);
1092
+ applyProtection('Connection API Spoofing', spoofConnectionAPI);
1093
+ applyProtection('Chrome Runtime API Spoofing', spoofChromeRuntime);
1094
+ // New 2024-2025 protections
1095
+ applyProtection('Device Memory Spoofing', spoofDeviceMemory);
1096
+ applyProtection('PDF Viewer Enabled Spoofing', spoofPdfViewerEnabled);
1097
+ applyProtection('Notification Permission Spoofing', spoofNotificationPermission);
1098
+ applyProtection('Bluetooth API Spoofing', spoofBluetoothAPI);
1099
+ applyProtection('USB API Spoofing', spoofUSBAPI);
1100
+ applyProtection('Serial API Spoofing', spoofSerialAPI);
1101
+ applyProtection('Speech Synthesis Spoofing', spoofSpeechSynthesis);
1102
+ applyProtection('Credentials API Spoofing', spoofCredentialsAPI);
1103
+ applyProtection('HID API Spoofing', spoofHIDAPI);
1104
+ applyProtection('Gamepad API Spoofing', spoofGamepadAPI);
1105
+ applyProtection('Clipboard API Protection', spoofClipboardAPI);
1106
+ applyProtection('Do Not Track Spoofing', spoofDoNotTrack);
1107
+ applyProtection('Global Privacy Control Spoofing', spoofGlobalPrivacyControl);
1108
+ // DataDome-specific protections
1109
+ applyProtection('Keyboard API Spoofing', spoofKeyboardAPI);
1110
+ applyProtection('MediaDevices API Spoofing', spoofMediaDevicesAPI);
1111
+ applyProtection('ServiceWorker API Protection', spoofServiceWorkerAPI);
1112
+ applyProtection('Undefined Navigator Props', spoofUndefinedNavigatorProps);
1113
+ // Cross-context consistency protections
1114
+ applyProtection('Worker Constructor Protection', protectWorkerConstructor);
1115
+ applyProtection('SharedWorker Protection', protectSharedWorkerConstructor);
1116
+ applyProtection('PostMessage Protection', protectPostMessage);
1117
+
1118
+ console.log(DEBUG_PREFIX, '✓ All stealth protections applied successfully');
435
1119
  } catch (e) {
436
- // Silently fail to avoid detection
1120
+ console.error(ERROR_PREFIX, '✗ Failed to apply stealth protections:', e);
1121
+ throw e; // Rethrow to make errors visible
437
1122
  }
438
1123
  })();`;
439
1124
  };