// 人机验证全链路自测(Node 侧算 PoW,与服务端 webcrypto 同算法) import crypto from 'node:crypto'; const BASE = 'https://api.200181.xyz/api/v2/human'; const POW_DIFFICULTY = 4; function sha256Hex(s) { return crypto.createHash('sha256').update(s).digest('hex'); } function solve(challenge, difficulty) { const prefix = '0'.repeat(difficulty); const t0 = Date.now(); for (let nonce = 0; nonce < 5_000_000; nonce++) { if (sha256Hex(challenge + nonce).startsWith(prefix)) { return { nonce, ms: Date.now() - t0, tries: nonce + 1 }; } } throw new Error('no solution'); } async function j(path, init) { const r = await fetch(BASE + path, init); const text = await r.text(); try { return { status: r.status, body: JSON.parse(text) }; } catch { return { status: r.status, body: text.slice(0, 200) }; } } async function main() { console.log('--- 1) GET /human/challenge'); const ch = await j('/challenge'); console.log(' ', ch.status, JSON.stringify(ch.body).slice(0, 160)); if (!ch.body || ch.body.enabled !== true) { console.log('开关没开(human_check 不是 1),先设置 KV 再测'); return; } console.log('--- 2) POST /human/verify 错误 PoW(应 need_captcha)'); const bad = await j('/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ challenge: ch.body.challenge, nonce: 12345, exp: ch.body.exp, sig: ch.body.sig, elapsedMs: 5000, events: 30, }), }); console.log(' ', bad.status, JSON.stringify(bad.body)); console.log('--- 3) 正确 PoW + 无交互信号(应 need_click)'); const sol = solve(ch.body.challenge, POW_DIFFICULTY); console.log(` 解出 nonce=${sol.nonce}(${sol.tries} 次尝试 / ${sol.ms}ms)`); const mid = await j('/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ challenge: ch.body.challenge, nonce: sol.nonce, exp: ch.body.exp, sig: ch.body.sig, elapsedMs: 300, events: 0, }), }); console.log(' ', mid.status, JSON.stringify(mid.body)); console.log('--- 4) 蜜罐被填(应 need_captcha)'); const honey = await j('/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ challenge: ch.body.challenge, nonce: sol.nonce, exp: ch.body.exp, sig: ch.body.sig, elapsedMs: 8000, events: 12, honeypot: 'bot@example.com', }), }); console.log(' ', honey.status, JSON.stringify(honey.body)); console.log('--- 5) 正确 PoW + 有交互(应 pass:true 并下发通行证)'); const okRes = await j('/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ challenge: ch.body.challenge, nonce: sol.nonce, exp: ch.body.exp, sig: ch.body.sig, elapsedMs: 8000, events: 12, }), }); console.log(' ', okRes.status, JSON.stringify(okRes.body)); console.log('--- 6) GET /human/status(应 pass:true,说明 KV 通行证生效)'); const st = await j('/status'); console.log(' ', st.status, JSON.stringify(st.body)); } main().catch((e) => console.error('ERR', e.message));