logo
Public
0
0
WeChat Login
chore(task): complete RCM-003 add fingerprint scope helpers

Fingerprint

lib/fingerprint 用于生成可注入到页面的新文档脚本,帮助 rod 在授权测试、兼容性研究、浏览器行为回放里统一定制浏览器暴露面的指纹值。

当前支持的表面:

  • navigatornavigator.userAgentData 与硬件相关字段(如 oscpucpuClassvendorSubproductSubpdfViewerEnabled
  • screenwindow.devicePixelRatio
  • IntlresolvedOptions(含 calendarnumberingSystemhourCycle)与 Date.prototype.getTimezoneOffset
  • navigator.permissionsNotification
  • navigator.mediaDevices
  • navigator.pluginsnavigator.mimeTypes
  • document.fonts.checkqueryLocalFontsCanvasRenderingContext2D.measureText
  • navigator.getBattery
  • navigator.connection / navigator.mozConnection / navigator.webkitConnection(含真实 EventTarget listener 存储)
  • speechSynthesis.getVoices()
  • AudioContext
  • canvas
  • WebGL(含 extensionsparameters 深度覆盖)
  • RTCPeerConnection WebRTC 泄露防护(disable / relay 模式)
  • navigator.storage.estimate() StorageManager
  • performance.now() / Date.now() 精度降噪
  • Function.prototype.toString 伪装(反检测基础设施)
  • Object.getOwnPropertyDescriptor 防御(反检测基础设施)
  • Worker(classic + module)内 navigator 一致性
  • iframe contentWindow navigator 一致性

模块内部已经按职责拆为:

  • types.go:公开配置 struct
  • validate.go:参数校验与 enabled 判定
  • source.go:payload 序列化与脚本拼接
  • script_common.go:共享 runtime 原语、toString 伪装、OwnPropertyDescriptor 防御
  • script_navigator.gonavigator / permissions / notification
  • script_environment.gofonts / intl / battery / network / screen / storageManager / timing
  • script_media.gomediaDevices / plugins / mimeTypes / audioContext / speechSynthesis
  • script_rendering.gocanvas / webgl
  • script_webrtc.go:WebRTC 泄露防护
  • script_worker.go:Worker(classic + module)内 navigator 一致性
  • script_frame.go:iframe contentWindow navigator 一致性

根层推荐优先通过 rod.Page.WithFingerprintrod.Page.MustWithFingerprint 使用;SetFingerprint / MustSetFingerprint 仍保留给需要手动管理生命周期的底层场景:

webdriver := false page.MustWithFingerprint(&rod.Fingerprint{ Navigator: &rod.NavigatorFingerprint{ UserAgent: rod.Ptr("RodAgent/1.0"), Platform: rod.Ptr("RodOS"), Language: rod.Ptr("zh-CN"), Languages: rod.Ptr([]string{"zh-CN", "zh"}), OSCPU: rod.Ptr("RodOSCPU"), CPUClass: rod.Ptr("x86"), HardwareConcurrency: rod.Ptr(0), DeviceMemory: rod.Ptr(0.0), MaxTouchPoints: rod.Ptr(0), WebDriver: &webdriver, UAData: &rod.NavigatorUADataFingerprint{ Brands: rod.Ptr([]rod.NavigatorBrandFingerprint{{Brand: "Rod", Version: "1"}}), FullVersionList: rod.Ptr([]rod.NavigatorBrandFingerprint{{Brand: "Rod", Version: "1.0.0.0"}}), Platform: rod.Ptr("RodOS"), }, }, Intl: &rod.IntlFingerprint{ TimeZone: rod.Ptr("Asia/Shanghai"), OffsetMinutes: rod.Ptr(-480), Calendar: rod.Ptr("gregory"), NumberingSystem: rod.Ptr("latn"), HourCycle: rod.Ptr("h23"), }, Fonts: &rod.FontsFingerprint{ Families: rod.Ptr([]string{"Rod Sans", "Rod Mono"}), WidthMultipliers: rod.Ptr(map[string]float64{ "Rod Sans": 1.5, }), }, Notification: &rod.NotificationFingerprint{ Permission: rod.Ptr("denied"), }, MediaDevices: &rod.MediaDevicesFingerprint{ Devices: rod.Ptr([]rod.MediaDeviceFingerprint{ { DeviceID: "rod-mic-1", Kind: "audioinput", Label: "Rod Mic", }, }), }, Battery: &rod.BatteryFingerprint{ Level: rod.Ptr(0.42), }, NetworkInformation: &rod.NetworkInformationFingerprint{ EffectiveType: rod.Ptr("4g"), Type: rod.Ptr("wifi"), }, WebGL: &rod.WebGLFingerprint{ Vendor: rod.Ptr("Google Inc. (NVIDIA)"), Renderer: rod.Ptr("ANGLE (NVIDIA GeForce RTX 3060)"), Extensions: rod.Ptr([]string{ "ANGLE_instanced_arrays", "EXT_blend_minmax", "WEBGL_debug_renderer_info", }), Parameters: rod.Ptr(map[string]any{ "7938": "WebGL 1.0 (OpenGL ES 2.0 Chromium)", }), }, WebRTC: &rod.WebRTCFingerprint{ Mode: rod.Ptr("relay"), // "disable" 完全禁用 | "relay" 强制中继 PublicIP: rod.Ptr("1.2.3.4"), // 仅 relay 模式下替换 SDP 中的 IP }, SpeechSynthesis: &rod.SpeechSynthesisFingerprint{ Voices: rod.Ptr([]rod.SpeechVoiceFingerprint{ {Name: "Microsoft Huihui", Lang: "zh-CN", LocalService: rod.Ptr(true)}, }), }, StorageManager: &rod.StorageManagerFingerprint{ Quota: rod.Ptr(int64(2147483648)), Usage: rod.Ptr(int64(1048576)), }, Timing: &rod.TimingFingerprint{ Precision: rod.Ptr(100.0), // 微秒量化精度 Jitter: rod.Ptr(5.0), // 最大抖动微秒 }, }, func() { page.MustNavigate("https://example.com").MustWaitLoad() })

如果需要直接使用底层包,可调用:

  • fingerprint.ApplySource(id, cfg)
  • fingerprint.RemoveSource(id)
  • fingerprint.Ptr(v)

这样可以把脚本注入到你自己的 CDP / browser orchestration 流程里。

lib/fingerprint 现在已经按 presence-driven pointer-style 收口主要 surface:nil 表示不覆盖,非 nil 则即便是 ""[]{}0false 也会被显式注入。需要表达空值时,不要依赖 Go 零值,直接传 pointer-style 字段。当前已覆盖:

  • navigator.*navigator.userAgentData.*
  • screen.*devicePixelRatio
  • Intl.*
  • permissions / notification
  • mediaDevices / plugins / mimeTypes / fonts
  • battery / networkInformation
  • audioContext / canvas / webgl / webrtc / speechSynthesis
  • storageManager / timing