import path from 'path'; import {fileURLToPath} from 'url'; import crypto from 'crypto'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // 操作系统 const osList = [ { name: 'Windows', versions: ['10.0', '11.0'], platforms: ['Win32', 'Win64', 'x64'] }, { name: 'Macintosh', versions: ['Intel Mac OS X 10_15_7', 'Intel Mac OS X 11_6_0', 'Intel Mac OS X 12_3_1', 'Apple Mac OS X 13_2_1'], platforms: ['MacIntel'] }, { name: 'Linux', versions: ['x86_64', 'i686'], platforms: ['Linux x86_64', 'Linux i686'] }, { name: 'Android', versions: ['11', '12', '13', '14'], platforms: ['Android'] }, { name: 'iOS', versions: ['15_4', '16_2', '17_0'], platforms: ['iPhone', 'iPad'] } ]; // 浏览器 const browserVersions = { 'chrome': { name: 'Chrome', // 主版本.次版本.构建号.补丁号 majorVersions: [120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134], minorVersions: [0, 1, 2, 3], buildVersions: [5000, 5500, 6000, 6500, 6700, 6800, 6900, 7000, 7100], patchVersions: [80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200], brandName: "Google Chrome", brandVersion: "1.0.0.0", fullVersion: "1.0.0.0", }, 'edge': { name: 'Edge', majorVersions: [120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134], minorVersions: [0, 1, 2, 3], buildVersions: [5000, 5500, 6000, 6500, 6700, 6800, 6900, 7000, 7100], patchVersions: [80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200], brandName: "Microsoft Edge", brandVersion: "1.0.0.0", fullVersion: "1.0.0.0", }, 'firefox': { name: 'Firefox', majorVersions: [120, 121, 122, 123, 124], minorVersions: [0, 1, 2], buildVersions: [], patchVersions: [], brandName: "Firefox", brandVersion: "1.0", fullVersion: "1.0", }, 'safari': { name: 'Safari', majorVersions: [15, 16, 17], minorVersions: [0, 1, 2, 3, 4, 5, 6], buildVersions: [], patchVersions: [], brandName: "Safari", brandVersion: "1.0.0", fullVersion: "1.0.0", }, 'opera': { name: 'Opera', majorVersions: [96, 97, 98, 99, 100, 101], minorVersions: [0, 1, 2, 3], buildVersions: [1000, 2000, 3000, 4000], patchVersions: [10, 20, 30, 40, 50], brandName: "Opera", brandVersion: "1.0.0.0", fullVersion: "1.0.0.0", } }; // WebGL 供应商和渲染器映射表 const gpuInfo = { 'NVIDIA': [ 'ANGLE (NVIDIA, NVIDIA GeForce GTX 1650 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 2060 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 2070 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3050 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3080 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3090 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 4080 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce RTX 4090 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)', ], 'AMD': [ 'ANGLE (AMD, AMD Radeon RX 570 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 580 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 5500 XT Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 5600 XT Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 5700 XT Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 6600 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 6700 XT Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 6800 XT Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 6900 XT Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 7600 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 7700 XT Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 7800 XT Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (AMD, AMD Radeon RX 7900 XT Direct3D11 vs_5_0 ps_5_0, D3D11)', ], 'Intel': [ 'ANGLE (Intel, Intel(R) UHD Graphics 620 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (Intel, Intel(R) UHD Graphics 730 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (Intel, Intel(R) UHD Graphics 750 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (Intel, Intel(R) Iris(TM) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (Intel, Intel(R) Iris(TM) Plus Graphics 655 Direct3D11 vs_5_0 ps_5_0, D3D11)', 'ANGLE (Intel, Intel(R) Arc(TM) A380 Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)', ], 'Apple': [ 'Apple M1', 'Apple M1 Pro', 'Apple M1 Max', 'Apple M1 Ultra', 'Apple M2', 'Apple M2 Pro', 'Apple M2 Max', 'Apple M3', 'Apple M3 Pro', 'Apple M3 Max', ], 'Mobile': [ 'Mali-G78 MP12', 'Adreno 650', 'Adreno 660', 'Adreno 730', 'Apple GPU (Metal)', ] }; // 设备名称列表 const deviceNames = [ // Windows 'DESKTOP-', 'LAPTOP-', 'PC-', 'WIN-', 'WORKSTATION-', // Mac 'MacBook-Pro', 'MacBook-Air', 'iMac-Pro', 'Mac-mini', 'Mac-Studio', // 通用 'DELL-', 'HP-', 'LENOVO-', 'ASUS-', 'ACER-', 'MSI-', 'ALIENWARE-', 'GIGABYTE-' ]; // 生成随机设备名称 function generateDeviceNameSuffix() { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; let result = ''; const length = Math.floor(Math.random() * 6) + 4; // 4-9位 for (let i = 0; i < length; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } // MAC地址 const macPrefixes = [ 'E8-2A-EA', '00-1A-2B', 'AC-DE-48', 'B8-27-EB', 'DC-A6-32', '00-50-56', '00-0C-29', '00-05-69', '00-25-90', 'BC-5F-F4', '48-45-20', '6C-4B-90', '94-E9-79', '5C-F9-38', '64-BC-0C', 'B4-2E-99', '8C-85-90', '34-97-F6', 'A4-83-E7', '78-7B-8A' ]; // 区域语言 const localeSettings = { 'en-US': { languages: ['en-US', 'en'], timeZones: ['America/New_York', 'America/Chicago', 'America/Denver', 'America/Los_Angeles'] }, 'en-GB': { languages: ['en-GB', 'en-US', 'en'], timeZones: ['Europe/London', 'Europe/Dublin'] }, 'zh-CN': { languages: ['zh-CN', 'zh', 'en-US', 'en'], timeZones: ['Asia/Shanghai', 'Asia/Hong_Kong'] }, 'zh-TW': { languages: ['zh-TW', 'zh', 'en-US', 'en'], timeZones: ['Asia/Taipei'] }, 'ja-JP': { languages: ['ja-JP', 'ja', 'en-US', 'en'], timeZones: ['Asia/Tokyo'] }, 'ko-KR': { languages: ['ko-KR', 'ko', 'en-US', 'en'], timeZones: ['Asia/Seoul'] }, 'fr-FR': { languages: ['fr-FR', 'fr', 'en-US', 'en'], timeZones: ['Europe/Paris'] }, 'de-DE': { languages: ['de-DE', 'de', 'en-US', 'en'], timeZones: ['Europe/Berlin'] }, 'es-ES': { languages: ['es-ES', 'es', 'en-US', 'en'], timeZones: ['Europe/Madrid'] }, 'ru-RU': { languages: ['ru-RU', 'ru', 'en-US', 'en'], timeZones: ['Europe/Moscow'] }, 'pt-BR': { languages: ['pt-BR', 'pt', 'en-US', 'en'], timeZones: ['America/Sao_Paulo'] }, 'nl-NL': { languages: ['nl-NL', 'nl', 'en-US', 'en'], timeZones: ['Europe/Amsterdam'] }, 'it-IT': { languages: ['it-IT', 'it', 'en-US', 'en'], timeZones: ['Europe/Rome'] }, 'pl-PL': { languages: ['pl-PL', 'pl', 'en-US', 'en'], timeZones: ['Europe/Warsaw'] }, 'tr-TR': { languages: ['tr-TR', 'tr', 'en-US', 'en'], timeZones: ['Europe/Istanbul'] } }; // CPU核心 const computerSpecs = [ {cores: 2, ram: [2, 4]}, {cores: 4, ram: [4, 8, 16]}, {cores: 6, ram: [8, 16, 32]}, {cores: 8, ram: [8, 16, 32, 64]}, {cores: 10, ram: [16, 32, 64]}, {cores: 12, ram: [16, 32, 64, 128]}, {cores: 16, ram: [32, 64, 128]}, {cores: 24, ram: [32, 64, 128]}, {cores: 32, ram: [64, 128, 256]} ]; // 插件 const browserPlugins = { 'chrome': [ { name: 'Chrome PDF Plugin', description: 'Portable Document Format', filename: 'internal-pdf-viewer', mimeTypes: ['application/pdf'] }, { name: 'Chrome PDF Viewer', description: '', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', mimeTypes: ['application/pdf'] }, { name: 'Native Client', description: '', filename: 'internal-nacl-plugin', mimeTypes: ['application/x-nacl', 'application/x-pnacl'] } ], 'edge': [ { name: 'Microsoft Edge PDF Plugin', description: 'Portable Document Format', filename: 'internal-pdf-viewer', mimeTypes: ['application/pdf'] }, { name: 'Microsoft Edge PDF Viewer', description: '', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai', mimeTypes: ['application/pdf'] }, { name: 'Native Client', description: '', filename: 'internal-nacl-plugin', mimeTypes: ['application/x-nacl', 'application/x-pnacl'] } ], 'firefox': [ {name: 'Firefox PDF Viewer', description: 'PDF Viewer', filename: 'pdf.js', mimeTypes: ['application/pdf']} ], 'safari': [ { name: 'QuickTime Plugin', description: 'QuickTime Plug-in', filename: 'QuickTime Plugin.plugin', mimeTypes: ['video/quicktime'] }, { name: 'WebKit built-in PDF', description: 'PDF Viewer', filename: 'internal-pdf-viewer', mimeTypes: ['application/pdf'] } ] }; /** * 随机整数 * @param {number} min * @param {number} max * @returns {number} */ function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } /** * @param {Array} array - 选项数组 * @returns {*} - 随机选择的项 */ function randomChoice(array) { if (!Array.isArray(array) || array.length === 0) { return null; } return array[Math.floor(Math.random() * array.length)]; } /** * @param {number} percentChance - true概率百分比 (0-100) * @returns {boolean} - 随机布尔值 */ function randomChance(percentChance) { return Math.random() * 100 < percentChance; } /** * @returns {string} - 随机种子 */ function createRandomSeed() { return crypto.randomBytes(16).toString('hex'); } /** * @param {string} seed - 种子字符串 * @param {number} min - 最小值 * @param {number} max - 最大值 * @returns {number} - 伪随机数 */ function seededRandom(seed, min, max) { const hash = crypto.createHash('sha256').update(seed).digest('hex'); const decimal = parseInt(hash.substring(0, 8), 16) / 0xffffffff; return Math.floor(decimal * (max - min + 1)) + min; } /** * 随机MAC地址 * @returns {string} */ function generateRandomMAC() { const prefix = randomChoice(macPrefixes); const bytes = []; for (let i = 0; i < 3; i++) { bytes.push(Math.floor(Math.random() * 256).toString(16).padStart(2, '0').toUpperCase()); } return `${prefix}-${bytes.join('-')}`; } /** * 详细版本号 * @param {Object} browser - 浏览器 * @returns {string} - 如 "133.0.6834.110" */ function generateRealisticVersion(browser) { if (!browser || !browser.majorVersions) { return "100.0.0.0"; // 默认值 } const majorVersion = randomChoice(browser.majorVersions); const minorVersion = randomChoice(browser.minorVersions || [0]); // Chrome/Edge 风格: 133.0.6834.110 if (browser.buildVersions && browser.buildVersions.length > 0 && browser.patchVersions && browser.patchVersions.length > 0) { const buildVersion = randomChoice(browser.buildVersions); const patchVersion = randomChoice(browser.patchVersions); return `${majorVersion}.${minorVersion}.${buildVersion}.${patchVersion}`; } // Firefox 风格: 123.0.1 else if (browser.minorVersions && browser.minorVersions.length > 0) { return `${majorVersion}.${minorVersion}`; } // 简单: 15.4 else { return `${majorVersion}.${getRandomInt(0, 9)}`; } } /** * 随机用户代理 * @param {string} browserType - 浏览器类型 * @returns {string} */ function generateRealisticUserAgent(browserType = null) { let browser; if (browserType && browserVersions[browserType.toLowerCase()]) { browser = browserVersions[browserType.toLowerCase()]; } else { const browserKeys = Object.keys(browserVersions); browser = browserVersions[randomChoice(browserKeys)]; } // 系统 const os = randomChoice(osList); const osVersion = randomChoice(os.versions); const platform = randomChoice(os.platforms); // 版本号 const version = generateRealisticVersion(browser); browser.fullVersion = version; // 分离版本号 const majorVersionPart = version.split('.')[0]; let userAgent; if (browser.name === 'Chrome' || browser.name === 'Edge') { if (os.name === 'Windows') { userAgent = `Mozilla/5.0 (Windows NT ${osVersion}; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`; if (browser.name === 'Edge') { userAgent += ` Edg/${majorVersionPart}.0.${getRandomInt(1000, 2000)}.${getRandomInt(10, 200)}`; } } else if (os.name === 'Macintosh') { userAgent = `Mozilla/5.0 (${os.name}; ${osVersion}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`; if (browser.name === 'Edge') { userAgent += ` Edg/${majorVersionPart}.0.${getRandomInt(1000, 2000)}.${getRandomInt(10, 200)}`; } } else if (os.name === 'Linux') { userAgent = `Mozilla/5.0 (X11; Linux ${osVersion}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36`; if (browser.name === 'Edge') { userAgent += ` Edg/${majorVersionPart}.0.${getRandomInt(1000, 2000)}.${getRandomInt(10, 200)}`; } } else if (os.name === 'Android') { userAgent = `Mozilla/5.0 (Linux; Android ${osVersion}; SM-${getRandomString(3, true)}${getRandomInt(10, 99)}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Mobile Safari/537.36`; if (browser.name === 'Edge') { userAgent += ` EdgA/${majorVersionPart}.0.${getRandomInt(1000, 2000)}.${getRandomInt(10, 200)}`; } } } else if (browser.name === 'Firefox') { if (os.name === 'Windows') { userAgent = `Mozilla/5.0 (Windows NT ${osVersion}; Win64; x64; rv:${majorVersionPart}.0) Gecko/20100101 Firefox/${version}`; } else if (os.name === 'Macintosh') { userAgent = `Mozilla/5.0 (Macintosh; ${osVersion}; rv:${majorVersionPart}.0) Gecko/20100101 Firefox/${version}`; } else if (os.name === 'Linux') { userAgent = `Mozilla/5.0 (X11; Linux ${osVersion}; rv:${majorVersionPart}.0) Gecko/20100101 Firefox/${version}`; } else if (os.name === 'Android') { userAgent = `Mozilla/5.0 (Android ${osVersion}; Mobile; rv:${majorVersionPart}.0) Gecko/20100101 Firefox/${version}`; } } else if (browser.name === 'Safari') { if (os.name === 'Macintosh') { const webkitVersion = (parseInt(majorVersionPart) + 500) + `.${getRandomInt(1, 36)}.${getRandomInt(1, 15)}`; userAgent = `Mozilla/5.0 (Macintosh; ${osVersion}) AppleWebKit/${webkitVersion} (KHTML, like Gecko) Version/${version} Safari/${webkitVersion}`; } else if (os.name === 'iOS') { const webkitVersion = (parseInt(majorVersionPart) + 500) + `.${getRandomInt(1, 36)}.${getRandomInt(1, 15)}`; const device = randomChance(70) ? 'iPhone' : 'iPad'; userAgent = `Mozilla/5.0 (${device}; CPU OS ${osVersion.replace(/_/g, '_')} like Mac OS X) AppleWebKit/${webkitVersion} (KHTML, like Gecko) Version/${version} Mobile/15E148 Safari/${webkitVersion}`; } } else if (browser.name === 'Opera') { if (os.name === 'Windows') { userAgent = `Mozilla/5.0 (Windows NT ${osVersion}; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36 OPR/${majorVersionPart}.0.${getRandomInt(2000, 5000)}.${getRandomInt(10, 200)}`; } else if (os.name === 'Macintosh') { userAgent = `Mozilla/5.0 (Macintosh; ${osVersion}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36 OPR/${majorVersionPart}.0.${getRandomInt(2000, 5000)}.${getRandomInt(10, 200)}`; } else if (os.name === 'Linux') { userAgent = `Mozilla/5.0 (X11; Linux ${osVersion}) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${version} Safari/537.36 OPR/${majorVersionPart}.0.${getRandomInt(2000, 5000)}.${getRandomInt(10, 200)}`; } } // 如果没有匹配到任何合适的组合,提供一个默认UA if (!userAgent) { userAgent = `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.0.0 Safari/537.36`; } return userAgent; } /** * 随机字符串 * @param {number} length - 长度 * @param {boolean} upperOnly - 是否仅大写字母 * @returns {string} */ function getRandomString(length, upperOnly = false) { const chars = upperOnly ? 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; let result = ''; for (let i = 0; i < length; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } /** * 一致浏览器指纹 * @param {Object} options - 配置选项 * @returns {Object} - 指纹数据 */ export function generateFingerprint(options = {}) { const seed = options.seed || createRandomSeed(); let browserType = options.browserType || null; if (browserType && typeof browserType === 'string') { browserType = browserType.toLowerCase(); if (!browserVersions[browserType]) { console.warn(`未支持的浏览器类型: ${browserType},将使用随机浏览器类型`); browserType = null; } } if (!browserType) { const browserKeys = Object.keys(browserVersions); browserType = browserKeys[Math.floor(Math.random() * browserKeys.length)]; } // 生成用户代理 const userAgent = options.userAgent || generateRealisticUserAgent(browserType); // 选择地区/语言 const locale = options.locale || randomChoice(Object.keys(localeSettings)); const localeData = localeSettings[locale]; // 计算机规格 const computerSpec = options.computerSpec || randomChoice(computerSpecs); // 选择GPU信息 const gpuVendor = options.gpuVendor || randomChoice(Object.keys(gpuInfo)); const gpuRenderer = options.gpuRenderer || randomChoice(gpuInfo[gpuVendor] || ['']); // 设备名称 const deviceNameBase = options.deviceNameBase || randomChoice(deviceNames); const deviceName = options.deviceName || (deviceNameBase.endsWith('-') ? `${deviceNameBase}${generateDeviceNameSuffix()}` : deviceNameBase); let platform = options.platform; if (!platform) { if (userAgent.includes('Windows')) { platform = 'Win32'; } else if (userAgent.includes('Macintosh') || userAgent.includes('Mac OS')) { platform = 'MacIntel'; } else if (userAgent.includes('Linux')) { platform = 'Linux x86_64'; } else if (userAgent.includes('Android')) { platform = 'Android'; } else if (userAgent.includes('iPhone') || userAgent.includes('iPad')) { platform = userAgent.includes('iPad') ? 'iPad' : 'iPhone'; } else { platform = 'Win32'; // 默认 } } // 插件列表 const plugins = options.plugins || (browserPlugins[browserType] || []); // 创建 return { seed, userAgent, browserType, platform, osInfo: determineOsInfo(userAgent), webRTC: options.webRTC !== undefined ? options.webRTC : false, timezone: options.timezone || randomChoice(localeData.timeZones || ['UTC']), geolocation: options.geolocation || 'prompt', // 语言和区域设置 language: options.language || locale, languages: options.languages || localeData.languages || [locale, 'en-US'], // 指纹保护 canvas: options.canvas || 'noise', webGL: options.webGL || 'noise', audioContext: options.audioContext || 'noise', mediaDevices: options.mediaDevices || 'noise', // 硬件信息 webGLMetadata: { vendor: `Google Inc. (${gpuVendor})`, renderer: gpuRenderer, vendorUnmasked: gpuVendor, rendererUnmasked: gpuRenderer }, // 系统资源 cpu: { cores: Number(options.cpuCores || computerSpec.cores), architecture: options.cpuArchitecture || 'x86-64' }, ram: options.ram || randomChoice(computerSpec.ram), deviceName: deviceName, macAddress: options.macAddress || generateRandomMAC(), // 其他设置 doNotTrack: options.doNotTrack !== undefined ? options.doNotTrack : randomChoice([null, '0', '1']), hardwareAcceleration: options.hardwareAcceleration || 'default', plugins: plugins, screenOrientation: options.screenOrientation || 'landscape-primary', // 版本信息 browserVersion: getBrowserVersionFromUA(userAgent), // 指纹强度 noiseLevel: options.noiseLevel || 'medium', // low, medium, high consistencyLevel: options.consistencyLevel || 'high', // low, medium, high touchSupport: options.touchSupport !== undefined ? options.touchSupport : (userAgent.includes('Mobile') || userAgent.includes('Android') || platform === 'iPhone' || platform === 'iPad'), maxTouchPoints: options.maxTouchPoints || (userAgent.includes('Mobile') ? getRandomInt(1, 5) : 0), pdfViewerEnabled: options.pdfViewerEnabled !== undefined ? options.pdfViewerEnabled : true }; } /** * 从用户代理确定操作系统 * @param {string} userAgent - 用户代理 * @returns {Object} - 操作系统信息 */ function determineOsInfo(userAgent) { let name, version, archType; if (userAgent.includes('Windows')) { name = 'Windows'; if (userAgent.includes('Windows NT 10.0')) { version = '10'; } else if (userAgent.includes('Windows NT 11.0')) { version = '11'; } else { version = '10'; // 默认Windows 10 } archType = userAgent.includes('Win64') || userAgent.includes('x64') ? 'x64' : 'x86'; } else if (userAgent.includes('Mac OS X') || userAgent.includes('Macintosh')) { name = 'Mac OS'; const macOSMatch = userAgent.match(/Mac OS X ([0-9_]+)/) || userAgent.match(/Macintosh; Intel Mac OS X ([0-9_]+)/); version = macOSMatch ? macOSMatch[1].replace(/_/g, '.') : '10.15'; archType = userAgent.includes('Intel') ? 'x64' : 'arm64'; } else if (userAgent.includes('Linux')) { name = 'Linux'; version = userAgent.match(/Linux ([^;)]+)/) ? userAgent.match(/Linux ([^;)]+)/)[1] : 'x86_64'; archType = userAgent.includes('x86_64') ? 'x64' : 'x86'; } else if (userAgent.includes('Android')) { name = 'Android'; const androidMatch = userAgent.match(/Android ([0-9.]+)/); version = androidMatch ? androidMatch[1] : '11'; archType = 'arm64'; } else if (userAgent.includes('iPhone') || userAgent.includes('iPad')) { name = 'iOS'; const iosMatch = userAgent.match(/OS ([0-9_]+)/); version = iosMatch ? iosMatch[1].replace(/_/g, '.') : '15.0'; archType = 'arm64'; } else { name = 'Unknown'; version = 'Unknown'; archType = 'Unknown'; } return {name, version, archType}; } /** * 从用户代理提取浏览器版本 * @param {string} userAgent - 用户代理 * @returns {Object} - 浏览器版本 */ function getBrowserVersionFromUA(userAgent) { let name, version, fullVersion; if (userAgent.includes('Firefox/')) { name = 'Firefox'; const match = userAgent.match(/Firefox\/([0-9.]+)/); fullVersion = match ? match[1] : '100.0'; } else if (userAgent.includes('Edg/')) { name = 'Edge'; const match = userAgent.match(/Edg\/([0-9.]+)/); fullVersion = match ? match[1] : '100.0.0.0'; } else if (userAgent.includes('OPR/') || userAgent.includes('Opera/')) { name = 'Opera'; const match = userAgent.match(/OPR\/([0-9.]+)/) || userAgent.match(/Opera\/([0-9.]+)/); fullVersion = match ? match[1] : '100.0.0.0'; } else if (userAgent.includes('Safari/') && !userAgent.includes('Chrome/')) { name = 'Safari'; const match = userAgent.match(/Version\/([0-9.]+)/); fullVersion = match ? match[1] : '15.0'; } else if (userAgent.includes('Chrome/')) { name = 'Chrome'; const match = userAgent.match(/Chrome\/([0-9.]+)/); fullVersion = match ? match[1] : '100.0.0.0'; } else { name = 'Unknown'; fullVersion = '1.0.0'; } version = fullVersion.split('.')[0]; // 主版本号 return {name, version, fullVersion}; } /** * 指纹应用到浏览器页面 * @param {Object} page - Puppeteer页面对象 * @param {Object} fingerprint - 指纹对象 * @returns {Promise} */ export async function applyFingerprint(page, fingerprint) { try { // 设置用户代理 await page.setUserAgent(fingerprint.userAgent); // 设置语言和时区 await page.setExtraHTTPHeaders({ 'Accept-Language': fingerprint.languages.join(',') }); await page.emulateTimezone(fingerprint.timezone); await page.evaluateOnNewDocument((fp) => { const deepClone = (obj) => { if (obj === null || typeof obj !== 'object') { return obj; } if (obj instanceof Date) { return new Date(obj); } if (obj instanceof RegExp) { return new RegExp(obj); } if (obj instanceof Array) { return obj.reduce((arr, item, i) => { arr[i] = deepClone(item); return arr; }, []); } if (obj instanceof Object) { return Object.keys(obj).reduce((newObj, key) => { newObj[key] = deepClone(obj[key]); return newObj; }, {}); } }; // 保存原始navigator const originalNavigator = window.navigator; const properties = Object.getOwnPropertyDescriptors(window.navigator); const resultNavigator = {}; // 允许的可写属性 const allowedToWrite = [ 'userAgent', 'appVersion', 'platform', 'language', 'languages', 'deviceMemory', 'hardwareConcurrency', 'doNotTrack', 'webdriver', 'maxTouchPoints' ]; // 适当UA模拟 const browserInfo = fp.browserVersion; for (const key in properties) { let overrideValue; switch (key) { case 'userAgent': overrideValue = fp.userAgent; break; case 'appVersion': overrideValue = fp.userAgent.replace('Mozilla/', ''); break; case 'platform': overrideValue = fp.platform; break; case 'language': overrideValue = fp.language; break; case 'languages': overrideValue = [...fp.languages]; break; case 'deviceMemory': overrideValue = fp.ram; break; case 'hardwareConcurrency': overrideValue = Number(fp.cpu.cores); break; case 'doNotTrack': overrideValue = fp.doNotTrack; break; case 'webdriver': overrideValue = false; break; case 'maxTouchPoints': overrideValue = fp.maxTouchPoints || 0; break; case 'vendor': overrideValue = browserInfo.name === 'Chrome' || browserInfo.name === 'Edge' ? 'Google Inc.' : ''; break; case 'appName': overrideValue = 'Netscape'; break; case 'appCodeName': overrideValue = 'Mozilla'; break; } // 如果有覆盖值 if (overrideValue !== undefined) { Object.defineProperty(resultNavigator, key, { value: overrideValue, configurable: false, enumerable: true, writable: false }); } else if (properties[key].configurable) { // 从原始 navigator 获取 Object.defineProperty(resultNavigator, key, { get: function () { try { return originalNavigator[key]; } catch (e) { return properties[key].value; } }, enumerable: properties[key].enumerable, configurable: false }); } else { // 不可配置的属性,保持原样 if (properties[key].writable) { resultNavigator[key] = originalNavigator[key]; } else { Object.defineProperty(resultNavigator, key, { value: originalNavigator[key], writable: properties[key].writable, enumerable: properties[key].enumerable, configurable: properties[key].configurable }); } } } // 创建代理以拦截任何新添加的属性 const navigatorProxy = new Proxy(resultNavigator, { has: (target, key) => key in target || key in originalNavigator, get: (target, key) => { if (key in target) { return target[key]; } // 使用原始值 return originalNavigator[key]; }, set: (target, key, value) => { if (allowedToWrite.includes(key)) { target[key] = value; return true; } return false; }, getOwnPropertyDescriptor: (target, key) => { return Object.getOwnPropertyDescriptor(target, key) || Object.getOwnPropertyDescriptor(originalNavigator, key); }, defineProperty: (target, key, descriptor) => { if (allowedToWrite.includes(key)) { Object.defineProperty(target, key, descriptor); return true; } return false; } }); // 替换 navigator Object.defineProperty(window, 'navigator', { value: navigatorProxy, writable: false, configurable: false, enumerable: true }); if ('userAgentData' in originalNavigator) { // 创建伪造userAgentData const brandsList = []; if (fp.browserType === 'chrome') { brandsList.push({brand: "Chromium", version: fp.browserVersion.version}); brandsList.push({brand: "Google Chrome", version: fp.browserVersion.version}); brandsList.push({brand: "Not;A=Brand", version: "99.0.0.0"}); } else if (fp.browserType === 'edge') { brandsList.push({brand: "Microsoft Edge", version: fp.browserVersion.version}); brandsList.push({brand: "Chromium", version: fp.browserVersion.version}); brandsList.push({brand: "Not;A=Brand", version: "99.0.0.0"}); } else if (fp.browserType === 'firefox') { brandsList.push({brand: "Firefox", version: fp.browserVersion.version}); brandsList.push({brand: "Not;A=Brand", version: "99.0.0.0"}); } const uaDataValues = { brands: brandsList, mobile: fp.userAgent.includes('Mobile'), platform: fp.osInfo.name }; const platformVersion = [fp.osInfo.version, 0, 0, 0]; const uaData = { brands: brandsList, mobile: fp.userAgent.includes('Mobile'), platform: fp.osInfo.name, architecture: fp.cpu.architecture, bitness: "64", model: "", platformVersion: platformVersion.join('.'), getHighEntropyValues: function (hints) { return new Promise(resolve => { const result = {}; if (hints.includes('architecture')) { result.architecture = fp.cpu.architecture; } if (hints.includes('bitness')) { result.bitness = "64"; } if (hints.includes('brands')) { result.brands = deepClone(brandsList); } if (hints.includes('mobile')) { result.mobile = fp.userAgent.includes('Mobile'); } if (hints.includes('model')) { result.model = ""; } if (hints.includes('platform')) { result.platform = fp.osInfo.name; } if (hints.includes('platformVersion')) { result.platformVersion = platformVersion.join('.'); } if (hints.includes('uaFullVersion')) { result.uaFullVersion = fp.browserVersion.fullVersion; } if (hints.includes('fullVersionList')) { result.fullVersionList = deepClone(brandsList); } resolve(result); }); }, toJSON: function () { return { brands: this.brands, mobile: this.mobile, platform: this.platform }; } }; // 添加到 navigator Object.defineProperty(navigatorProxy, 'userAgentData', { value: uaData, writable: false, enumerable: true, configurable: false }); } if (fp.webRTC === false) { // 阻止 WebRTC 泄露 const origRTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection; if (origRTCPeerConnection) { class CustomRTCPeerConnection extends origRTCPeerConnection { constructor(configuration) { // 过滤掉ICE服务器 if (configuration && configuration.iceServers) { configuration = { ...configuration, iceServers: [] }; } super(configuration); } createOffer(...args) { // 拦截createOffer return new Promise((resolve, reject) => { super.createOffer(...args) .then(offer => { if (offer && offer.sdp) { offer.sdp = offer.sdp.replace(/IP4 \d+\.\d+\.\d+\.\d+/g, 'IP4 0.0.0.0'); } resolve(offer); }) .catch(reject); }); } createAnswer(...args) { return new Promise((resolve, reject) => { super.createAnswer(...args) .then(answer => { if (answer && answer.sdp) { answer.sdp = answer.sdp.replace(/IP4 \d+\.\d+\.\d+\.\d+/g, 'IP4 0.0.0.0'); } resolve(answer); }) .catch(reject); }); } } window.RTCPeerConnection = CustomRTCPeerConnection; window.webkitRTCPeerConnection = CustomRTCPeerConnection; window.mozRTCPeerConnection = CustomRTCPeerConnection; } // 禁用媒体设备 const safeMediaDevices = { enumerateDevices: function () { return Promise.resolve([]); }, getSupportedConstraints: function () { return {}; }, getUserMedia: function () { return Promise.reject(new Error('Permission denied')); }, getDisplayMedia: function () { return Promise.reject(new Error('Permission denied')); } }; if (originalNavigator.mediaDevices) { Object.defineProperty(navigatorProxy, 'mediaDevices', { value: safeMediaDevices, writable: false, enumerable: true, configurable: false }); } } if (fp.canvas === 'noise' || fp.canvas === 'block') { const originalGetContext = HTMLCanvasElement.prototype.getContext; HTMLCanvasElement.prototype.getContext = function (type, attributes) { if (fp.canvas === 'block' && (type === '2d' || type.includes('webgl'))) { return null; } const context = originalGetContext.call(this, type, attributes); if (!context) return null; if (type === '2d') { // 2D Canvas指纹保护 const origGetImageData = context.getImageData; const origPutImageData = context.putImageData; const origToDataURL = this.toDataURL; const origToBlob = this.toBlob; // 添加微小噪声的函数 const addNoise = function (data) { const noise = Math.floor(Math.random() * 10) / 255; for (let i = 0; i < data.data.length; i += 4) { if (data.data[i + 3] > 0) { if (Math.random() > 0.5) { data.data[i + 3] -= noise; } else { data.data[i + 3] += noise; } } } return data; }; context.getImageData = function (sx, sy, sw, sh) { const imageData = origGetImageData.call(this, sx, sy, sw, sh); return addNoise(imageData); }; this.toDataURL = function (...args) { const dataURL = origToDataURL.apply(this, args); if (!dataURL) return dataURL; // URL添加微小噪声 (改变最后几个字符) const lastCommaIndex = dataURL.lastIndexOf(','); if (lastCommaIndex !== -1) { const prefix = dataURL.substring(0, lastCommaIndex + 1); const data = dataURL.substring(lastCommaIndex + 1); const noisyChar = String.fromCharCode( data.charCodeAt(data.length - 2) + Math.round(Math.random() * 2 - 1) ); return prefix + data.substring(0, data.length - 2) + noisyChar + data.substring(data.length - 1); } return dataURL; }; this.toBlob = function (callback, ...args) { origToBlob.call(this, (blob) => { if (!blob) { callback(blob); return; } const reader = new FileReader(); reader.readAsDataURL(blob); reader.onloadend = function () { // 修改dataURL const dataURL = reader.result; const lastCommaIndex = dataURL.lastIndexOf(','); if (lastCommaIndex !== -1) { const prefix = dataURL.substring(0, lastCommaIndex + 1); const data = dataURL.substring(lastCommaIndex + 1); const noisyChar = String.fromCharCode( data.charCodeAt(data.length - 2) + Math.round(Math.random() * 2 - 1) ); const newDataURL = prefix + data.substring(0, data.length - 2) + noisyChar + data.substring(data.length - 1); const byteString = atob(newDataURL.split(',')[1]); const mimeString = newDataURL.split(',')[0].split(':')[1].split(';')[0]; const ab = new ArrayBuffer(byteString.length); const ia = new Uint8Array(ab); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } callback(new Blob([ab], {type: mimeString})); } }; callback(blob); }, ...args); }; } else if (type.includes('webgl') || type.includes('experimental-webgl')) { // WebGL Canvas指纹保护 const origGetParameter = context.getParameter; context.getParameter = function (parameter) { // UNMASKED_VENDOR_WEBGL if (parameter === 37445) { return fp.webGLMetadata.vendorUnmasked; } // UNMASKED_RENDERER_WEBGL if (parameter === 37446) { return fp.webGLMetadata.rendererUnmasked; } return origGetParameter.call(this, parameter); }; } return context; }; } if (fp.audioContext === 'noise') { const AudioContext = window.AudioContext || window.webkitAudioContext; if (AudioContext) { const origAudioContext = AudioContext; // 创建带噪声AudioContext window.AudioContext = window.webkitAudioContext = function () { const ctx = new origAudioContext(); const origGetChannelData = ctx.createAnalyser().getFloatFrequencyData; if (origGetChannelData) { ctx.createAnalyser().getFloatFrequencyData = function (array) { origGetChannelData.call(this, array); // 添加微小噪声 for (let i = 0; i < array.length; i += 50) { if (array[i]) { array[i] += (Math.random() * 0.0001) - 0.00005; } } }; } return ctx; }; } } // 创建自定义插件列表 const mimeTypeArray = []; const pluginArray = []; if (fp.plugins && Array.isArray(fp.plugins)) { fp.plugins.forEach((plugin, pluginIndex) => { if (!plugin || !plugin.name) return; // 创建MimeTypes const mimeTypes = {}; let mimeTypeCount = 0; if (plugin.mimeTypes && Array.isArray(plugin.mimeTypes)) { plugin.mimeTypes.forEach((type, index) => { const mimeType = { type, description: plugin.description || '', suffixes: plugin.name.toLowerCase().replace(/[^a-z0-9]/g, ''), enabledPlugin: null }; mimeTypes[mimeTypeCount] = mimeType; mimeTypes[type] = mimeType; mimeTypeCount++; mimeTypeArray.push(mimeType); }); } // 创建插件对象 const pluginObj = { name: plugin.name, filename: plugin.filename || '', description: plugin.description || '', length: mimeTypeCount, item: function (index) { return this[index]; }, namedItem: function (name) { return this[name]; } }; // 扩展插件对象 for (let i = 0; i < mimeTypeCount; i++) { pluginObj[i] = mimeTypes[i]; } // mime设置enabledPlugin Object.values(mimeTypes).forEach(mime => { mime.enabledPlugin = pluginObj; }); pluginArray.push(pluginObj); }); // 自定义的navigator.plugins const pluginsObj = { length: pluginArray.length, item: function (index) { return this[index]; }, namedItem: function (name) { return this[name] || null; }, refresh: function () { } }; for (let i = 0; i < pluginArray.length; i++) { const plugin = pluginArray[i]; pluginsObj[i] = plugin; pluginsObj[plugin.name] = plugin; } // 自定义navigator.mimeTypes const mimeTypesObj = { length: mimeTypeArray.length, item: function (index) { return this[index]; }, namedItem: function (name) { return this[name] || null; } }; for (let i = 0; i < mimeTypeArray.length; i++) { const mimeType = mimeTypeArray[i]; mimeTypesObj[i] = mimeType; mimeTypesObj[mimeType.type] = mimeType; } // plugins和mimeTypes附加到navigator Object.defineProperty(navigatorProxy, 'plugins', { value: pluginsObj, writable: false, enumerable: true, configurable: false }); Object.defineProperty(navigatorProxy, 'mimeTypes', { value: mimeTypesObj, writable: false, enumerable: true, configurable: false }); } // 隐藏自动化 Object.defineProperty(navigatorProxy, 'webdriver', { get: () => false, enumerable: true, configurable: false }); // 修复Chrome特征 if (window.chrome) { const chromeObj = {}; const originalChrome = window.chrome; // 复制原始chrome for (const key in originalChrome) { try { if (key === 'runtime' && originalChrome.runtime) { // 处理chrome.runtime const runtimeObj = {}; for (const rKey in originalChrome.runtime) { try { runtimeObj[rKey] = originalChrome.runtime[rKey]; } catch (e) { } } chromeObj.runtime = runtimeObj; } else { chromeObj[key] = originalChrome[key]; } } catch (e) { } } // 创建chrome.app chromeObj.app = { isInstalled: false, InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' }, RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' } }; // 替换chrome Object.defineProperty(window, 'chrome', { value: chromeObj, writable: false, enumerable: true, configurable: false }); } // 添加PDF查看器 if (fp.pdfViewerEnabled) { for (const mimeType of ['application/pdf', 'text/pdf']) { const pdfMime = { type: mimeType, suffixes: 'pdf', description: 'Portable Document Format' }; if (navigatorProxy.mimeTypes) { const mimeTypesObj = navigatorProxy.mimeTypes; const index = mimeTypesObj.length; pdfMime.enabledPlugin = navigatorProxy.plugins[0]; mimeTypesObj[index] = pdfMime; mimeTypesObj[mimeType] = pdfMime; mimeTypesObj.length++; } } } // 噪声 if (fp.noiseLevel && (fp.noiseLevel === 'medium' || fp.noiseLevel === 'high')) { const addNoise = (value, scale) => { if (typeof value !== 'number') return value; const noise = (Math.random() - 0.5) * scale; return value + noise; }; } // 清理webdriver delete window.__nightmare; delete window.cdc_adoQpoasnfa76pfcZLmcfl_Array; delete window.cdc_adoQpoasnfa76pfcZLmcfl_Promise; delete window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol; const originalToString = Function.prototype.toString; Function.prototype.toString = function () { if (this === Function.prototype.toString) { return originalToString.call(this); } const fnName = this.name; if (fnName === 'getParameter' || fnName === 'getChannelData' || fnName === 'toDataURL' || fnName === 'toBlob' || fnName === 'getImageData') { return "function " + fnName + "() { [native code] }"; } return originalToString.call(this); }; // 创建隐藏的指纹验证 window._fingerprintId = fp.seed; const event = new CustomEvent('fingerprintApplied', { detail: {success: true, fingerprintId: fp.seed} }); document.dispatchEvent(event); }, fingerprint); const debugInfo = await page.evaluate((fp) => { return { hardwareConcurrency: navigator.hardwareConcurrency, hardwareConcurrencyType: typeof navigator.hardwareConcurrency, expectedCores: fp.cpu.cores, expectedCoresType: typeof fp.cpu.cores }; }, fingerprint); // console.log('指纹应用调试信息:', debugInfo); console.log(`已应用自定义浏览器指纹: ${fingerprint.userAgent}`); return true; } catch (error) { console.error('应用浏览器指纹时出错:', error); return false; } } /** * 为特定浏览器创建并应用指纹 * @param {Object} page - Puppeteer * @param {string|Object} options - 浏览器或完整配置 * @returns {Promise} - 应用指纹 */ export async function setupBrowserFingerprint(page, options = {}) { try { if (typeof options === 'string') { options = {browserType: options}; } // 生成完整的指纹 const fingerprint = generateFingerprint(options); // 应用指纹 const success = await applyFingerprint(page, fingerprint); // 验证指纹应用 if (success) { try { const appliedUserAgent = await page.evaluate(() => navigator.userAgent); if (appliedUserAgent !== fingerprint.userAgent) { console.warn('用户代理未正确应用:', { expected: fingerprint.userAgent, applied: appliedUserAgent }); } // 验证CPU核心数 // const hardwareConcurrency = await page.evaluate(() => navigator.hardwareConcurrency); // if (Number(hardwareConcurrency) !== Number(fingerprint.cpu.cores)) { // console.warn('CPU核心数未正确应用:', { // expected: fingerprint.cpu.cores, // applied: hardwareConcurrency, // expectedType: typeof fingerprint.cpu.cores, // appliedType: typeof hardwareConcurrency // }); // } // 验证WebGL if (fingerprint.webGL !== 'block') { const webglVendor = await page.evaluate(() => { try { const canvas = document.createElement('canvas'); const gl = canvas.getContext('webgl'); return gl ? gl.getParameter(gl.getParameter(37445)) : null; } catch (e) { return null; } }); if (webglVendor && !webglVendor.includes(fingerprint.webGLMetadata.vendorUnmasked)) { console.warn('WebGL供应商信息未正确应用'); } } console.log('指纹验证成功'); } catch (verifyError) { console.warn('指纹验证时出错:', verifyError); } } return fingerprint; } catch (error) { console.error('设置浏览器指纹时出错:', error); throw error; } } /** * 验证页面指纹是否正确应用 * @param {Object} page - Puppeteer * @param {Object} fingerprint - 指定指纹 * @returns {Promise} */ export async function verifyFingerprint(page, fingerprint) { try { const results = await page.evaluate((fp) => { const checks = { userAgent: navigator.userAgent === fp.userAgent, platform: navigator.platform === fp.platform, hardwareConcurrency: Number(navigator.hardwareConcurrency) === Number(fp.cpu.cores), language: navigator.language === fp.language, deviceMemory: navigator.deviceMemory === fp.ram, doNotTrack: navigator.doNotTrack === fp.doNotTrack }; return { success: Object.values(checks).every(v => v), details: checks }; }, fingerprint); console.log('指纹验证结果:', results); return results.success; } catch (error) { console.error('验证指纹时出错:', error); return false; } } /** * 获取随机指纹 * @param {string} browserFamily ('chrome', 'edge', 'firefox', 'safari') * @returns {Object} - 指纹 */ export function getRealisticFingerprint(browserFamily = 'chrome') { // 标准化浏览器 browserFamily = browserFamily.toLowerCase(); // 选择合适操作系统 let osFamily; const browserType = browserFamily; if (browserFamily === 'safari') { osFamily = Math.random() < 0.8 ? 'Macintosh' : 'iOS'; } else { const osDistribution = { 'chrome': {'Windows': 0.65, 'Macintosh': 0.25, 'Linux': 0.08, 'Android': 0.02}, 'edge': {'Windows': 0.80, 'Macintosh': 0.18, 'Linux': 0.02}, 'firefox': {'Windows': 0.55, 'Macintosh': 0.25, 'Linux': 0.20} }; const distribution = osDistribution[browserFamily] || {'Windows': 0.7, 'Macintosh': 0.25, 'Linux': 0.05}; const rand = Math.random(); let cumulative = 0; for (const [os, probability] of Object.entries(distribution)) { cumulative += probability; if (rand <= cumulative) { osFamily = os; break; } } } // 选择规格 let computerSpec; if (osFamily === 'Windows' || osFamily === 'Macintosh') { computerSpec = { cores: [4, 6, 8, 12, 16][Math.floor(Math.random() * 5)], ram: [8, 16, 32, 64][Math.floor(Math.random() * 4)] }; } else if (osFamily === 'Linux') { computerSpec = { cores: [4, 8, 16, 24, 32][Math.floor(Math.random() * 5)], ram: [8, 16, 32, 64, 128][Math.floor(Math.random() * 5)] }; } else { computerSpec = { cores: [2, 4, 6, 8][Math.floor(Math.random() * 4)], ram: [4, 6, 8, 12][Math.floor(Math.random() * 4)] }; } // 语言 const commonLanguages = ['en-US', 'en-GB', 'zh-CN', 'es-ES', 'fr-FR', 'de-DE', 'ja-JP', 'ru-RU']; const locale = randomChoice(commonLanguages); return { browserType, userAgent: null, osFamily, computerSpec, locale, timezone: null, webRTC: false, noiseLevel: 'medium', consistencyLevel: 'high' }; }