From 6900cc8a25b0ea436bde667a62d803b270fbb2f9 Mon Sep 17 00:00:00 2001 From: wangxiaoshuang <825034831@qq.com> Date: Fri, 16 Jan 2026 11:36:10 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8F=E8=A7=88=E5=99=A8=E6=8C=87=E7=BA=B9?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/request.js | 39 +++++++- src/utils/systemInfo.js | 211 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 247 insertions(+), 3 deletions(-) diff --git a/src/utils/request.js b/src/utils/request.js index dba4f357..ff1a4c02 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -5,7 +5,7 @@ import router from '@/router' import WHITELIST from "./whiteList" import moment from 'moment-timezone'; import { encryptConfig } from "@/utils/encrypt" -import { customAgent } from './fingerprint' +import SystemInfo from "@/utils/systemInfo"; const ROUTER = require('@/router'); axios.defaults.withCredentials = false const service = axios.create({ @@ -27,8 +27,41 @@ service.interceptors.request.use( var language = zzSessionStorage.getItem('lang') config.headers['Accept-Language'] = language === 'en' ? 'en-US,en;q=0.5' : 'zh-CN,zh;q=0.9' config.headers['TimeZoneId'] = moment.tz.guess() - let fingerprint = await customAgent() - config.headers['BrowserFingerprint'] = fingerprint.visitorId + const systemInfo = new SystemInfo(); + const allInfo = systemInfo.getAllInfo(); + let obj = { + browser: { + name: allInfo.browser.name, + version: allInfo.browser.version, + }, + platform: allInfo.platform, + os: { + name: allInfo.os.name, + version: allInfo.os.version + }, + hardware: { + logicalCores: allInfo.hardware.logicalCores, + deviceMemory: allInfo.hardware.deviceMemory + }, + webgl: { + version: allInfo.webgl.version, + renderer: allInfo.webgl.renderer, + vendor: allInfo.webgl.vendor, + shadingLanguage: allInfo.webgl.shadingLanguage, + gpuType: { + type: allInfo.webgl.gpuType.type, + discrete: allInfo.webgl.gpuType.discrete, + }, + performance: { + tier: allInfo.webgl.performance.tier, + }, + extensions: { + length: allInfo.webgl.extensions.length, + } + } + } + let guid = await systemInfo.generateGuid(obj) + config.headers['BrowserFingerprint'] = guid if (config.ENCRYPT) { try { config = await encryptConfig(config) diff --git a/src/utils/systemInfo.js b/src/utils/systemInfo.js index fe1fe00a..f039bc1e 100644 --- a/src/utils/systemInfo.js +++ b/src/utils/systemInfo.js @@ -466,6 +466,217 @@ class SystemInfo { return html; } + deepSortObject(obj) { + if (obj === null || typeof obj !== 'object') { + return obj; + } + + if (Array.isArray(obj)) { + return obj.map(deepSortObject); + } + + const sorted = {}; + Object.keys(obj).sort().forEach(key => { + sorted[key] = this.deepSortObject(obj[key]); + }); + + return sorted; + } + + getCanonicalString(obj) { + if (typeof obj !== 'object' || obj === null) { + return JSON.stringify(obj); + } + + const sorted = this.deepSortObject(obj); + return JSON.stringify(sorted); + } + + // 简单哈希函数 + 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; + } + return hash; + } + + // 简单SHA-256模拟 + simpleSHA256(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; + } + + const hashArray = []; + for (let i = 0; i < 8; i++) { + hashArray[i] = (hash + i * 2654435761) >>> 0; + } + + return hashArray; + } + + // 格式化哈希为GUID + formatHashAsGuid(hashArray) { + const hexParts = hashArray.map(h => h.toString(16).padStart(8, '0')); + return `${hexParts[0]}${hexParts[1].substring(0, 4)}-${hexParts[1].substring(4)}-${hexParts[2].substring(0, 4)}-${hexParts[3].substring(0, 4)}-${hexParts[3].substring(4)}${hexParts[4]}${hexParts[5]}`; + } + + // 1. 确定性哈希算法 + objectToGuidDeterministic(obj) { + const canonicalString = this.getCanonicalString(obj); + const hash = this.simpleSHA256(canonicalString); + return this.formatHashAsGuid(hash).toUpperCase(); + } + + // 2. 伪随机算法 + getSeedFromObject(obj) { + const str = JSON.stringify(obj); + return this.simpleHash(str); + } + + createSeededRandom(seed) { + let state = seed; + return function () { + state = (state * 1664525 + 1013904223) >>> 0; + return (state & 0x3FFFFFFF) / 0x3FFFFFFF; + }; + } + + generateVersion4Guid(randomFn) { + let guid = ''; + + for (let i = 0; i < 32; i++) { + if (i === 8 || i === 12 || i === 16 || i === 20) { + guid += '-'; + } + + if (i === 12) { + guid += '4'; + } else if (i === 16) { + const variant = Math.floor(randomFn() * 4); + guid += (8 + variant).toString(16).toUpperCase(); + } else { + const randomHex = Math.floor(randomFn() * 16).toString(16); + guid += randomHex; + } + } + + return guid.toUpperCase(); + } + + objectToGuidPseudorandom(obj) { + const seed = this.getSeedFromObject(obj); + const prng = this.createSeededRandom(seed); + return this.generateVersion4Guid(prng); + } + + // 3. Crypto API算法(同步版本) + objectToGuidCryptoSync(obj) { + try { + const str = this.getCanonicalString(obj); + let hash = 0; + for (let i = 0; i < str.length; i++) { + const char = str.charCodeAt(i); + hash = ((hash << 5) - hash) + char; + hash = hash & hash; + } + + const bytes = new Array(16); + for (let i = 0; i < 16; i++) { + bytes[i] = (hash + i * 2654435761) & 0xFF; + } + + bytes[6] = (bytes[6] & 0x0F) | 0x40; + bytes[8] = (bytes[8] & 0x3F) | 0x80; + + return bytes.map(b => b.toString(16).padStart(2, '0')) + .join('') + .replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5') + .toUpperCase(); + } catch (error) { + return this.objectToGuidDeterministic(obj); + } + } + + // 4. 组合算法 + combineComponents(deterministicHash, namespaceHash, timestamp, randomComponent) { + const hashDigits = deterministicHash.replace(/-/g, ''); + const bytes = new Array(16); + + for (let i = 0; i < 16; i++) { + const hashByte = parseInt(hashDigits.substr(i * 2, 2), 16) || 0; + const nsByte = (namespaceHash >> (i * 2)) & 0xFF; + const timeByte = (timestamp >> (i * 2)) & 0xFF; + const randomByte = parseInt(randomComponent.substr(i % 8, 1), 16) || 0; + + bytes[i] = (hashByte ^ nsByte ^ timeByte ^ randomByte) & 0xFF; + } + + bytes[6] = (bytes[6] & 0x0F) | 0x40; + bytes[8] = (bytes[8] & 0x3F) | 0x80; + + return bytes.map(b => b.toString(16).padStart(2, '0')) + .join('') + .replace(/(.{8})(.{4})(.{4})(.{4})(.{12})/, '$1-$2-$3-$4-$5') + .toUpperCase(); + } + + objectToGuidCombined(obj, namespace = '') { + const deterministicHash = this.objectToGuidDeterministic(obj); + const namespaceHash = namespace ? this.simpleHash(namespace) : 0; + const timestamp = Date.now(); + const randomComponent = Math.random().toString(16).substr(2, 8); + + return this.combineComponents(deterministicHash, namespaceHash, timestamp, randomComponent); + } + + // 主生成函数 + async generateGuid(inputText, inputType, algorithmType = 'deterministic') { + let obj; + try { + if (inputType === 'json') { + obj = JSON.parse(inputText); + } else { + obj = inputText + } + } catch (error) { + return error; + } + + let guid; + let algorithmName; + try { + switch (algorithmType) { + case 'deterministic': + guid = this.objectToGuidDeterministic(obj); + algorithmName = '确定性哈希算法'; + break; + case 'pseudorandom': + guid = this.objectToGuidPseudorandom(obj); + algorithmName = '伪随机算法'; + break; + case 'crypto': + guid = this.objectToGuidCryptoSync(obj); + algorithmName = 'Crypto API算法'; + break; + case 'combined': + guid = this.objectToGuidCombined(obj, 'example-namespace'); + algorithmName = '组合算法'; + break; + default: + guid = '未知算法'; + algorithmName = '未知'; + } + return guid; + } catch (error) { + return error + } + } } if (typeof module !== 'undefined' && module.exports) {