/** * 设备指纹生成工具 * 通过收集浏览器和设备特征生成唯一标识 */ class DeviceFingerprint { constructor() { this.components = []; } /** * 收集所有设备特征 */ async collectComponents() { this.components = []; // 1. User Agent this.addComponent('userAgent', navigator.userAgent); // 2. 语言 this.addComponent('language', navigator.language); // 3. 屏幕分辨率 this.addComponent('screenResolution', `${screen.width}x${screen.height}x${screen.colorDepth}`); // 4. 时区 this.addComponent('timezone', Intl.DateTimeFormat().resolvedOptions().timeZone); this.addComponent('timezoneOffset', new Date().getTimezoneOffset()); // 5. 平台 this.addComponent('platform', navigator.platform); // 6. Canvas指纹 this.addComponent('canvas', await this.getCanvasFingerprint()); // 7. WebGL指纹 this.addComponent('webgl', this.getWebGLFingerprint()); // 8. 字体检测 this.addComponent('fonts', this.getAvailableFonts()); // 9. 插件信息 this.addComponent('plugins', this.getPluginInfo()); // 10. 硬件并发数 this.addComponent('hardwareConcurrency', navigator.hardwareConcurrency || 'unknown'); // 11. 设备内存 this.addComponent('deviceMemory', navigator.deviceMemory || 'unknown'); // 12. 触摸支持 this.addComponent('touchSupport', 'ontouchstart' in window); // 13. Cookie启用 this.addComponent('cookieEnabled', navigator.cookieEnabled); // 14. Do Not Track this.addComponent('doNotTrack', navigator.doNotTrack || 'unknown'); } /** * 添加组件 */ addComponent(key, value) { this.components.push({ key, value }); } /** * 获取Canvas指纹 */ async getCanvasFingerprint() { try { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = 200; canvas.height = 50; // 绘制文本 ctx.textBaseline = 'top'; ctx.font = '14px Arial'; ctx.fillStyle = '#f60'; ctx.fillRect(0, 0, 200, 50); ctx.fillStyle = '#069'; ctx.fillText('Device Fingerprint 🔒', 10, 10); // 获取图像数据 return canvas.toDataURL(); } catch (e) { return 'unsupported'; } } /** * 获取WebGL指纹 */ getWebGLFingerprint() { try { const canvas = document.createElement('canvas'); const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); if (!gl) return 'unsupported'; const debugInfo = gl.getExtension('WEBGL_debug_renderer_info'); if (!debugInfo) return 'no-extension'; const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL); const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL); return `${vendor}~${renderer}`; } catch (e) { return 'unsupported'; } } /** * 检测可用字体 */ getAvailableFonts() { const baseFonts = ['monospace', 'sans-serif', 'serif']; const testFonts = [ 'Arial', 'Verdana', 'Times New Roman', 'Courier New', 'Georgia', 'Palatino', 'Garamond', 'Comic Sans MS', 'Trebuchet MS', 'Impact', 'Arial Black', 'Tahoma' ]; const availableFonts = []; // 创建测试元素 const testString = 'mmmmmmmmmmlli'; const testSize = '72px'; const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // 获取基准字体宽度 const baseFontWidths = {}; baseFonts.forEach(baseFont => { ctx.font = `${testSize} ${baseFont}`; baseFontWidths[baseFont] = ctx.measureText(testString).width; }); // 测试每个字体 testFonts.forEach(font => { let detected = false; baseFonts.forEach(baseFont => { ctx.font = `${testSize} '${font}', ${baseFont}`; const width = ctx.measureText(testString).width; if (width !== baseFontWidths[baseFont]) { detected = true; } }); if (detected) { availableFonts.push(font); } }); return availableFonts.join(','); } /** * 获取插件信息 */ getPluginInfo() { if (!navigator.plugins) return 'unsupported'; const plugins = []; for (let i = 0; i < navigator.plugins.length; i++) { plugins.push(navigator.plugins[i].name); } return plugins.join(','); } /** * 生成指纹哈希 */ async generateHash() { await this.collectComponents(); // 将所有组件转换为字符串 const componentString = this.components .map(c => `${c.key}:${c.value}`) .join('|'); // 使用简单的哈希函数(生产环境建议使用更强的哈希) return this.simpleHash(componentString); } /** * 简单哈希函数 */ simpleHash(str) { let hash = 0; for (let i = 0; i < str.length; i++) { const char = str.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32bit integer } return Math.abs(hash).toString(16); } /** * 获取或创建设备指纹 */ static async getFingerprint() { try { // 尝试从localStorage获取缓存的指纹 const cached = localStorage.getItem('device_fingerprint'); if (cached) { return cached; } } catch (e) { console.warn('读取缓存的设备指纹失败:', e); } try { // 生成新指纹 const fp = new DeviceFingerprint(); const fingerprint = await fp.generateHash(); // 尝试缓存指纹 try { localStorage.setItem('device_fingerprint', fingerprint); } catch (e) { console.warn('缓存设备指纹失败:', e); } return fingerprint; } catch (error) { console.error('生成设备指纹失败:', error); // 降级方案:返回基于UserAgent的简单hash const fallback = new DeviceFingerprint(); return fallback.simpleHash(navigator.userAgent + Date.now()); } } /** * 清除缓存的指纹 */ static clearFingerprint() { localStorage.removeItem('device_fingerprint'); } } // 导出供其他脚本使用 if (typeof module !== 'undefined' && module.exports) { module.exports = DeviceFingerprint; }