From cbfefa49de006c30c95fb68a7900498577a12f66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=AB=E9=81=97=E5=BF=98=E7=9A=84=E8=AE=B0=E5=BF=86?= <32097237+YIWANG-sketch@users.noreply.github.com> Date: Fri, 14 Mar 2025 05:52:03 +0800 Subject: [PATCH] Delete you_providers/browserFingerprint.mjs --- you_providers/browserFingerprint.mjs | 1626 -------------------------- 1 file changed, 1626 deletions(-) delete mode 100644 you_providers/browserFingerprint.mjs diff --git a/you_providers/browserFingerprint.mjs b/you_providers/browserFingerprint.mjs deleted file mode 100644 index d219382..0000000 --- a/you_providers/browserFingerprint.mjs +++ /dev/null @@ -1,1626 +0,0 @@ -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' - }; -}