jumpy-lion 0.0.42 → 0.0.44

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 (41) hide show
  1. package/dist/fingerprinting/fingerprint-injector.d.ts.map +1 -1
  2. package/dist/fingerprinting/fingerprint-injector.js +4 -1
  3. package/dist/fingerprinting/fingerprint-injector.js.map +1 -1
  4. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.d.ts.map +1 -1
  5. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.js +283 -4
  6. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.js.map +1 -1
  7. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts.map +1 -1
  8. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js +107 -0
  9. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js.map +1 -1
  10. package/dist/fingerprinting/fingerprint-overrides/index.d.ts +1 -0
  11. package/dist/fingerprinting/fingerprint-overrides/index.d.ts.map +1 -1
  12. package/dist/fingerprinting/fingerprint-overrides/index.js +2 -0
  13. package/dist/fingerprinting/fingerprint-overrides/index.js.map +1 -1
  14. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.d.ts.map +1 -1
  15. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js +99 -68
  16. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js.map +1 -1
  17. package/dist/fingerprinting/fingerprint-overrides/prototype-integrity.d.ts +13 -0
  18. package/dist/fingerprinting/fingerprint-overrides/prototype-integrity.d.ts.map +1 -0
  19. package/dist/fingerprinting/fingerprint-overrides/prototype-integrity.js +355 -0
  20. package/dist/fingerprinting/fingerprint-overrides/prototype-integrity.js.map +1 -0
  21. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.d.ts +2 -0
  22. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.d.ts.map +1 -1
  23. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.js +155 -24
  24. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.js.map +1 -1
  25. package/dist/fingerprinting/fingerprint-overrides/stealth-script.d.ts.map +1 -1
  26. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js +339 -0
  27. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js.map +1 -1
  28. package/dist/fingerprinting/fingerprint-overrides/ua-ch.d.ts +7 -1
  29. package/dist/fingerprinting/fingerprint-overrides/ua-ch.d.ts.map +1 -1
  30. package/dist/fingerprinting/fingerprint-overrides/ua-ch.js +158 -58
  31. package/dist/fingerprinting/fingerprint-overrides/ua-ch.js.map +1 -1
  32. package/dist/fingerprinting/fingerprint-overrides/utils.d.ts.map +1 -1
  33. package/dist/fingerprinting/fingerprint-overrides/utils.js +214 -12
  34. package/dist/fingerprinting/fingerprint-overrides/utils.js.map +1 -1
  35. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.d.ts.map +1 -1
  36. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js +39 -10
  37. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js.map +1 -1
  38. package/dist/index.d.ts +1 -1
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/tsconfig.build.tsbuildinfo +1 -1
  41. package/package.json +1 -1
@@ -4,6 +4,8 @@
4
4
  *
5
5
  * IMPORTANT: This is now a SCRIPT to be injected via addScriptToEvaluateOnNewDocument,
6
6
  * NOT via Runtime.evaluate (which would defeat the purpose since Runtime.evaluate IS detectable!)
7
+ *
8
+ * Enhanced 2024-2025: Comprehensive stack trace sanitization that removes ALL CDP markers
7
9
  */
8
10
  /**
9
11
  * Creates the runtime enable bypass script that should be bundled with other stealth scripts.
@@ -16,7 +18,7 @@ export const createRuntimeEnableBypassScript = () => `
16
18
 
17
19
  try {
18
20
  // =============================================================================
19
- // PART 1: Error stack trace sanitization
21
+ // PART 1: Comprehensive Error stack trace sanitization
20
22
  // CDP detection often works by examining Error.stack for automation markers
21
23
  // =============================================================================
22
24
 
@@ -24,56 +26,185 @@ export const createRuntimeEnableBypassScript = () => `
24
26
  const originalErrorToString = Error.prototype.toString;
25
27
  const originalErrorStackDesc = Object.getOwnPropertyDescriptor(Error.prototype, 'stack');
26
28
 
27
- // Patterns that reveal CDP/automation
28
- const CDP_MARKERS = [
29
- '__puppeteer_evaluation_script__',
30
- '__playwright_evaluation_script__',
31
- 'CDP_',
32
- 'chrome-extension://',
33
- 'devtools://',
34
- 'pptr:',
35
- 'Runtime.evaluate',
29
+ // Comprehensive patterns that reveal CDP/automation
30
+ const CDP_MARKER_PATTERNS = [
31
+ // Puppeteer/Playwright markers
32
+ /__puppeteer_evaluation_script__/g,
33
+ /__playwright_evaluation_script__/g,
34
+ /__driver_evaluate/g,
35
+ /__webdriver_evaluate/g,
36
+ /__selenium_evaluate/g,
37
+ /__fxdriver_evaluate/g,
38
+
39
+ // CDP protocol markers
40
+ /CDP_[A-Z_]+/g,
41
+ /Runtime\\.evaluate/g,
42
+ /Runtime\\.callFunctionOn/g,
43
+ /Page\\.addScriptToEvaluateOnNewDocument/g,
44
+
45
+ // DevTools markers
46
+ /devtools:\\/\\/[^\\s)]+/g,
47
+ /chrome-extension:\\/\\/[a-z]+\\/[^\\s)]+/g,
48
+
49
+ // Puppeteer-specific patterns
50
+ /pptr:[^\\s)]+/g,
51
+ /\\(pptr:[^)]+\\)/g,
52
+
53
+ // Anonymous script patterns that reveal CDP injection
54
+ /at <anonymous>:\\d+:\\d+/g,
55
+ /at Object\\.<anonymous> \\(<anonymous>:\\d+:\\d+\\)/g,
56
+ /at Object\\.construct \\(<anonymous>:\\d+:\\d+\\)/g,
57
+ /at Object\\.apply \\(<anonymous>:\\d+:\\d+\\)/g,
58
+ /at Object\\.get \\(<anonymous>:\\d+:\\d+\\)/g,
59
+ /at newHandler\\.<computed>/g,
60
+ /\\(<anonymous>:\\d+:\\d+\\)/g,
61
+
62
+ // Source URL comments
63
+ /\\/\\/# sourceURL=[^\\n]+/g,
64
+ /\\/\\/# sourceMappingURL=[^\\n]+/g,
65
+ /\\/\\/@sourceURL=[^\\n]+/g,
66
+ ];
67
+
68
+ // Realistic replacement frames for different contexts
69
+ const REALISTIC_FRAMES = [
70
+ 'at https://www.google.com/pagead/managed/js/gpt/m202412091001/pubads_impl_page_level_ads.js:1:100',
71
+ 'at https://www.googletagmanager.com/gtm.js:1:234',
72
+ 'at https://www.google-analytics.com/analytics.js:1:456',
36
73
  ];
37
74
 
75
+ /**
76
+ * Sanitize a single stack frame line
77
+ */
78
+ const sanitizeStackLine = (line) => {
79
+ if (!line || typeof line !== 'string') return line;
80
+
81
+ // Check if this line contains CDP markers
82
+ let hasCDPMarker = false;
83
+ for (const pattern of CDP_MARKER_PATTERNS) {
84
+ pattern.lastIndex = 0; // Reset regex state
85
+ if (pattern.test(line)) {
86
+ hasCDPMarker = true;
87
+ break;
88
+ }
89
+ }
90
+
91
+ // If line has CDP markers, replace the entire line with a realistic one
92
+ // or just the marker portion
93
+ if (hasCDPMarker) {
94
+ // If the line is mostly anonymous/CDP content, skip it entirely
95
+ if (line.includes('<anonymous>:') && !line.includes('http')) {
96
+ return null; // Mark for removal
97
+ }
98
+
99
+ // Otherwise, sanitize the markers
100
+ let sanitized = line;
101
+ for (const pattern of CDP_MARKER_PATTERNS) {
102
+ pattern.lastIndex = 0;
103
+ sanitized = sanitized.replace(pattern, '');
104
+ }
105
+
106
+ // Clean up any double spaces or empty parentheses
107
+ sanitized = sanitized
108
+ .replace(/\\(\\s*\\)/g, '')
109
+ .replace(/\\s+/g, ' ')
110
+ .trim();
111
+
112
+ // If line is now too short to be meaningful, skip it
113
+ if (sanitized.length < 10 || sanitized === 'at') {
114
+ return null;
115
+ }
116
+
117
+ return sanitized;
118
+ }
119
+
120
+ return line;
121
+ };
122
+
123
+ /**
124
+ * Comprehensively sanitize a stack trace
125
+ */
38
126
  const sanitizeStack = (stack) => {
39
127
  if (!stack || typeof stack !== 'string') return stack;
40
128
 
41
- let sanitized = stack;
42
- for (const marker of CDP_MARKERS) {
43
- if (sanitized.includes(marker)) {
44
- // Replace with generic anonymous reference
45
- // Simple string replacement (markers don't contain regex special chars)
46
- while (sanitized.includes(marker)) {
47
- sanitized = sanitized.split(marker).join('anonymous');
48
- }
129
+ const lines = stack.split('\\n');
130
+ const sanitizedLines = [];
131
+ let removedCount = 0;
132
+
133
+ for (let i = 0; i < lines.length; i++) {
134
+ const line = lines[i];
135
+ const sanitized = sanitizeStackLine(line);
136
+
137
+ if (sanitized === null) {
138
+ removedCount++;
139
+ // Don't add too many removed lines in a row
140
+ if (removedCount > 3) continue;
141
+ } else {
142
+ removedCount = 0;
143
+ sanitizedLines.push(sanitized);
49
144
  }
50
145
  }
51
- return sanitized;
146
+
147
+ // Ensure stack looks natural - should have at least error message + a few frames
148
+ if (sanitizedLines.length < 2) {
149
+ // Add some realistic frames if stack is too short
150
+ sanitizedLines.push(' at HTMLDocument.<anonymous> (https://www.example.com/:1:100)');
151
+ }
152
+
153
+ return sanitizedLines.join('\\n');
52
154
  };
53
155
 
54
156
  // Override Error.prepareStackTrace if it exists (V8 specific)
55
- if (typeof Error.prepareStackTrace === 'function') {
157
+ // This is called when stack property is first accessed
158
+ if (Error.prepareStackTrace !== undefined) {
56
159
  const originalPrepareStackTrace = Error.prepareStackTrace;
57
160
  Error.prepareStackTrace = function(error, structuredStackTrace) {
58
- const stack = originalPrepareStackTrace.call(this, error, structuredStackTrace);
161
+ // If there's an original prepareStackTrace, use it first
162
+ let stack;
163
+ if (typeof originalPrepareStackTrace === 'function') {
164
+ stack = originalPrepareStackTrace.call(this, error, structuredStackTrace);
165
+ } else {
166
+ // Default V8 formatting
167
+ stack = error.toString() + '\\n' +
168
+ structuredStackTrace.map(frame => {
169
+ const fnName = frame.getFunctionName() || '<anonymous>';
170
+ const fileName = frame.getFileName() || '<anonymous>';
171
+ const lineNumber = frame.getLineNumber() || 0;
172
+ const columnNumber = frame.getColumnNumber() || 0;
173
+ return \` at \${fnName} (\${fileName}:\${lineNumber}:\${columnNumber})\`;
174
+ }).join('\\n');
175
+ }
59
176
  return sanitizeStack(stack);
60
177
  };
61
178
  }
62
179
 
63
- // Override Error.prototype.stack getter
180
+ // Override Error.prototype.stack getter with comprehensive sanitization
64
181
  if (originalErrorStackDesc && originalErrorStackDesc.get) {
65
182
  Object.defineProperty(Error.prototype, 'stack', {
66
183
  get: function() {
67
184
  const stack = originalErrorStackDesc.get.call(this);
68
185
  return sanitizeStack(stack);
69
186
  },
70
- set: originalErrorStackDesc.set,
187
+ set: function(value) {
188
+ if (originalErrorStackDesc.set) {
189
+ // Sanitize before setting too
190
+ originalErrorStackDesc.set.call(this, sanitizeStack(value));
191
+ }
192
+ },
71
193
  configurable: true,
72
194
  enumerable: false
73
195
  });
74
196
  }
75
197
 
76
- console.log(DEBUG_PREFIX, '✓ Error stack trace sanitization applied');
198
+ // Also patch Error.captureStackTrace for V8
199
+ if (typeof Error.captureStackTrace === 'function') {
200
+ const originalCaptureStackTrace = Error.captureStackTrace;
201
+ Error.captureStackTrace = function(targetObject, constructorOpt) {
202
+ originalCaptureStackTrace.call(this, targetObject, constructorOpt);
203
+ // Stack will be sanitized when accessed via our getter
204
+ };
205
+ }
206
+
207
+ console.log(DEBUG_PREFIX, '✓ Comprehensive Error stack trace sanitization applied');
77
208
 
78
209
  // =============================================================================
79
210
  // PART 2: Console protection
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-enable-bypass.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/runtime-enable-bypass.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAW,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkI5D,CAAC"}
1
+ {"version":3,"file":"runtime-enable-bypass.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/runtime-enable-bypass.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAW,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmQ5D,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"stealth-script.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/stealth-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,mBAAmB,QAAO,MAowBtC,CAAC"}
1
+ {"version":3,"file":"stealth-script.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/stealth-script.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,mBAAmB,QAAO,MAulCtC,CAAC"}
@@ -734,6 +734,336 @@ export const createStealthScript = () => {
734
734
  safeDefineGetter(navigator, 'globalPrivacyControl', () => false);
735
735
  };
736
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
+
737
1067
  // Initialize all protections
738
1068
  const DEBUG_PREFIX = '[CDP-FP-DEBUG]';
739
1069
  const ERROR_PREFIX = '[CDP-FP-ERROR]';
@@ -775,6 +1105,15 @@ export const createStealthScript = () => {
775
1105
  applyProtection('Clipboard API Protection', spoofClipboardAPI);
776
1106
  applyProtection('Do Not Track Spoofing', spoofDoNotTrack);
777
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);
778
1117
 
779
1118
  console.log(DEBUG_PREFIX, '✓ All stealth protections applied successfully');
780
1119
  } catch (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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAkwBL,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAqlCL,CAAC;AACP,CAAC,CAAC"}
@@ -1,6 +1,12 @@
1
1
  /**
2
- * navigator.userAgentData spoofing
2
+ * navigator.userAgentData spoofing (UA-CH Client Hints)
3
3
  * Generates brand list & bitness matching the chosen platform.
4
+ *
5
+ * 2024-2025 Enhanced:
6
+ * - Consistent platform returns "Windows" for Win32
7
+ * - Proper getHighEntropyValues() with all Windows-specific fields
8
+ * - Realistic Chrome version numbers matching userAgent
9
+ * - Proper prototype chain and native-like appearance
4
10
  */
5
11
  export declare const createUAClientHintsSpoofingScript: (platform?: string) => string;
6
12
  //# sourceMappingURL=ua-ch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ua-ch.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/ua-ch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,iCAAiC,yBAAyB,MAyFtE,CAAC"}
1
+ {"version":3,"file":"ua-ch.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/ua-ch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,iCAAiC,yBAAyB,MAwLtE,CAAC"}