mirror of
https://github.com/black-ant/Ant-Browser.git
synced 2026-07-14 18:48:55 +08:00
publish: 1.0.0 snapshot (bad2ec1)
channel: master version: 1.0.0 source-ref: master published-at-utc: 2026-03-13T15:19:28Z
This commit is contained in:
@@ -0,0 +1,350 @@
|
||||
// 指纹参数序列化/反序列化工具
|
||||
|
||||
/**
|
||||
* 获取系统当前时区
|
||||
* @returns IANA 时区标识符,如 "Asia/Shanghai"
|
||||
*/
|
||||
export function getSystemTimezone(): string {
|
||||
try {
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
} catch {
|
||||
return 'UTC'
|
||||
}
|
||||
}
|
||||
|
||||
export interface FingerprintConfig {
|
||||
// 指纹种子(核心)
|
||||
seed?: string // --fingerprint=<seed> 控制所有随机噪声的根种子
|
||||
|
||||
// 基础身份
|
||||
brand?: string // --fingerprint-brand=
|
||||
platform?: string // --fingerprint-platform=
|
||||
lang?: string // --lang=
|
||||
timezone?: string // --timezone=
|
||||
|
||||
// 屏幕与窗口
|
||||
resolution?: string // --window-size=(预设值或 'custom')
|
||||
customResolution?: string // 当 resolution === 'custom' 时使用
|
||||
colorDepth?: string // --fingerprint-color-depth=
|
||||
|
||||
// 硬件信息
|
||||
hardwareConcurrency?: string // --fingerprint-hardware-concurrency=
|
||||
deviceMemory?: string // --fingerprint-device-memory=
|
||||
|
||||
// 渲染指纹
|
||||
canvasNoise?: boolean // --fingerprint-canvas-noise=
|
||||
webglVendor?: string // --fingerprint-webgl-vendor=
|
||||
webglRenderer?: string // --fingerprint-webgl-renderer=
|
||||
audioNoise?: boolean // --fingerprint-audio-noise=
|
||||
|
||||
// 字体
|
||||
fonts?: string // --fingerprint-fonts=
|
||||
|
||||
// 网络与隐私
|
||||
webrtcPolicy?: string // --webrtc-ip-handling-policy=
|
||||
doNotTrack?: boolean // --fingerprint-do-not-track=
|
||||
|
||||
// 媒体设备
|
||||
mediaDevices?: string // --fingerprint-media-devices= (格式: "2,1,0" 摄像头,麦克风,扬声器)
|
||||
|
||||
// 触摸
|
||||
touchPoints?: string // --fingerprint-touch-points=
|
||||
|
||||
unknownArgs?: string[] // 无法识别的原始参数,原样保留
|
||||
}
|
||||
|
||||
export const PRESET_RESOLUTIONS = ['1920,1080', '1440,900', '1366,768', '2560,1440', '1280,800', '1600,900']
|
||||
|
||||
// CLI 参数前缀 → FingerprintConfig 字段映射
|
||||
export const KEY_MAP: Record<string, keyof FingerprintConfig> = {
|
||||
'--fingerprint': 'seed',
|
||||
'--fingerprint-brand': 'brand',
|
||||
'--fingerprint-platform': 'platform',
|
||||
'--lang': 'lang',
|
||||
'--timezone': 'timezone',
|
||||
'--window-size': 'resolution',
|
||||
'--fingerprint-color-depth': 'colorDepth',
|
||||
'--fingerprint-hardware-concurrency': 'hardwareConcurrency',
|
||||
'--fingerprint-device-memory': 'deviceMemory',
|
||||
'--fingerprint-canvas-noise': 'canvasNoise',
|
||||
'--fingerprint-webgl-vendor': 'webglVendor',
|
||||
'--fingerprint-webgl-renderer': 'webglRenderer',
|
||||
'--fingerprint-audio-noise': 'audioNoise',
|
||||
'--fingerprint-fonts': 'fonts',
|
||||
'--webrtc-ip-handling-policy': 'webrtcPolicy',
|
||||
'--fingerprint-do-not-track': 'doNotTrack',
|
||||
'--fingerprint-media-devices': 'mediaDevices',
|
||||
'--fingerprint-touch-points': 'touchPoints',
|
||||
}
|
||||
|
||||
// FingerprintConfig → string[]
|
||||
export function serialize(config: FingerprintConfig): string[] {
|
||||
const args: string[] = []
|
||||
if (config.seed) args.push(`--fingerprint=${config.seed}`)
|
||||
if (config.brand) args.push(`--fingerprint-brand=${config.brand}`)
|
||||
if (config.platform) args.push(`--fingerprint-platform=${config.platform}`)
|
||||
if (config.lang) args.push(`--lang=${config.lang}`)
|
||||
if (config.timezone) {
|
||||
// 如果是 system,替换为实际系统时区
|
||||
const tz = config.timezone === 'system' ? getSystemTimezone() : config.timezone
|
||||
args.push(`--timezone=${tz}`)
|
||||
}
|
||||
|
||||
const res = config.resolution === 'custom' ? config.customResolution : config.resolution
|
||||
if (res) args.push(`--window-size=${res}`)
|
||||
|
||||
if (config.colorDepth) args.push(`--fingerprint-color-depth=${config.colorDepth}`)
|
||||
if (config.hardwareConcurrency) args.push(`--fingerprint-hardware-concurrency=${config.hardwareConcurrency}`)
|
||||
if (config.deviceMemory) args.push(`--fingerprint-device-memory=${config.deviceMemory}`)
|
||||
|
||||
if (config.canvasNoise !== undefined) args.push(`--fingerprint-canvas-noise=${config.canvasNoise}`)
|
||||
if (config.webglVendor) args.push(`--fingerprint-webgl-vendor=${config.webglVendor}`)
|
||||
if (config.webglRenderer) args.push(`--fingerprint-webgl-renderer=${config.webglRenderer}`)
|
||||
if (config.audioNoise !== undefined) args.push(`--fingerprint-audio-noise=${config.audioNoise}`)
|
||||
|
||||
if (config.fonts) args.push(`--fingerprint-fonts=${config.fonts}`)
|
||||
|
||||
if (config.webrtcPolicy) args.push(`--webrtc-ip-handling-policy=${config.webrtcPolicy}`)
|
||||
if (config.doNotTrack !== undefined) args.push(`--fingerprint-do-not-track=${config.doNotTrack}`)
|
||||
if (config.mediaDevices) args.push(`--fingerprint-media-devices=${config.mediaDevices}`)
|
||||
if (config.touchPoints) args.push(`--fingerprint-touch-points=${config.touchPoints}`)
|
||||
|
||||
return [...args, ...(config.unknownArgs ?? [])]
|
||||
}
|
||||
|
||||
// string[] → FingerprintConfig
|
||||
export function deserialize(args: string[]): FingerprintConfig {
|
||||
const config: FingerprintConfig = { unknownArgs: [] }
|
||||
|
||||
for (const arg of args) {
|
||||
const eqIdx = arg.indexOf('=')
|
||||
if (eqIdx === -1) {
|
||||
config.unknownArgs!.push(arg)
|
||||
continue
|
||||
}
|
||||
const key = arg.slice(0, eqIdx)
|
||||
const val = arg.slice(eqIdx + 1)
|
||||
const field = KEY_MAP[key]
|
||||
|
||||
if (!field) {
|
||||
config.unknownArgs!.push(arg)
|
||||
continue
|
||||
}
|
||||
|
||||
if (field === 'canvasNoise' || field === 'audioNoise' || field === 'doNotTrack') {
|
||||
(config as Record<string, unknown>)[field] = val === 'true'
|
||||
} else if (field === 'resolution') {
|
||||
if (PRESET_RESOLUTIONS.includes(val)) {
|
||||
config.resolution = val
|
||||
} else {
|
||||
config.resolution = 'custom'
|
||||
config.customResolution = val
|
||||
}
|
||||
} else {
|
||||
(config as Record<string, unknown>)[field] = val
|
||||
}
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// 生成随机指纹种子(32位正整数)
|
||||
export function randomFingerprintSeed(): string {
|
||||
return String(Math.floor(Math.random() * 2147483647) + 1)
|
||||
}
|
||||
|
||||
// ─── 预设指纹配置 ────────────────────────────────────────────────────────────
|
||||
|
||||
export interface FingerprintPreset {
|
||||
id: string
|
||||
name: string
|
||||
description: string
|
||||
config: Partial<FingerprintConfig>
|
||||
}
|
||||
|
||||
export const FINGERPRINT_PRESETS: FingerprintPreset[] = [
|
||||
{
|
||||
id: 'win-chrome-office',
|
||||
name: 'Windows / Chrome / 办公',
|
||||
description: '模拟国内办公室 Windows 用户,中文环境,1920x1080',
|
||||
config: {
|
||||
brand: 'Chrome',
|
||||
platform: 'windows',
|
||||
lang: 'zh-CN',
|
||||
timezone: 'Asia/Shanghai',
|
||||
resolution: '1920,1080',
|
||||
colorDepth: '24',
|
||||
hardwareConcurrency: '8',
|
||||
deviceMemory: '8',
|
||||
canvasNoise: true,
|
||||
audioNoise: true,
|
||||
webglVendor: 'Intel',
|
||||
webglRenderer: 'Intel(R) UHD Graphics 630',
|
||||
fonts: 'Arial,Microsoft YaHei,SimSun,SimHei,Helvetica,Times New Roman',
|
||||
webrtcPolicy: 'disable_non_proxied_udp',
|
||||
doNotTrack: false,
|
||||
touchPoints: '0',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'win-chrome-gaming',
|
||||
name: 'Windows / Chrome / 游戏主机',
|
||||
description: '模拟高配游戏 PC,NVIDIA 显卡,2560x1440',
|
||||
config: {
|
||||
brand: 'Chrome',
|
||||
platform: 'windows',
|
||||
lang: 'en-US',
|
||||
timezone: 'America/New_York',
|
||||
resolution: '2560,1440',
|
||||
colorDepth: '24',
|
||||
hardwareConcurrency: '16',
|
||||
deviceMemory: '16',
|
||||
canvasNoise: true,
|
||||
audioNoise: true,
|
||||
webglVendor: 'NVIDIA',
|
||||
webglRenderer: 'NVIDIA GeForce RTX 3080',
|
||||
fonts: 'Arial,Helvetica,Times New Roman,Courier New,Verdana',
|
||||
webrtcPolicy: 'disable_non_proxied_udp',
|
||||
doNotTrack: false,
|
||||
touchPoints: '0',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'mac-chrome-designer',
|
||||
name: 'macOS / Chrome / 设计师',
|
||||
description: '模拟 Mac 设计师用户,Apple GPU,Retina 分辨率',
|
||||
config: {
|
||||
brand: 'Chrome',
|
||||
platform: 'mac',
|
||||
lang: 'zh-CN',
|
||||
timezone: 'Asia/Shanghai',
|
||||
resolution: '2560,1440',
|
||||
colorDepth: '30',
|
||||
hardwareConcurrency: '10',
|
||||
deviceMemory: '16',
|
||||
canvasNoise: true,
|
||||
audioNoise: true,
|
||||
webglVendor: 'Apple',
|
||||
webglRenderer: 'Apple M2',
|
||||
fonts: 'Arial,Helvetica,PingFang SC,Hiragino Sans GB,STHeiti,Times New Roman',
|
||||
webrtcPolicy: 'disable_non_proxied_udp',
|
||||
doNotTrack: true,
|
||||
touchPoints: '0',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'win-edge-enterprise',
|
||||
name: 'Windows / Edge / 企业',
|
||||
description: '模拟企业 Windows 用户,Edge 浏览器,标准配置',
|
||||
config: {
|
||||
brand: 'Edge',
|
||||
platform: 'windows',
|
||||
lang: 'zh-CN',
|
||||
timezone: 'Asia/Shanghai',
|
||||
resolution: '1366,768',
|
||||
colorDepth: '24',
|
||||
hardwareConcurrency: '4',
|
||||
deviceMemory: '4',
|
||||
canvasNoise: true,
|
||||
audioNoise: false,
|
||||
webglVendor: 'Intel',
|
||||
webglRenderer: 'Intel(R) HD Graphics 520',
|
||||
fonts: 'Arial,Microsoft YaHei,Calibri,Segoe UI,Times New Roman',
|
||||
webrtcPolicy: 'default_public_interface_only',
|
||||
doNotTrack: false,
|
||||
touchPoints: '0',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'win-chrome-us-user',
|
||||
name: 'Windows / Chrome / 美国用户',
|
||||
description: '模拟美国普通用户,英文环境,AMD 显卡',
|
||||
config: {
|
||||
brand: 'Chrome',
|
||||
platform: 'windows',
|
||||
lang: 'en-US',
|
||||
timezone: 'America/Los_Angeles',
|
||||
resolution: '1920,1080',
|
||||
colorDepth: '24',
|
||||
hardwareConcurrency: '8',
|
||||
deviceMemory: '8',
|
||||
canvasNoise: true,
|
||||
audioNoise: true,
|
||||
webglVendor: 'AMD',
|
||||
webglRenderer: 'AMD Radeon RX 6600',
|
||||
fonts: 'Arial,Helvetica,Times New Roman,Courier New,Georgia',
|
||||
webrtcPolicy: 'disable_non_proxied_udp',
|
||||
doNotTrack: false,
|
||||
touchPoints: '0',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'mac-safari-jp',
|
||||
name: 'macOS / Safari / 日本用户',
|
||||
description: '模拟日本 Mac 用户,Safari 风格,日语环境',
|
||||
config: {
|
||||
brand: 'Safari',
|
||||
platform: 'mac',
|
||||
lang: 'ja-JP',
|
||||
timezone: 'Asia/Tokyo',
|
||||
resolution: '1440,900',
|
||||
colorDepth: '24',
|
||||
hardwareConcurrency: '8',
|
||||
deviceMemory: '8',
|
||||
canvasNoise: true,
|
||||
audioNoise: true,
|
||||
webglVendor: 'Apple',
|
||||
webglRenderer: 'Apple M1',
|
||||
fonts: 'Arial,Helvetica,Hiragino Kaku Gothic ProN,Yu Gothic,Times New Roman',
|
||||
webrtcPolicy: 'disable_non_proxied_udp',
|
||||
doNotTrack: true,
|
||||
touchPoints: '0',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'win-chrome-uk-office',
|
||||
name: 'Windows / Chrome / 英国-办公',
|
||||
description: '模拟英国办公室 Windows 用户,英文环境 (en-GB)',
|
||||
config: {
|
||||
brand: 'Chrome',
|
||||
platform: 'windows',
|
||||
lang: 'en-GB',
|
||||
timezone: 'Europe/London',
|
||||
resolution: '1920,1080',
|
||||
colorDepth: '24',
|
||||
hardwareConcurrency: '8',
|
||||
deviceMemory: '8',
|
||||
canvasNoise: true,
|
||||
audioNoise: true,
|
||||
webglVendor: 'Intel',
|
||||
webglRenderer: 'Intel(R) UHD Graphics 630',
|
||||
fonts: 'Arial,Helvetica,Times New Roman,Courier New,Verdana',
|
||||
webrtcPolicy: 'disable_non_proxied_udp',
|
||||
doNotTrack: false,
|
||||
touchPoints: '0',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'mac-chrome-us-edu',
|
||||
name: 'macOS / Chrome / 美国-教育',
|
||||
description: '模拟美国大学教育网 Mac 用户,英文环境 (en-US)',
|
||||
config: {
|
||||
brand: 'Chrome',
|
||||
platform: 'mac',
|
||||
lang: 'en-US',
|
||||
timezone: 'America/New_York',
|
||||
resolution: '1440,900',
|
||||
colorDepth: '24',
|
||||
hardwareConcurrency: '8',
|
||||
deviceMemory: '8',
|
||||
canvasNoise: true,
|
||||
audioNoise: true,
|
||||
webglVendor: 'Apple',
|
||||
webglRenderer: 'Apple M1',
|
||||
fonts: 'Arial,Helvetica,Times New Roman,Courier New,Georgia',
|
||||
webrtcPolicy: 'disable_non_proxied_udp',
|
||||
doNotTrack: false,
|
||||
touchPoints: '0',
|
||||
},
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user