import { JSDOM } from "npm:jsdom"; import { userAgent } from "./utils.ts"; import crypto from "node:crypto"; // 更详细的类型定义 interface MockMeta { readonly origin: string; readonly stack: string; readonly duration: number; } interface HashResults { server_hashes: string[]; client_hashes: string[]; signals: Record; meta: Record; } interface JSExecutionResult { server_hashes?: string[]; client_hashes?: string[]; signals?: Record; meta?: Record; } const mockMeta: MockMeta = { origin: "https://duckduckgo.com", stack: "", duration: Math.floor(Math.random() * 100) + 1, } as const; class VqdHashGenerator { private static extractIIFEJSDOM(jsCode: string): HashResults { const results: HashResults = { server_hashes: [], client_hashes: [], signals: {}, meta: {}, }; let dom: JSDOM | null = null; try { dom = new JSDOM( ``, { url: "https://duckduckgo.com", referrer: "https://duckduckgo.com", pretendToBeVisual: true, resources: "usable", } ); const { window } = dom; // 设置全局变量 globalThis.window = window; globalThis.document = window.document; // 创建自定义 navigator 对象 const customNavigator = { userAgent: userAgent, platform: "Win32", language: "en-US", languages: ["en-US", "en"], cookieEnabled: true, onLine: true, hardwareConcurrency: 4, maxTouchPoints: 0, vendor: "Google Inc.", vendorSub: "", productSub: "20030107", appName: "Netscape", appVersion: userAgent, product: "Gecko", }; // 重新定义 window.navigator Object.defineProperty(window, "navigator", { value: customNavigator, writable: true, configurable: true, enumerable: true, }); // 设置 globalThis.navigator Object.defineProperty(globalThis, "navigator", { value: customNavigator, writable: true, configurable: true, enumerable: true, }); // 删除 webdriver 属性 delete (window.navigator as any).webdriver; // 执行 JavaScript 代码 const result = window.eval(jsCode) as JSExecutionResult; if (result && typeof result === "object") { results.server_hashes = result.server_hashes || []; results.client_hashes = result.client_hashes || []; results.signals = result.signals || {}; results.meta = result.meta || {}; } } catch (error) { console.error("JSDOM execution failed:", error); throw new Error( `JSDOM执行失败: ${ error instanceof Error ? error.message : String(error) }` ); } finally { // 清理资源 if (dom) { dom.window.close(); } delete globalThis.window; delete globalThis.document; delete globalThis.navigator; } return results; } private static hashClientValues(mockClientHashes: string[]): string[] { return mockClientHashes.map((value: string): string => { const hash = crypto.createHash("sha256"); hash.update(value, "utf8"); return hash.digest("base64"); }); } static generate(vqdHashRequest: string): string { if (!vqdHashRequest || typeof vqdHashRequest !== "string") { throw new Error("VQD Hash 请求参数无效"); } try { // 解码 base64 const jsCode = atob(vqdHashRequest); // 提取和处理 hash const hash = this.extractIIFEJSDOM(jsCode); // 处理客户端 hash hash.client_hashes = this.hashClientValues(hash.client_hashes); // 合并 meta 数据 hash.meta = { ...hash.meta, ...mockMeta, }; // 返回编码后的结果 return btoa(JSON.stringify(hash)); } catch (error) { console.error("generateVqdHash 执行失败:", error); throw new Error( `VQD Hash 生成失败: ${ error instanceof Error ? error.message : String(error) }` ); } } } // 导出函数版本以保持向后兼容 export function generateVqdHash(vqdHashRequest: string): string { return VqdHashGenerator.generate(vqdHashRequest); } // 导出类版本 export { VqdHashGenerator }; export type { HashResults, MockMeta, JSExecutionResult };