Files
2025-12-08 09:54:51 +08:00

185 lines
5.8 KiB
JavaScript

// 使用IIFE封装防止污染全局变量
(function (window) {
// 配置参数
const defaultConfig = {
webgl: true,
audio: true,
deviceInfo: true,
};
// 创建全局对象
window.DeviceFingerprint = {
init: function (config = {}) {
// 等待DOM加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this._initialize(config));
} else {
this._initialize(config);
}
return this;
},
// 新增实际初始化方法
_initialize: function (config) {
this.config = { ...defaultConfig, ...config };
this._loadDependencies()
.then(() => {
this._injectCanvasElements();
})
.catch((error) => {
console.error('依赖加载失败:', error);
});
},
// 自动注入需要的canvas元素
_injectCanvasElements: function () {
if (!document.getElementById('fp-canvas')) {
const canvas = document.createElement('canvas');
canvas.id = 'fp-canvas';
canvas.style.display = 'block';
document.body.appendChild(canvas);
}
},
_getIP: async function () {
const endpoints = [
// 'https://api.ipify.org?format=json', // 主接口
'https://ipapi.co/json/', // 备用接口1
// 'https://ipinfo.io/json' // 备用接口2
];
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
try {
// 尝试所有接口直到成功
for (const url of endpoints) {
try {
const response = await fetch(url, {
signal: controller.signal,
});
if (!response.ok) throw new Error('响应异常');
const data = await response.json();
return data.ip || data.ipAddress || '未知IP';
} catch (error) {
console.warn(`接口 ${url} 请求失败:`, error.message);
}
}
return '获取失败';
} catch (error) {
console.error('IP获取最终失败:', error);
return '获取失败';
} finally {
clearTimeout(timeoutId);
}
},
// 统一获取所有指纹
async getAllFingerprints() {
// 等待MD5库加载
if (!window.hex_md5) {
await this._loadDependencies();
}
const results = {};
// 添加null检查
if (!document.getElementById('fp-canvas')) {
throw new Error('Canvas元素未成功创建');
}
if (this.config.webgl) {
results.webgl = this._getWebGLFingerprint();
}
if (this.config.deviceInfo) {
results.device = this._getDeviceFingerprint();
}
return results;
},
getWebGLFingerprint: async function () {
// 等待依赖加载完成
if (!window.hex_md5) {
await this._loadDependencies();
}
try {
// 检查canvas元素是否存在
if (!document.getElementById('fp-canvas')) {
throw new Error('Canvas元素未找到,请先调用初始化方法');
}
// 调用内部方法获取指纹
return this._getWebGLFingerprint();
} catch (error) {
console.error('获取WebGL指纹失败:', error);
return null;
}
},
_getWebGLFingerprint: async function () {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
if (!gl) return 'unsupported';
// 获取WebGL基础参数
const params = [
gl.getParameter(gl.VERSION),
gl.getParameter(gl.SHADING_LANGUAGE_VERSION),
gl.getParameter(gl.VENDOR),
gl.getParameter(gl.RENDERER),
gl.getParameter(gl.MAX_TEXTURE_SIZE),
gl.getParameter(gl.MAX_RENDERBUFFER_SIZE),
];
// 获取屏幕尺寸
const screen = `${window.screen.width}x${window.screen.height}x${window.screen.colorDepth}`;
console.log('screen', screen);
console.log('params', params);
// 组合关键特征
const fingerprintData = `${params.join('|')}|${screen}`;
return hex_md5(fingerprintData);
},
_getDeviceFingerprint: function () {
try {
const deviceInfo = {
screen: `${screen.width}x${screen.height}`,
colorDepth: screen.colorDepth,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
platform: navigator.platform,
userAgent: navigator.userAgent,
languages: navigator.languages.join(','),
hardwareConcurrency: navigator.hardwareConcurrency || 'unknown',
};
return hex_md5(JSON.stringify(deviceInfo));
} catch (error) {
console.error('Device info error:', error);
return null;
}
},
// 修改MD5加载方法
_loadDependencies: function () {
return new Promise((resolve, reject) => {
if (window.hex_md5) return resolve();
const script = document.createElement('script');
script.src = './md5.js';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
},
getWebGLFingerprint: async function () {
// 等待依赖加载完成
if (!window.hex_md5) {
await this._loadDependencies();
}
try {
// 检查canvas元素是否存在
if (!document.getElementById('fp-canvas')) {
throw new Error('Canvas元素未找到,请先调用初始化方法');
}
// 调用内部方法获取指纹
return this._getWebGLFingerprint();
} catch (error) {
console.error('获取WebGL指纹失败:', error);
return null;
}
},
};
// 自动初始化(可选)
window.DeviceFingerprint.init();
})(window);