fpscanner 0.9.4 → 0.9.5-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 (36) hide show
  1. package/README.md +42 -15
  2. package/dist/detections/hasBotUserAgent.d.ts +3 -0
  3. package/dist/detections/hasBotUserAgent.d.ts.map +1 -0
  4. package/dist/detections/hasGPUMismatch.d.ts +3 -0
  5. package/dist/detections/hasGPUMismatch.d.ts.map +1 -0
  6. package/dist/detections/hasHeadlessChromeScreenResolution.d.ts.map +1 -1
  7. package/dist/detections/hasInconsistentEtsl.d.ts +3 -0
  8. package/dist/detections/hasInconsistentEtsl.d.ts.map +1 -0
  9. package/dist/detections/hasMismatchLanguages.d.ts +3 -0
  10. package/dist/detections/hasMismatchLanguages.d.ts.map +1 -0
  11. package/dist/detections/hasPlatformMismatch.d.ts +3 -0
  12. package/dist/detections/hasPlatformMismatch.d.ts.map +1 -0
  13. package/dist/fpScanner.cjs.js +2 -2
  14. package/dist/fpScanner.es.js +323 -223
  15. package/dist/index.d.ts +4 -4
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/signals/browserFeatures.d.ts +18 -0
  18. package/dist/signals/browserFeatures.d.ts.map +1 -1
  19. package/dist/signals/iframe.d.ts.map +1 -1
  20. package/dist/signals/worker.d.ts.map +1 -1
  21. package/dist/types.d.ts +23 -0
  22. package/dist/types.d.ts.map +1 -1
  23. package/package.json +6 -4
  24. package/scripts/safe-publish.js +111 -0
  25. package/src/detections/hasBotUserAgent.ts +11 -0
  26. package/src/detections/hasGPUMismatch.ts +25 -0
  27. package/src/detections/hasHeadlessChromeScreenResolution.ts +0 -3
  28. package/src/detections/hasImpossibleDeviceMemory.ts +1 -1
  29. package/src/detections/hasInconsistentEtsl.ts +21 -0
  30. package/src/detections/hasMismatchLanguages.ts +13 -0
  31. package/src/detections/hasPlatformMismatch.ts +46 -0
  32. package/src/index.ts +48 -5
  33. package/src/signals/browserFeatures.ts +37 -11
  34. package/src/signals/iframe.ts +9 -1
  35. package/src/signals/worker.ts +31 -8
  36. package/src/types.ts +23 -0
package/dist/index.d.ts CHANGED
@@ -12,10 +12,11 @@ declare class FingerprintScanner {
12
12
  * Bitmasks are extensible - new boolean fields are appended without breaking existing positions.
13
13
  *
14
14
  * Sections:
15
- * - det: fastBotDetectionDetails bitmask (14 bits: headlessChromeScreenResolution, hasWebdriver,
15
+ * - det: fastBotDetectionDetails bitmask (21 bits: headlessChromeScreenResolution, hasWebdriver,
16
16
  * hasWebdriverWritable, hasSeleniumProperty, hasCDP, hasPlaywright, hasImpossibleDeviceMemory,
17
17
  * hasHighCPUCount, hasMissingChromeObject, hasWebdriverIframe, hasWebdriverWorker,
18
- * hasMismatchWebGLInWorker, hasMismatchPlatformIframe, hasMismatchPlatformWorker)
18
+ * hasMismatchWebGLInWorker, hasMismatchPlatformIframe, hasMismatchPlatformWorker,
19
+ * hasMismatchLanguages, hasInconsistentEtsl, hasBotUserAgent, hasGPUMismatch, hasPlatformMismatch)
19
20
  * - auto: automation bitmask (5 bits: webdriver, webdriverWritable, selenium, cdp, playwright) + hash
20
21
  * - dev: WIDTHxHEIGHT + cpu + mem + device bitmask + hash of all device signals
21
22
  * - brw: features.bitmask + extensions.bitmask + plugins bitmask (3 bits) + hash of browser signals
@@ -28,8 +29,7 @@ declare class FingerprintScanner {
28
29
  private encryptFingerprint;
29
30
  /**
30
31
  * Detection rules with name and severity.
31
- * All rules are currently HIGH severity as they indicate bot-like behavior.
32
- */
32
+ */
33
33
  private getDetectionRules;
34
34
  private runDetectionRules;
35
35
  collectFingerprint(options?: CollectFingerprintOptions): Promise<string | Fingerprint>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAsDA,OAAO,EAAE,WAAW,EAA0C,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAGzG,cAAM,kBAAkB;IACpB,OAAO,CAAC,WAAW,CAAc;;YAiLnB,aAAa;IAQ3B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,4BAA4B;YA2LtB,kBAAkB;IAoBhC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,iBAAiB;IAiCnB,kBAAkB,CAAC,OAAO,GAAE,yBAA6C;CA0HlF;AAED,eAAe,kBAAkB,CAAC;AAClC,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2DA,OAAO,EAAE,WAAW,EAA0C,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAGzG,cAAM,kBAAkB;IACpB,OAAO,CAAC,WAAW,CAAc;;YAwMnB,aAAa;IAQ3B;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,OAAO,CAAC,4BAA4B;YAgMtB,kBAAkB;IAoBhC;;MAEE;IACF,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,iBAAiB;IAsCnB,kBAAkB,CAAC,OAAO,GAAE,yBAA6C;CA0HlF;AAED,eAAe,kBAAkB,CAAC;AAClC,cAAc,SAAS,CAAC"}
@@ -10,5 +10,23 @@ export declare function browserFeatures(): {
10
10
  webAssembly: boolean;
11
11
  buffer: boolean;
12
12
  showModalDialog: boolean;
13
+ safari: boolean;
14
+ webkitPrefixedFunction: boolean;
15
+ mozPrefixedFunction: boolean;
16
+ usb: boolean;
17
+ browserCapture: boolean;
18
+ paymentRequestUpdateEvent: boolean;
19
+ pressureObserver: boolean;
20
+ audioSession: boolean;
21
+ selectAudioOutput: boolean;
22
+ barcodeDetector: boolean;
23
+ battery: boolean;
24
+ devicePosture: boolean;
25
+ documentPictureInPicture: boolean;
26
+ eyeDropper: boolean;
27
+ editContext: boolean;
28
+ fencedFrame: boolean;
29
+ sanitizer: boolean;
30
+ otpCredential: boolean;
13
31
  };
14
32
  //# sourceMappingURL=browserFeatures.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"browserFeatures.d.ts","sourceRoot":"","sources":["../../src/signals/browserFeatures.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe;;;;;;;;;;;;EAqB9B"}
1
+ {"version":3,"file":"browserFeatures.d.ts","sourceRoot":"","sources":["../../src/signals/browserFeatures.ts"],"names":[],"mappings":"AAUA,wBAAgB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"iframe.d.ts","sourceRoot":"","sources":["../../src/signals/iframe.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM;;;;;;;EA+BrB"}
1
+ {"version":3,"file":"iframe.d.ts","sourceRoot":"","sources":["../../src/signals/iframe.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM;;;;;;;EAuCrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/signals/worker.ts"],"names":[],"mappings":"AAEA,wBAAsB,MAAM,qBA0E3B"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/signals/worker.ts"],"names":[],"mappings":"AAEA,wBAAsB,MAAM,qBAiG3B"}
package/dist/types.d.ts CHANGED
@@ -63,6 +63,24 @@ export interface BrowserFeaturesSignal {
63
63
  webAssembly: SignalValue<boolean>;
64
64
  buffer: SignalValue<boolean>;
65
65
  showModalDialog: SignalValue<boolean>;
66
+ safari: SignalValue<boolean>;
67
+ webkitPrefixedFunction: SignalValue<boolean>;
68
+ mozPrefixedFunction: SignalValue<boolean>;
69
+ usb: SignalValue<boolean>;
70
+ browserCapture: SignalValue<boolean>;
71
+ paymentRequestUpdateEvent: SignalValue<boolean>;
72
+ pressureObserver: SignalValue<boolean>;
73
+ audioSession: SignalValue<boolean>;
74
+ selectAudioOutput: SignalValue<boolean>;
75
+ barcodeDetector: SignalValue<boolean>;
76
+ battery: SignalValue<boolean>;
77
+ devicePosture: SignalValue<boolean>;
78
+ documentPictureInPicture: SignalValue<boolean>;
79
+ eyeDropper: SignalValue<boolean>;
80
+ editContext: SignalValue<boolean>;
81
+ fencedFrame: SignalValue<boolean>;
82
+ sanitizer: SignalValue<boolean>;
83
+ otpCredential: SignalValue<boolean>;
66
84
  }
67
85
  export interface MediaQueriesSignal {
68
86
  prefersColorScheme: SignalValue<string | null>;
@@ -179,6 +197,11 @@ export interface FastBotDetectionDetails {
179
197
  hasMismatchPlatformWorker: DetectionRuleResult;
180
198
  hasSwiftshaderRenderer: DetectionRuleResult;
181
199
  hasUTCTimezone: DetectionRuleResult;
200
+ hasMismatchLanguages: DetectionRuleResult;
201
+ hasInconsistentEtsl: DetectionRuleResult;
202
+ hasBotUserAgent: DetectionRuleResult;
203
+ hasGPUMismatch: DetectionRuleResult;
204
+ hasPlatformMismatch: DetectionRuleResult;
182
205
  }
183
206
  export interface Fingerprint {
184
207
  signals: FingerprintSignals;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fpscanner",
3
- "version": "0.9.4",
3
+ "version": "0.9.5-beta.1",
4
4
  "description": "A lightweight browser fingerprinting and bot detection library with encryption, obfuscation, and cross-context validation",
5
5
  "main": "dist/fpScanner.cjs.js",
6
6
  "module": "dist/fpScanner.es.js",
@@ -29,7 +29,9 @@
29
29
  "test:vitest": "vitest",
30
30
  "test:playwright": "npm run build:obfuscate && npx playwright test",
31
31
  "test:playwright:headed": "npm run build:obfuscate && npx playwright test --headed",
32
- "prepublishOnly": "node scripts/verify-publish.js"
32
+ "prepublishOnly": "node scripts/verify-publish.js",
33
+ "publish:beta": "node scripts/safe-publish.js beta",
34
+ "publish:stable": "node scripts/safe-publish.js stable"
33
35
  },
34
36
  "repository": {
35
37
  "type": "git",
@@ -58,9 +60,9 @@
58
60
  },
59
61
  "homepage": "https://github.com/antoinevastel/fpscanner",
60
62
  "dependencies": {
61
- "ua-parser-js": "^0.7.18",
62
63
  "javascript-obfuscator": "^5.1.0",
63
- "terser": "^5.46.0"
64
+ "terser": "^5.46.0",
65
+ "ua-parser-js": "^0.7.18"
64
66
  },
65
67
  "devDependencies": {
66
68
  "@playwright/test": "^1.57.0",
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execSync } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ const publishType = process.argv[2]; // 'beta' or 'stable'
8
+
9
+ if (!publishType || !['beta', 'stable'].includes(publishType)) {
10
+ console.error('❌ Usage: npm run publish:beta or npm run publish:stable');
11
+ process.exit(1);
12
+ }
13
+
14
+ const ROOT_DIR = path.resolve(__dirname, '..');
15
+ const DIST_DIR = path.join(ROOT_DIR, 'dist');
16
+
17
+ function run(command, description) {
18
+ console.log(`\n🔄 ${description}...`);
19
+ try {
20
+ execSync(command, { cwd: ROOT_DIR, stdio: 'inherit' });
21
+ console.log(`✅ ${description} - Done`);
22
+ } catch (error) {
23
+ console.error(`❌ ${description} - Failed`);
24
+ process.exit(1);
25
+ }
26
+ }
27
+
28
+ function checkGitStatus() {
29
+ console.log('\n🔍 Checking git status...');
30
+ try {
31
+ const status = execSync('git status --porcelain', { cwd: ROOT_DIR, encoding: 'utf8' });
32
+ if (status.trim()) {
33
+ console.error('❌ Git working directory is not clean. Please commit or stash changes first.');
34
+ console.error('\nUncommitted changes:');
35
+ console.error(status);
36
+ process.exit(1);
37
+ }
38
+ console.log('✅ Git working directory is clean');
39
+ } catch (error) {
40
+ console.error('❌ Failed to check git status');
41
+ process.exit(1);
42
+ }
43
+ }
44
+
45
+ function getPackageVersion() {
46
+ const packageJson = require(path.join(ROOT_DIR, 'package.json'));
47
+ return packageJson.version;
48
+ }
49
+
50
+ console.log('═══════════════════════════════════════════════════════════');
51
+ console.log(`🚀 Safe Publish Script - ${publishType.toUpperCase()}`);
52
+ console.log('═══════════════════════════════════════════════════════════');
53
+
54
+ // Step 0: Check git status
55
+ checkGitStatus();
56
+
57
+ // Step 1: Clean dist directory
58
+ console.log('\n🧹 Cleaning dist directory...');
59
+ if (fs.existsSync(DIST_DIR)) {
60
+ fs.rmSync(DIST_DIR, { recursive: true, force: true });
61
+ console.log('✅ Dist directory cleaned');
62
+ } else {
63
+ console.log('✅ Dist directory already clean');
64
+ }
65
+
66
+ // Step 2: Build package with sentinel key (no key injection)
67
+ run('npm run build', 'Building package with sentinel key');
68
+
69
+ // Step 3: Verify build
70
+ run('node scripts/verify-publish.js', 'Verifying build integrity');
71
+
72
+ // Step 4: Get version and confirm
73
+ const version = getPackageVersion();
74
+ console.log(`\n📦 Package version: ${version}`);
75
+
76
+ if (publishType === 'beta' && !version.includes('beta')) {
77
+ console.error(`❌ Version ${version} is not a beta version. Use publish:stable instead.`);
78
+ process.exit(1);
79
+ }
80
+
81
+ if (publishType === 'stable' && version.includes('beta')) {
82
+ console.error(`❌ Version ${version} is a beta version. Use publish:beta instead.`);
83
+ process.exit(1);
84
+ }
85
+
86
+ // Step 5: Publish
87
+ const publishTag = publishType === 'beta' ? '--tag beta' : '';
88
+ run(`npm publish ${publishTag}`, `Publishing to npm with ${publishType} tag`);
89
+
90
+ // Step 6: Create git tag
91
+ const gitTag = `v${version}`;
92
+ console.log(`\n🏷️ Creating git tag: ${gitTag}...`);
93
+ try {
94
+ execSync(`git tag ${gitTag}`, { cwd: ROOT_DIR, stdio: 'inherit' });
95
+ console.log(`✅ Git tag created: ${gitTag}`);
96
+
97
+ console.log('\n💡 Don\'t forget to push the tag:');
98
+ console.log(` git push origin ${gitTag}`);
99
+ } catch (error) {
100
+ console.log(`⚠️ Git tag might already exist: ${gitTag}`);
101
+ }
102
+
103
+ console.log('\n═══════════════════════════════════════════════════════════');
104
+ console.log('✅ PUBLISH SUCCESSFUL!');
105
+ console.log('═══════════════════════════════════════════════════════════');
106
+ console.log(`\n📦 Published: fpscanner@${version}`);
107
+ console.log(`🏷️ Tag: ${publishType}`);
108
+ console.log('\n📝 Next steps:');
109
+ console.log(` 1. Push git tag: git push origin ${gitTag}`);
110
+ console.log(` 2. Test installation: npm install fpscanner@${publishType}`);
111
+ console.log('═══════════════════════════════════════════════════════════\n');
@@ -0,0 +1,11 @@
1
+ import { Fingerprint } from "../types";
2
+
3
+ export function hasBotUserAgent(fingerprint: Fingerprint) {
4
+ const userAgents = [
5
+ fingerprint.signals.browser.userAgent,
6
+ fingerprint.signals.contexts.iframe.userAgent,
7
+ fingerprint.signals.contexts.webWorker.userAgent,
8
+ ];
9
+
10
+ return userAgents.some(userAgent => /bot|headless/i.test(userAgent.toLowerCase()));
11
+ }
@@ -0,0 +1,25 @@
1
+ import { Fingerprint } from "../types";
2
+
3
+ // For the moment, we only detect GPU mismatches related to Apple OS/GPU
4
+
5
+ export function hasGPUMismatch(fingerprint: Fingerprint) {
6
+ const gpu = fingerprint.signals.graphics.webgpu;
7
+ const webGL = fingerprint.signals.graphics.webGL;
8
+ const userAgent = fingerprint.signals.browser.userAgent;
9
+
10
+
11
+ // Inconsistencies around Apple OS/GPU
12
+ if ((webGL.vendor.includes('Apple') || webGL.renderer.includes('Apple')) && !userAgent.includes('Mac')) {
13
+ return true;
14
+ }
15
+
16
+ if (gpu.vendor.includes('apple') && !userAgent.includes('Mac')) {
17
+ return true;
18
+ }
19
+
20
+ if (gpu.vendor.includes('apple') && !webGL.renderer.includes('Apple')) {
21
+ return true;
22
+ }
23
+
24
+ return false;
25
+ }
@@ -2,9 +2,6 @@ import { Fingerprint } from '../types';
2
2
 
3
3
  export function hasHeadlessChromeScreenResolution(fingerprint: Fingerprint) {
4
4
  const screen = fingerprint.signals.device.screenResolution;
5
- if (typeof screen.width !== 'number' || typeof screen.height !== 'number') {
6
- return false;
7
- }
8
5
 
9
6
  return (screen.width === 600 && screen.height === 800) || (screen.availableWidth === 600 && screen.availableHeight === 800) || (screen.innerWidth === 600 && screen.innerHeight === 800);
10
7
  }
@@ -5,5 +5,5 @@ export function hasImpossibleDeviceMemory(fingerprint: Fingerprint) {
5
5
  return false;
6
6
  }
7
7
 
8
- return (fingerprint.signals.device.memory > 8 || fingerprint.signals.device.memory < 0.25);
8
+ return (fingerprint.signals.device.memory > 32 || fingerprint.signals.device.memory < 0.25);
9
9
  }
@@ -0,0 +1,21 @@
1
+ import { Fingerprint } from "../types";
2
+
3
+ export function hasInconsistentEtsl(fingerprint: Fingerprint) {
4
+
5
+ // On Chromium-based browsers, ETSL should be 33
6
+ if (fingerprint.signals.browser.features.chrome && fingerprint.signals.browser.etsl !== 33) {
7
+ return true;
8
+ }
9
+
10
+ // On Safari, ETSL should be 37
11
+ if (fingerprint.signals.browser.features.safari && fingerprint.signals.browser.etsl !== 37) {
12
+ return true;
13
+ }
14
+
15
+ // On Firefox, ETSL should be 37
16
+ if (fingerprint.signals.browser.userAgent.includes('Firefox') && fingerprint.signals.browser.etsl !== 37) {
17
+ return true;
18
+ }
19
+
20
+ return false;
21
+ }
@@ -0,0 +1,13 @@
1
+ import { Fingerprint } from "../types";
2
+
3
+ export function hasMismatchLanguages(fingerprint: Fingerprint) {
4
+ const languages = fingerprint.signals.locale.languages.languages;
5
+ const language = fingerprint.signals.locale.languages.language;
6
+
7
+
8
+ if (language && languages && Array.isArray(languages) && languages.length > 0) {
9
+ return languages[0] !== language;
10
+ }
11
+
12
+ return false;
13
+ }
@@ -0,0 +1,46 @@
1
+ import { Fingerprint } from "../types";
2
+ import { ERROR, NA } from "../signals/utils";
3
+
4
+ export function hasPlatformMismatch(fingerprint: Fingerprint) {
5
+ const platform = fingerprint.signals.device.platform;
6
+ const userAgent = fingerprint.signals.browser.userAgent;
7
+ const highEntropyPlatform = fingerprint.signals.browser.highEntropyValues.platform;
8
+
9
+ if (userAgent.includes('Mac') && !platform.includes('Mac')) {
10
+ return true;
11
+ }
12
+
13
+ if (userAgent.includes('Windows') && !platform.includes('Win')) {
14
+ return true;
15
+ }
16
+
17
+ if (userAgent.includes('Linux') && !platform.includes('Linux')) {
18
+ return true;
19
+ }
20
+
21
+
22
+ // Check applied only if highEntropyPlatform is not ERROR or NA
23
+ if (highEntropyPlatform !== ERROR && highEntropyPlatform !== NA) {
24
+ if (highEntropyPlatform.includes('Mac') && !platform.includes('Mac')) {
25
+ return true;
26
+ }
27
+
28
+ if (highEntropyPlatform.includes('Windows') && !platform.includes('Win')) {
29
+ return true;
30
+ }
31
+
32
+ if (highEntropyPlatform.includes('Linux') && !platform.includes('Linux')) {
33
+ return true;
34
+ }
35
+
36
+ if (highEntropyPlatform.includes('Android') && !platform.includes('Android')) {
37
+ return true;
38
+ }
39
+
40
+ if (highEntropyPlatform.includes('iOS') && !platform.includes('iOS')) {
41
+ return true;
42
+ }
43
+ }
44
+
45
+ return false;
46
+ }
package/src/index.ts CHANGED
@@ -49,6 +49,11 @@ import { hasMismatchPlatformIframe } from './detections/hasMismatchPlatformIfram
49
49
  import { hasWebdriverWritable } from './detections/hasWebdriverWritable';
50
50
  import { hasSwiftshaderRenderer } from './detections/hasSwiftshaderRenderer';
51
51
  import { hasUTCTimezone } from './detections/hasUTCTimezone';
52
+ import { hasMismatchLanguages } from './detections/hasMismatchLanguages';
53
+ import { hasInconsistentEtsl } from './detections/hasInconsistentEtsl';
54
+ import { hasBotUserAgent } from './detections/hasBotUserAgent';
55
+ import { hasGPUMismatch } from './detections/hasGPUMismatch';
56
+ import { hasPlatformMismatch } from './detections/hasPlatformMismatch';
52
57
 
53
58
  import { ERROR, HIGH, INIT, LOW, MEDIUM, SKIPPED, hashCode } from './signals/utils';
54
59
  import { encryptString } from './crypto-helpers';
@@ -118,6 +123,24 @@ class FingerprintScanner {
118
123
  webAssembly: INIT,
119
124
  buffer: INIT,
120
125
  showModalDialog: INIT,
126
+ safari: INIT,
127
+ webkitPrefixedFunction: INIT,
128
+ mozPrefixedFunction: INIT,
129
+ usb: INIT,
130
+ browserCapture: INIT,
131
+ paymentRequestUpdateEvent: INIT,
132
+ pressureObserver: INIT,
133
+ audioSession: INIT,
134
+ selectAudioOutput: INIT,
135
+ barcodeDetector: INIT,
136
+ battery: INIT,
137
+ devicePosture: INIT,
138
+ documentPictureInPicture: INIT,
139
+ eyeDropper: INIT,
140
+ editContext: INIT,
141
+ fencedFrame: INIT,
142
+ sanitizer: INIT,
143
+ otpCredential: INIT,
121
144
  },
122
145
  plugins: {
123
146
  isValidPluginArray: INIT,
@@ -229,6 +252,11 @@ class FingerprintScanner {
229
252
  hasMismatchPlatformWorker: { detected: false, severity: 'high' },
230
253
  hasSwiftshaderRenderer: { detected: false, severity: 'low' },
231
254
  hasUTCTimezone: { detected: false, severity: 'medium' },
255
+ hasMismatchLanguages: { detected: false, severity: 'low' },
256
+ hasInconsistentEtsl: { detected: false, severity: 'high' },
257
+ hasBotUserAgent: { detected: false, severity: 'high' },
258
+ hasGPUMismatch: { detected: false, severity: 'high' },
259
+ hasPlatformMismatch: { detected: false, severity: 'high' },
232
260
  },
233
261
  };
234
262
  }
@@ -250,10 +278,11 @@ class FingerprintScanner {
250
278
  * Bitmasks are extensible - new boolean fields are appended without breaking existing positions.
251
279
  *
252
280
  * Sections:
253
- * - det: fastBotDetectionDetails bitmask (14 bits: headlessChromeScreenResolution, hasWebdriver,
281
+ * - det: fastBotDetectionDetails bitmask (21 bits: headlessChromeScreenResolution, hasWebdriver,
254
282
  * hasWebdriverWritable, hasSeleniumProperty, hasCDP, hasPlaywright, hasImpossibleDeviceMemory,
255
283
  * hasHighCPUCount, hasMissingChromeObject, hasWebdriverIframe, hasWebdriverWorker,
256
- * hasMismatchWebGLInWorker, hasMismatchPlatformIframe, hasMismatchPlatformWorker)
284
+ * hasMismatchWebGLInWorker, hasMismatchPlatformIframe, hasMismatchPlatformWorker,
285
+ * hasMismatchLanguages, hasInconsistentEtsl, hasBotUserAgent, hasGPUMismatch, hasPlatformMismatch)
257
286
  * - auto: automation bitmask (5 bits: webdriver, webdriverWritable, selenium, cdp, playwright) + hash
258
287
  * - dev: WIDTHxHEIGHT + cpu + mem + device bitmask + hash of all device signals
259
288
  * - brw: features.bitmask + extensions.bitmask + plugins bitmask (3 bits) + hash of browser signals
@@ -270,7 +299,7 @@ class FingerprintScanner {
270
299
  // Section 1: Version
271
300
  const version = 'FS1';
272
301
 
273
- // Section 2: Detection bitmask - all 14 fastBotDetectionDetails booleans
302
+ // Section 2: Detection bitmask - all 21 fastBotDetectionDetails booleans
274
303
  // Order matches FastBotDetectionDetails interface for consistency
275
304
  const detBitmask = [
276
305
  det.headlessChromeScreenResolution.detected,
@@ -289,6 +318,11 @@ class FingerprintScanner {
289
318
  det.hasMismatchPlatformWorker.detected,
290
319
  det.hasSwiftshaderRenderer.detected,
291
320
  det.hasUTCTimezone.detected,
321
+ det.hasMismatchLanguages.detected,
322
+ det.hasInconsistentEtsl.detected,
323
+ det.hasBotUserAgent.detected,
324
+ det.hasGPUMismatch.detected,
325
+ det.hasPlatformMismatch.detected,
292
326
  // Add other detection rules output here
293
327
  ].map(b => b ? '1' : '0').join('');
294
328
  const detSection = detBitmask;
@@ -471,8 +505,7 @@ class FingerprintScanner {
471
505
 
472
506
  /**
473
507
  * Detection rules with name and severity.
474
- * All rules are currently HIGH severity as they indicate bot-like behavior.
475
- */
508
+ */
476
509
  private getDetectionRules(): DetectionRule[] {
477
510
  return [
478
511
  { name: 'headlessChromeScreenResolution', severity: HIGH, test: hasHeadlessChromeScreenResolution },
@@ -491,6 +524,11 @@ class FingerprintScanner {
491
524
  { name: 'hasMismatchPlatformWorker', severity: HIGH, test: hasMismatchPlatformWorker },
492
525
  { name: 'hasSwiftshaderRenderer', severity: LOW, test: hasSwiftshaderRenderer },
493
526
  { name: 'hasUTCTimezone', severity: MEDIUM, test: hasUTCTimezone },
527
+ { name: 'hasMismatchLanguages', severity: LOW, test: hasMismatchLanguages },
528
+ { name: 'hasInconsistentEtsl', severity: HIGH, test: hasInconsistentEtsl },
529
+ { name: 'hasBotUserAgent', severity: HIGH, test: hasBotUserAgent },
530
+ { name: 'hasGPUMismatch', severity: HIGH, test: hasGPUMismatch },
531
+ { name: 'hasPlatformMismatch', severity: HIGH, test: hasPlatformMismatch },
494
532
  ];
495
533
  }
496
534
 
@@ -513,6 +551,11 @@ class FingerprintScanner {
513
551
  hasMismatchPlatformWorker: { detected: false, severity: 'high' },
514
552
  hasSwiftshaderRenderer: { detected: false, severity: 'low' },
515
553
  hasUTCTimezone: { detected: false, severity: 'medium' },
554
+ hasMismatchLanguages: { detected: false, severity: 'low' },
555
+ hasInconsistentEtsl: { detected: false, severity: 'high' },
556
+ hasBotUserAgent: { detected: false, severity: 'high' },
557
+ hasGPUMismatch: { detected: false, severity: 'high' },
558
+ hasPlatformMismatch: { detected: false, severity: 'high' },
516
559
  };
517
560
 
518
561
  for (const rule of rules) {
@@ -1,19 +1,45 @@
1
1
  import { INIT } from "./utils";
2
2
 
3
+ function safeCheck(check: () => boolean): boolean {
4
+ try {
5
+ return check();
6
+ } catch {
7
+ return false;
8
+ }
9
+ }
10
+
3
11
  export function browserFeatures() {
4
12
  const browserFeaturesData = {
5
13
  bitmask: INIT,
6
- chrome: 'chrome' in window,
7
- brave: 'brave' in navigator,
8
- applePaySupport: 'ApplePaySetup' in window,
9
- opera: (typeof (window as any).opr !== "undefined") ||
10
- (typeof (window as any).onoperadetachedviewchange === "object"),
11
- serial: (window.navigator as any).serial !== undefined,
12
- attachShadow: !!Element.prototype.attachShadow,
13
- caches: !!window.caches,
14
- webAssembly: !!window.WebAssembly && !!window.WebAssembly.instantiate,
15
- buffer: 'Buffer' in window,
16
- showModalDialog: 'showModalDialog' in window,
14
+ chrome: safeCheck(() => 'chrome' in window),
15
+ brave: safeCheck(() => 'brave' in navigator),
16
+ applePaySupport: safeCheck(() => 'ApplePaySetup' in window),
17
+ opera: safeCheck(() => (typeof (window as any).opr !== "undefined") ||
18
+ (typeof (window as any).onoperadetachedviewchange === "object")),
19
+ serial: safeCheck(() => (window.navigator as any).serial !== undefined),
20
+ attachShadow: safeCheck(() => !!Element.prototype.attachShadow),
21
+ caches: safeCheck(() => !!window.caches),
22
+ webAssembly: safeCheck(() => !!window.WebAssembly && !!window.WebAssembly.instantiate),
23
+ buffer: safeCheck(() => 'Buffer' in window),
24
+ showModalDialog: safeCheck(() => 'showModalDialog' in window),
25
+ safari: safeCheck(() => 'safari' in window),
26
+ webkitPrefixedFunction: safeCheck(() => 'webkitCancelAnimationFrame' in window),
27
+ mozPrefixedFunction: safeCheck(() => 'mozGetUserMedia' in navigator),
28
+ usb: safeCheck(() => typeof (window as any).USB === 'function'),
29
+ browserCapture: safeCheck(() => typeof (window as any).BrowserCaptureMediaStreamTrack === 'function'),
30
+ paymentRequestUpdateEvent: safeCheck(() => typeof (window as any).PaymentRequestUpdateEvent === 'function'),
31
+ pressureObserver: safeCheck(() => typeof (window as any).PressureObserver === 'function'),
32
+ audioSession: safeCheck(() => 'audioSession' in navigator),
33
+ selectAudioOutput: safeCheck(() => typeof navigator !== 'undefined' && typeof navigator.mediaDevices !== 'undefined' && typeof (navigator.mediaDevices as any).selectAudioOutput === 'function'),
34
+ barcodeDetector: safeCheck(() => 'BarcodeDetector' in window),
35
+ battery: safeCheck(() => 'getBattery' in navigator),
36
+ devicePosture: safeCheck(() => 'DevicePosture' in window),
37
+ documentPictureInPicture: safeCheck(() => 'documentPictureInPicture' in window),
38
+ eyeDropper: safeCheck(() => 'EyeDropper' in window),
39
+ editContext: safeCheck(() => 'EditContext' in window),
40
+ fencedFrame: safeCheck(() => 'FencedFrameConfig' in window),
41
+ sanitizer: safeCheck(() => 'Sanitizer' in window),
42
+ otpCredential: safeCheck(() => 'OTPCredential' in window),
17
43
  };
18
44
 
19
45
  // set bitmask to 0/1 string based on browserFeaturesData, exclude bitmask property itself (you need to filter on the key)
@@ -10,11 +10,13 @@ export function iframe() {
10
10
  language: INIT,
11
11
  };
12
12
  const iframe = document.createElement('iframe');
13
+ let iframeAdded = false;
13
14
 
14
15
  try {
15
16
  iframe.style.display = 'none';
16
17
  iframe.src = 'about:blank';
17
18
  document.body.appendChild(iframe);
19
+ iframeAdded = true;
18
20
 
19
21
  const iframeWindowNavigator = (iframe.contentWindow?.navigator as any);
20
22
 
@@ -27,7 +29,13 @@ export function iframe() {
27
29
  } catch (e) {
28
30
  setObjectValues(iframeData, ERROR);
29
31
  } finally {
30
- document.body.removeChild(iframe);
32
+ if (iframeAdded) {
33
+ try {
34
+ document.body.removeChild(iframe);
35
+ } catch (_) {
36
+ // Ignore removal errors
37
+ }
38
+ }
31
39
  }
32
40
 
33
41
  return iframeData;