diff --git a/inject.js b/inject.js index 88f444e..9744cfe 100644 --- a/inject.js +++ b/inject.js @@ -155,7 +155,10 @@ hardwareConcurrency: CONFIG.nav.hardwareConcurrency, platform: CONFIG.nav.platform, deviceMemory: CONFIG.nav.deviceMemory, - maxTouchPoints: CONFIG.nav.maxTouchPoints + maxTouchPoints: CONFIG.nav.maxTouchPoints, + userAgent: CONFIG.nav.userAgent, + appVersion: CONFIG.nav.appVersion, + oscpu: CONFIG.nav.oscpu }; for (const [prop, value] of Object.entries(navOverrides)) { diff --git a/lib/fingerprint-gen.js b/lib/fingerprint-gen.js index 9ab76fa..b3ae390 100644 --- a/lib/fingerprint-gen.js +++ b/lib/fingerprint-gen.js @@ -1,5 +1,6 @@ // Deterministic fingerprint profile generator // Given the same seed, always produces the same device identity +// Profiles are coherent — platform, UA, GPU, resolution all match // Real hardware values — spoofed values must NEVER match these const REAL_HARDWARE = { @@ -8,6 +9,112 @@ const REAL_HARDWARE = { screenHeight: 1080 }; +// --- Device Archetypes --- +// Each archetype defines a coherent set of values for a device class + +const DEVICE_ARCHETYPES = [ + // Windows desktops + { + platform: "Win32", + uaTemplate: "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/{ffVersion}", + appVersionTemplate: "5.0 (Windows)", + oscpu: "Windows NT 10.0; Win64; x64", + vendors: ["Google Inc. (NVIDIA)", "Google Inc. (AMD)", "Google Inc. (Intel)"], + renderers: [ + "ANGLE (NVIDIA GeForce GTX 1060 Direct3D11 vs_5_0 ps_5_0)", + "ANGLE (NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0)", + "ANGLE (AMD Radeon RX 580 Direct3D11 vs_5_0 ps_5_0)", + "ANGLE (AMD Radeon RX 6700 XT Direct3D11 vs_5_0 ps_5_0)", + "ANGLE (Intel HD Graphics 630 Direct3D11 vs_5_0 ps_5_0)" + ], + resolutions: [ + { width: 2560, height: 1440 }, + { width: 1366, height: 768 }, + { width: 1536, height: 864 }, + { width: 1680, height: 1050 }, + { width: 2560, height: 1080 }, + { width: 3440, height: 1440 }, + { width: 1600, height: 900 } + ], + cores: [4, 6, 8, 12, 16], + memory: [8, 16, 32] + }, + // Linux desktops + { + platform: "Linux x86_64", + uaTemplate: "Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/{ffVersion}", + appVersionTemplate: "5.0 (X11)", + oscpu: "Linux x86_64", + vendors: ["Google Inc. (AMD)", "Google Inc. (Intel)", "Google Inc."], + renderers: [ + "Mesa Intel(R) UHD Graphics 620", + "Mesa AMD Radeon RX 580", + "ANGLE (Intel, Mesa Intel(R) UHD Graphics 620, OpenGL 4.6)", + "Mesa Intel(R) HD Graphics 530", + "AMD Radeon RX 6600 (radeonsi, navi23, LLVM 15.0.7, DRM 3.49)" + ], + resolutions: [ + { width: 2560, height: 1440 }, + { width: 1366, height: 768 }, + { width: 1536, height: 864 }, + { width: 1440, height: 900 }, + { width: 3440, height: 1440 }, + { width: 1600, height: 900 } + ], + cores: [2, 6, 8, 12, 16], + memory: [4, 8, 16, 32] + }, + // macOS desktops + { + platform: "MacIntel", + uaTemplate: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:128.0) Gecko/20100101 Firefox/{ffVersion}", + appVersionTemplate: "5.0 (Macintosh)", + oscpu: "Intel Mac OS X 10.15", + vendors: ["Google Inc. (Apple)", "Google Inc. (Intel)", "Google Inc."], + renderers: [ + "ANGLE (Apple, Apple M1, OpenGL 4.1)", + "ANGLE (Apple, Apple M2, OpenGL 4.1)", + "ANGLE (Intel, Intel(R) Iris(TM) Plus Graphics 655, OpenGL 4.1)", + "ANGLE (Apple, ANGLE Metal Renderer: Apple M1 Pro, OpenGL 4.1)" + ], + resolutions: [ + { width: 2560, height: 1440 }, + { width: 1440, height: 900 }, + { width: 1680, height: 1050 }, + { width: 2560, height: 1600 }, + { width: 3024, height: 1964 } + ], + cores: [4, 8, 10, 12], + memory: [8, 16, 32] + } +]; + +const FIREFOX_VERSIONS = ["126.0", "127.0", "128.0", "129.0", "130.0", "131.0", "132.0", "133.0", "134.0"]; + +const LANGUAGE_SETS = [ + ["en-US", "en"], + ["en-GB", "en"], + ["en-US"], + ["de-DE", "de", "en-US", "en"], + ["fr-FR", "fr", "en-US", "en"] +]; + +const COLOR_DEPTHS = [24, 30, 32]; + +const TIMEZONES = [ + { name: "America/New_York", offset: 300 }, + { name: "America/Chicago", offset: 360 }, + { name: "America/Denver", offset: 420 }, + { name: "America/Los_Angeles", offset: 480 }, + { name: "Europe/London", offset: 0 }, + { name: "Europe/Berlin", offset: -60 }, + { name: "Europe/Paris", offset: -60 }, + { name: "Asia/Tokyo", offset: -540 }, + { name: "Australia/Sydney", offset: -660 }, + { name: "America/Toronto", offset: 300 }, + { name: "America/Phoenix", offset: 420 } +]; + function generateFingerprintProfile(masterSeed) { const rng = mulberry32(masterSeed); @@ -15,14 +122,8 @@ function generateFingerprintProfile(masterSeed) { return arr[Math.floor(rng() * arr.length)]; } - // Pick from array, but never the excluded value. Rerolls if needed. - function pickExcluding(arr, exclude) { - const filtered = arr.filter(v => { - if (typeof exclude === "object" && exclude !== null) { - return Object.keys(exclude).some(k => v[k] !== exclude[k]); - } - return v !== exclude; - }); + function pickExcluding(arr, excludeFn) { + const filtered = arr.filter(excludeFn); return filtered.length > 0 ? pick(filtered) : pick(arr); } @@ -30,67 +131,19 @@ function generateFingerprintProfile(masterSeed) { return (rng() * 0xFFFFFFFF) >>> 0; } - const platforms = ["Win32", "Linux x86_64", "MacIntel"]; + // Pick a device archetype + const arch = pick(DEVICE_ARCHETYPES); - const vendors = [ - "Google Inc. (NVIDIA)", - "Google Inc. (AMD)", - "Google Inc. (Intel)", - "Google Inc." - ]; + // Pick coherent values from within the archetype + const res = pickExcluding(arch.resolutions, r => + r.width !== REAL_HARDWARE.screenWidth || r.height !== REAL_HARDWARE.screenHeight + ); - const renderers = [ - "ANGLE (NVIDIA GeForce GTX 1060 Direct3D11 vs_5_0 ps_5_0)", - "ANGLE (AMD Radeon RX 580 Direct3D11 vs_5_0 ps_5_0)", - "ANGLE (Intel HD Graphics 630 Direct3D11 vs_5_0 ps_5_0)", - "ANGLE (NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0)", - "ANGLE (AMD Radeon RX 6700 XT Direct3D11 vs_5_0 ps_5_0)", - "Mesa Intel(R) UHD Graphics 620", - "Mesa AMD Radeon RX 580", - "ANGLE (Intel, Mesa Intel(R) UHD Graphics 620, OpenGL 4.6)" - ]; + const cores = pickExcluding(arch.cores, c => c !== REAL_HARDWARE.hardwareConcurrency); - const resolutions = [ - { width: 2560, height: 1440 }, - { width: 1366, height: 768 }, - { width: 1536, height: 864 }, - { width: 1440, height: 900 }, - { width: 1680, height: 1050 }, - { width: 2560, height: 1080 }, - { width: 3440, height: 1440 }, - { width: 1600, height: 900 } - ]; - - const languageSets = [ - ["en-US", "en"], - ["en-GB", "en"], - ["en-US"], - ["de-DE", "de", "en-US", "en"], - ["fr-FR", "fr", "en-US", "en"] - ]; - - // Exclude real hardwareConcurrency (4) - const hardwareConcurrencies = [2, 6, 8, 12, 16]; - const deviceMemories = [4, 8, 16, 32]; - const colorDepths = [24, 30, 32]; - - // Timezones for spoofing — common real-world timezones - const timezones = [ - { name: "America/New_York", offset: 300 }, - { name: "America/Chicago", offset: 360 }, - { name: "America/Denver", offset: 420 }, - { name: "America/Los_Angeles", offset: 480 }, - { name: "Europe/London", offset: 0 }, - { name: "Europe/Berlin", offset: -60 }, - { name: "Europe/Paris", offset: -60 }, - { name: "Asia/Tokyo", offset: -540 }, - { name: "Australia/Sydney", offset: -660 }, - { name: "America/Toronto", offset: 300 }, - { name: "America/Phoenix", offset: 420 } - ]; - - // Resolution: never match real 1920x1080 - const res = pickExcluding(resolutions, { width: REAL_HARDWARE.screenWidth, height: REAL_HARDWARE.screenHeight }); + const ffVersion = pick(FIREFOX_VERSIONS); + const userAgent = arch.uaTemplate.replace("{ffVersion}", ffVersion); + const appVersion = arch.appVersionTemplate; return { seed: masterSeed, @@ -99,22 +152,25 @@ function generateFingerprintProfile(masterSeed) { fontSeed: subSeed(), rectSeed: subSeed(), nav: { - hardwareConcurrency: pick(hardwareConcurrencies), - platform: pick(platforms), - languages: pick(languageSets), - deviceMemory: pick(deviceMemories), - maxTouchPoints: 0 + hardwareConcurrency: cores, + platform: arch.platform, + languages: pick(LANGUAGE_SETS), + deviceMemory: pick(arch.memory), + maxTouchPoints: 0, + userAgent: userAgent, + appVersion: appVersion, + oscpu: arch.oscpu }, screen: { width: res.width, height: res.height, - colorDepth: pick(colorDepths) + colorDepth: pick(COLOR_DEPTHS) }, webgl: { - vendor: pick(vendors), - renderer: pick(renderers) + vendor: pick(arch.vendors), + renderer: pick(arch.renderers) }, - timezone: pick(timezones), + timezone: pick(TIMEZONES), webrtc: { blockLocal: true }