jumpy-lion 0.1.2 → 0.1.3
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.
- package/dist/browser-controller.js +1 -1
- package/dist/browser-controller.js.map +1 -1
- package/dist/browser-process/browser.d.ts.map +1 -1
- package/dist/browser-process/browser.js +3 -1
- package/dist/browser-process/browser.js.map +1 -1
- package/dist/fingerprinting/fingerprint-injector.d.ts +7 -1
- package/dist/fingerprinting/fingerprint-injector.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-injector.js +75 -10
- package/dist/fingerprinting/fingerprint-injector.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/index.d.ts +1 -0
- package/dist/fingerprinting/fingerprint-overrides/index.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/index.js +1 -0
- package/dist/fingerprinting/fingerprint-overrides/index.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/media-codecs-spoofing.d.ts +14 -0
- package/dist/fingerprinting/fingerprint-overrides/media-codecs-spoofing.d.ts.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/media-codecs-spoofing.js +160 -0
- package/dist/fingerprinting/fingerprint-overrides/media-codecs-spoofing.js.map +1 -0
- package/dist/fingerprinting/fingerprint-overrides/platform-consistency.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js +19 -17
- package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/stealth-script.d.ts.map +1 -1
- package/dist/fingerprinting/fingerprint-overrides/stealth-script.js +77 -19
- package/dist/fingerprinting/fingerprint-overrides/stealth-script.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -21,7 +21,7 @@ export const createPlatformConsistencyScript = (platform, fingerprintData) => {
|
|
|
21
21
|
maxTouchPoints: 0,
|
|
22
22
|
platform: 'Win32',
|
|
23
23
|
oscpu: 'Windows NT 10.0; Win64; x64',
|
|
24
|
-
vendor: '',
|
|
24
|
+
vendor: 'Google Inc.',
|
|
25
25
|
vendorSub: '',
|
|
26
26
|
productSub: '20030107',
|
|
27
27
|
cookieEnabled: true,
|
|
@@ -46,13 +46,14 @@ export const createPlatformConsistencyScript = (platform, fingerprintData) => {
|
|
|
46
46
|
{ type: 'text/pdf', suffixes: 'pdf', description: 'Portable Document Format' },
|
|
47
47
|
],
|
|
48
48
|
// Windows-specific connection properties
|
|
49
|
+
// NOTE: 'type' is NOT available on desktop Chrome (only Android),
|
|
50
|
+
// so we intentionally omit it to match real browser behavior
|
|
49
51
|
connection: {
|
|
50
52
|
downlink: 10,
|
|
51
53
|
effectiveType: '4g',
|
|
52
54
|
onchange: null,
|
|
53
55
|
rtt: 50,
|
|
54
56
|
saveData: false,
|
|
55
|
-
type: 'ethernet',
|
|
56
57
|
},
|
|
57
58
|
},
|
|
58
59
|
'MacIntel': {
|
|
@@ -212,25 +213,26 @@ export const createPlatformConsistencyScript = (platform, fingerprintData) => {
|
|
|
212
213
|
safeDefineProperty(navigator, 'mimeTypes', mimeTypesGetter);
|
|
213
214
|
}
|
|
214
215
|
|
|
215
|
-
// Override navigator.connection
|
|
216
|
-
//
|
|
216
|
+
// Override navigator.connection using a Proxy
|
|
217
|
+
// Connection properties (rtt, downlink, etc.) are non-configurable getters in Chrome,
|
|
218
|
+
// so Object.defineProperty fails. A Proxy on the navigator property intercepts all reads.
|
|
219
|
+
// CRITICAL: rtt === 0 in headless mode is a well-known detection vector.
|
|
217
220
|
if (config.connection && navigator.connection) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
return;
|
|
221
|
+
const realConnection = navigator.connection;
|
|
222
|
+
const connectionOverrides = config.connection;
|
|
223
|
+
const connectionProxy = new Proxy(realConnection, {
|
|
224
|
+
get(target, prop, receiver) {
|
|
225
|
+
if (prop in connectionOverrides) {
|
|
226
|
+
return connectionOverrides[prop];
|
|
224
227
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
} catch (e) {
|
|
231
|
-
// Silently ignore non-configurable properties
|
|
228
|
+
const value = Reflect.get(target, prop, receiver);
|
|
229
|
+
if (typeof value === 'function') {
|
|
230
|
+
return value.bind(target);
|
|
231
|
+
}
|
|
232
|
+
return value;
|
|
232
233
|
}
|
|
233
234
|
});
|
|
235
|
+
safeDefineProperty(navigator, 'connection', () => connectionProxy);
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
// Override screen properties (with guards)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"platform-consistency.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/platform-consistency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAuBH,MAAM,CAAC,MAAM,+BAA+B,GAAG,CAAC,QAAgB,EAAE,eAAgC,EAAU,EAAE;IAC1G,uDAAuD;IACvD,MAAM,eAAe,GAAG;QACpB,OAAO,EAAE;YACL,gBAAgB,EAAE,GAAG;YACrB,WAAW,EAAE,EAAE;YACf,UAAU,EAAE,EAAE;YACd,mBAAmB,EAAE,CAAC;YACtB,cAAc,EAAE,CAAC;YACjB,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,6BAA6B;YACpC,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"platform-consistency.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/platform-consistency.ts"],"names":[],"mappings":"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"}
|
|
@@ -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,
|
|
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,MAy8BtC,CAAC"}
|
|
@@ -84,10 +84,11 @@ export const createStealthScript = () => {
|
|
|
84
84
|
|
|
85
85
|
// 3. WebDriver and Automation Flags Removal (2025)
|
|
86
86
|
const removeAutomationFlags = () => {
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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);
|
|
91
92
|
|
|
92
93
|
// Remove automation indicators
|
|
93
94
|
const automationProperties = [
|
|
@@ -283,16 +284,22 @@ export const createStealthScript = () => {
|
|
|
283
284
|
};
|
|
284
285
|
|
|
285
286
|
// 8. Connection API Spoofing (2025)
|
|
287
|
+
// Uses Proxy because connection properties are non-configurable getters.
|
|
288
|
+
// rtt === 0 is a well-known headless detection vector.
|
|
286
289
|
const spoofConnectionAPI = () => {
|
|
287
290
|
if ('connection' in navigator || 'mozConnection' in navigator || 'webkitConnection' in navigator) {
|
|
288
|
-
const
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
291
|
+
const realConnection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
|
|
292
|
+
if (realConnection) {
|
|
293
|
+
const overrides = { rtt: 50, downlink: 10.0, effectiveType: '4g', saveData: false };
|
|
294
|
+
const proxy = new Proxy(realConnection, {
|
|
295
|
+
get(target, prop, receiver) {
|
|
296
|
+
if (prop in overrides) return overrides[prop];
|
|
297
|
+
const val = Reflect.get(target, prop, receiver);
|
|
298
|
+
if (typeof val === 'function') return val.bind(target);
|
|
299
|
+
return val;
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
safeDefineGetter(navigator, 'connection', () => proxy);
|
|
296
303
|
}
|
|
297
304
|
}
|
|
298
305
|
};
|
|
@@ -334,22 +341,73 @@ export const createStealthScript = () => {
|
|
|
334
341
|
requestUpdateCheck: () => Promise.resolve(['no_update', {}]),
|
|
335
342
|
restart: () => {},
|
|
336
343
|
restartAfterDelay: () => {},
|
|
337
|
-
getPlatformInfo: () =>
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
344
|
+
getPlatformInfo: () => {
|
|
345
|
+
// Derive OS from navigator.platform for consistency
|
|
346
|
+
const p = (navigator.platform || '').toLowerCase();
|
|
347
|
+
let os = 'win';
|
|
348
|
+
let arch = 'x86-64';
|
|
349
|
+
if (p.includes('mac')) { os = 'mac'; arch = 'arm64'; }
|
|
350
|
+
else if (p.includes('linux')) { os = 'linux'; }
|
|
351
|
+
return Promise.resolve({ os, arch, nacl_arch: arch });
|
|
352
|
+
},
|
|
342
353
|
getPackageDirectoryEntry: () => Promise.resolve({}),
|
|
343
354
|
lastError: null
|
|
344
355
|
};
|
|
345
356
|
|
|
346
357
|
if (!window.chrome) window.chrome = {};
|
|
347
|
-
safeDefineProperty(window.chrome, 'runtime', {
|
|
348
|
-
value: runtime,
|
|
358
|
+
safeDefineProperty(window.chrome, 'runtime', {
|
|
359
|
+
value: runtime,
|
|
349
360
|
enumerable: true,
|
|
350
361
|
writable: false
|
|
351
362
|
});
|
|
352
363
|
}
|
|
364
|
+
|
|
365
|
+
// Ensure chrome.app exists (present in all real Chrome browsers)
|
|
366
|
+
if (window.chrome && !window.chrome.app) {
|
|
367
|
+
window.chrome.app = {
|
|
368
|
+
isInstalled: false,
|
|
369
|
+
InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' },
|
|
370
|
+
RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' },
|
|
371
|
+
getDetails: () => null,
|
|
372
|
+
getIsInstalled: () => false,
|
|
373
|
+
installState: () => 'not_installed',
|
|
374
|
+
runningState: () => 'cannot_run',
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// chrome.csi() - Chrome-specific, returns page load timing info
|
|
379
|
+
if (window.chrome && !window.chrome.csi) {
|
|
380
|
+
window.chrome.csi = function() {
|
|
381
|
+
return {
|
|
382
|
+
onloadT: Date.now() - (Math.random() * 2000 + 500),
|
|
383
|
+
startE: Date.now() - (Math.random() * 3000 + 1000),
|
|
384
|
+
pageT: performance.now(),
|
|
385
|
+
tran: 15, // Normal navigation
|
|
386
|
+
};
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// chrome.loadTimes() - Chrome-specific, returns load timing info
|
|
391
|
+
if (window.chrome && !window.chrome.loadTimes) {
|
|
392
|
+
window.chrome.loadTimes = function() {
|
|
393
|
+
const now = Date.now() / 1000;
|
|
394
|
+
return {
|
|
395
|
+
commitLoadTime: now - Math.random() * 2,
|
|
396
|
+
connectionInfo: 'h2',
|
|
397
|
+
finishDocumentLoadTime: now - Math.random(),
|
|
398
|
+
finishLoadTime: now - Math.random() * 0.5,
|
|
399
|
+
firstPaintAfterLoadTime: 0,
|
|
400
|
+
firstPaintTime: now - Math.random() * 1.5,
|
|
401
|
+
navigationType: 'Other',
|
|
402
|
+
npnNegotiatedProtocol: 'h2',
|
|
403
|
+
requestTime: now - Math.random() * 3,
|
|
404
|
+
startLoadTime: now - Math.random() * 2.5,
|
|
405
|
+
wasAlternateProtocolAvailable: false,
|
|
406
|
+
wasFetchedViaSpdy: true,
|
|
407
|
+
wasNpnNegotiated: true,
|
|
408
|
+
};
|
|
409
|
+
};
|
|
410
|
+
}
|
|
353
411
|
};
|
|
354
412
|
|
|
355
413
|
// 10. Device Memory Spoofing (2024-2025)
|
|
@@ -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
|
|
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"}
|