function challengeOptions(job){ let raw=job&&job.payload; if(!raw) return []; if(typeof raw==='string'){ try{ raw=JSON.parse(raw); }catch(e){ return []; } } const opts=raw&&raw.challenge_options; return Array.isArray(opts)?opts.filter(o=>o&&o.id):[]; } function challengeLabel(opt){ const label=String((opt&&opt.label)||(opt&&opt.kind)||'验证方式'); const hint=String((opt&&opt.hint)||'').trim(); if(!hint || label.indexOf(hint)>=0) return label; return label+'('+hint+')'; } async function solve(id){ const j0=await api('/api/jobs/'+id); const hint=String((j0&&j0.challenge_hint)||''); const kind=String((j0&&j0.challenge_type)||''); const opts=challengeOptions(j0); if(kind==='2sv' && opts.length){ const picked=await askChallenge(j0, opts); if(!picked) return; const body={choice:String(picked.id||'')}; if(picked.code) body.code=String(picked.code).trim(); const j=await api('/api/jobs/'+id+'/challenge',{method:'POST',body:JSON.stringify(body)}); if(j.error) return fail('无法提交', j.error); notice('已选择验证方式', challengeLabel(picked)); render(); return; } if(kind==='prompt'){ const promptOpt=opts.find(o=>o&&String(o.prompt||'').trim())||opts[0]||{}; const ok=await askDevicePrompt(j0, promptOpt, hint); if(!ok) return; const j=await api('/api/jobs/'+id+'/challenge',{method:'POST',body:JSON.stringify({choice:'done'})}); if(j.error) return fail('无法继续', j.error); notice('已确认', '继续登录'); render(); return; } const lines=hint.split('\n').map(s=>s.trim()).filter(Boolean); const url=lines.filter(s=>/^https?:\/\//.test(s)).pop()||''; const text=lines.filter(s=>s!==url).join('\n')||(kind==='3ds'?'需要 3DS 验证':'请输入验证码'); const message=text+(url?('\n'+url):''); const code=await ask(kind==='3ds'?'3DS 验证':'填写验证码', message, '', '验证码'); if(code===null) return; const j=await api('/api/jobs/'+id+'/challenge',{method:'POST',body:JSON.stringify({code:String(code||'').trim()})}); if(j.error) return fail('无法提交', j.error); notice('已提交验证码', '任务 #'+(j.job_id||id)); const account=(j0&&j0.account_id)||0; if(account) watchAccountJob(account, 'bind', id, '验证卡'); render(); } function askDevicePrompt(job, opt, hint){ return new Promise(resolve=>{ const root=$('#modalRoot'); const number=String((opt&&opt.prompt)||'').trim(); const detail=String((opt&&opt.detail)||'').trim(); const big=number?'
'+esc(number)+'
在已登录的手机或平板上,三个数字里点这一个
':''; root.innerHTML=''; const close=v=>{ root.innerHTML=''; resolve(v); }; $('#mCancel').onclick=()=>close(null); $('#mOk').onclick=()=>close(true); bindMaskClose(root, ()=>close(null)); }); } function askChallenge(job, opts){ return new Promise(resolve=>{ const root=$('#modalRoot'); const rows=opts.map((o,i)=>'').join(''); const hint=String((job&&job.challenge_hint)||'这个账号需要二次验证。请选择页面上列出的方式。'); root.innerHTML=''; const close=v=>{ root.innerHTML=''; resolve(v); }; $('#mCancel').onclick=()=>close(null); $('#mOk').onclick=()=>{ const picked=root.querySelector('input[name="chg"]:checked'); if(!picked) return; const opt=opts.find(o=>String(o.id)===picked.value)||{id:picked.value}; close({id:opt.id, kind:opt.kind, label:opt.label, code:$('#chgCode').value}); }; bindMaskClose(root, ()=>close(null)); }); }