// 在真 Chrome(9222) 里拉起 1ms 的腾讯验证码。 // 用法: node tools/cdp_show_captcha.js function arg(name, def) { const i = process.argv.indexOf('--' + name); if (i < 0) return def; const v = process.argv[i + 1]; return (v === undefined || v.startsWith('--')) ? true : v; } const sleep = ms => new Promise(r => setTimeout(r, ms)); class Cdp { constructor(ws) { this.ws = ws; this.id = 0; this.waits = new Map(); this.handlers = []; } static async connect(url) { const ws = new WebSocket(url); await new Promise((res, rej) => { ws.onopen = res; ws.onerror = rej; }); const c = new Cdp(ws); ws.onmessage = ev => { const m = JSON.parse(ev.data); if (m.id && c.waits.has(m.id)) { const { res, rej } = c.waits.get(m.id); c.waits.delete(m.id); m.error ? rej(new Error(JSON.stringify(m.error))) : res(m.result); } else if (m.method) { for (const h of c.handlers) h(m); } }; return c; } send(method, params = {}) { const id = ++this.id; this.ws.send(JSON.stringify({ id, method, params })); return new Promise((res, rej) => this.waits.set(id, { res, rej })); } on(fn) { this.handlers.push(fn); } close() { try { this.ws.close(); } catch (e) {} } } async function listTargets(port) { const r = await fetch(`http://127.0.0.1:${port}/json/list`); return r.json(); } (async () => { const port = parseInt(arg('port', '9222'), 10); const aid = arg('aid', '195672344'); const pageUrl = arg('url', 'https://1ms.run/'); const targets = await listTargets(port); let page = targets.find(t => t.type === 'page' && !(t.url || '').startsWith('chrome')); if (!page) throw new Error('没有可用页面 target'); const cdp = await Cdp.connect(page.webSocketDebuggerUrl); await cdp.send('Page.enable'); await cdp.send('Runtime.enable'); console.log(`[1] 导航到 ${pageUrl}`); await cdp.send('Page.navigate', { url: pageUrl }); await sleep(4000); console.log(`[2] 注入 TCaptcha SDK 并 show(aid=${aid})`); const expr = `(async () => { const load = (src) => new Promise((res, rej) => { const s = document.createElement('script'); s.src = src; s.onload = () => res(true); s.onerror = () => rej(new Error('fail')); document.head.appendChild(s); }); if (typeof window.TencentCaptcha !== 'function') await load('https://ssl.captcha.qq.com/TCaptcha.js'); window.__capres = null; window.__cap = new window.TencentCaptcha('${aid}', function (r) { window.__capres = r; }, {}); window.__cap.show(); return {ok: true}; })()`; const r = await cdp.send('Runtime.evaluate', { expression: expr, awaitPromise: true, returnByValue: true }); console.log(' ', JSON.stringify(r.result && r.result.value)); await sleep(2500); const t2 = await listTargets(port); console.log('[3] 当前 targets:'); for (const t of t2) console.log(` ${t.type}\t${(t.url || '').slice(0, 100)}`); cdp.close(); })().catch(e => { console.error('ERR', e.message); process.exit(1); });