// hydevice 指纹运行器: 仿真 Android WebView 环境 -> 真实请求 df/token + df/collect -> 输出 sdid // argv: [stateDir, deviceJson] — deviceJson 为账号画像派生的设备覆盖参数 (一号一设备) process.on('uncaughtException', e => { console.error('[uncaught]', String(e && e.message).slice(0, 120)); }); const fs = require('fs'); const path = require('path'); const https = require('https'); globalThis.window = globalThis; let _deviceOverrides = null; try { _deviceOverrides = JSON.parse(fs.readFileSync(process.argv[3] || '', 'utf8')); } catch (e) {} require(path.join(__dirname, 'env.js')).makeEnv(_deviceOverrides); // ---- localStorage 持久化(设备稳定性) ---- const stateDir = process.argv[2] || '.'; try { fs.mkdirSync(stateDir, {recursive: true}); } catch (e) {} const lsFile = path.join(stateDir, 'localstorage.json'); let _ls = {}; try { _ls = JSON.parse(fs.readFileSync(lsFile, 'utf8')); } catch (e) {} globalThis.localStorage = { getItem: k => (k in _ls ? _ls[k] : null), setItem: (k, v) => { _ls[k] = String(v); try { fs.writeFileSync(lsFile, JSON.stringify(_ls)); } catch (e) {} }, removeItem: k => { delete _ls[k]; try { fs.writeFileSync(lsFile, JSON.stringify(_ls)); } catch (e) {} }, clear: () => { _ls = {}; try { fs.writeFileSync(lsFile, JSON.stringify(_ls)); } catch (e) {} }, key: i => Object.keys(_ls)[i] || null, get length() { return Object.keys(_ls).length; }, }; globalThis.sessionStorage = {getItem: () => null, setItem(){}, removeItem(){}, clear(){}, key: () => null, get length(){ return 0; }}; // ---- 真实 XHR ---- function xhr(url, body, headers) { return new Promise((resolve) => { const u = new URL(url); const data = body == null ? null : Buffer.from(String(body), 'utf8'); const req = https.request({ hostname: u.hostname, port: 443, path: u.pathname + u.search, method: 'POST', headers: Object.assign({ 'accept': 'application/json, text/javascript, */*; q=0.01', 'content-type': 'application/json', 'origin': 'https://aq.huya.com', 'referer': 'https://aq.huya.com/', 'user-agent': globalThis.navigator.userAgent, 'accept-language': 'zh-CN,zh;q=0.9', }, headers || {}), timeout: 15000, }, res => { let chunks = []; res.on('data', c => chunks.push(c)); res.on('end', () => resolve({status: res.statusCode, text: Buffer.concat(chunks).toString('utf8')})); }); req.on('timeout', () => { req.destroy(); resolve({status: 0, text: ''}); }); req.on('error', () => resolve({status: 0, text: ''})); if (data) req.write(data); req.end(); }); } globalThis.XMLHttpRequest = class { open(m, u){ this._m = m; this._u = u; this._h = {}; } setRequestHeader(k, v){ this._h[k] = v; } getAllResponseHeaders(){ return ''; } addEventListener(t, f){ if (t === 'load' || t === 'readystatechange') this._on = f; } send(d){ xhr(this._u, d, this._h).then(r => { this.status = r.status; this.readyState = 4; this.responseText = r.text; this.response = r.text; const done = () => { if (String(this._u).includes('/collect')) { try { const j = JSON.parse(r.text); if (j && j.data) { if (j.data.sdid) console.log('__SDID__' + j.data.sdid); if (j.data.hdid) console.log('__HDID__' + j.data.hdid); setTimeout(() => process.exit(0), 200); } } catch (e) {} } try { this.onreadystatechange && this.onreadystatechange(); } catch (e) {} try { this._on && this._on(); } catch (e) {} try { this.onload && this.onload(); } catch (e) {} }; setTimeout(done, 30); }); } }; eval(fs.readFileSync(path.join(__dirname, 'hydevice-prod-1.2.45-min.js'), 'utf8')); try { globalThis.initFingerprint(process.argv[3] || '5008'); } catch (e) { console.error('[init]', e.message.slice(0, 120)); } setTimeout(() => { console.error('__TIMEOUT__'); process.exit(2); }, 25000);