function obidSpec(pkg){
pkg=String(pkg||'');
if(pkg==='ai.x.grok'||pkg==='ai.x.grok.bot') return {label:'SSO', hint:'grok.com 的 sso cookie / JWT', mode:'grok'};
if(pkg==='com.anysphere.cursor') return {label:'用户 ID', hint:'Cursor 用户 ID,原值作为 obfuscatedAccountId', mode:'raw'};
if(pkg==='com.twitter.android') return {label:'用户 ID', hint:'X 用户 ID,原值作为 obfuscatedAccountId', mode:'raw'};
if(pkg==='com.anthropic.claude') return {label:'Session Key', hint:'sk- 开头的 sessionKey,购买时解析 Organization ID 和 Account UUID', mode:'claude'};
if(pkg==='com.discord') return {label:'用户 Authorization', hint:'Discord token,先解出用户 ID 再 SHA-256 hex', mode:'discord'};
if(pkg==='com.openai.chatgpt') return {label:'用户 ID', hint:'ChatGPT 用户 ID,SHA-256 Base64', mode:'b64'};
return null;
}
async function sha256Bytes(text){
const data=new TextEncoder().encode(String(text||''));
const buf=await crypto.subtle.digest('SHA-256', data);
return new Uint8Array(buf);
}
function discordUserId(token){
token=String(token||'').trim();
const part=token.split('.')[0].replace(/=+$/,'').replace(/-/g,'+').replace(/_/g,'/');
if(!part) throw new Error('token 格式无效');
const pad=part+'='.repeat((4-part.length%4)%4);
const id=atob(pad);
if(!/^[0-9]+$/.test(id)) throw new Error('解码结果不是数字 user-id');
return id;
}
async function obidValue(mode, raw){
raw=String(raw||'').trim();
if(!raw) return {account:'', profile:''};
if(mode==='raw') return {account:raw, profile:''};
if(mode==='discord'){
const id=discordUserId(raw);
const bytes=await sha256Bytes(id);
return {account:[...bytes].map(b=>b.toString(16).padStart(2,'0')).join(''), profile:''};
}
if(mode==='b64'){
const bytes=await sha256Bytes(raw);
let s=''; bytes.forEach(b=>{ s+=String.fromCharCode(b); });
return {account:btoa(s), profile:''};
}
if(mode==='grok'||mode==='claude'){
const j=await api('/api/purchases/obid',{method:'POST',body:JSON.stringify({package:mode==='grok'?'ai.x.grok':'com.anthropic.claude', input:raw, account_id:window._obidAccount||0})});
if(j.error) throw new Error(j.error);
return {account:j.obfuscated_account_id||'', profile:j.obfuscated_profile_id||'', subscriptions:j.subscriptions||[]};
}
return {account:raw, profile:''};
}
function viewCards(){
const dock=document.getElementById('pagerDock');
const all=(cache.cards||[]).filter(c=>{
if(!c) return false;
if(filters.cardHidden==='hidden' && !c.hidden) return false;
if(filters.cardHidden!=='hidden' && filters.cardHidden!=='all' && c.hidden) return false;
return matchQ([c.brand,c.scheme,c.type,c.bank,c.country,c.country_a2,c.last4,c.bin,c.pan,c.note,String(c.id)]);
});
const info=paginate(all,'cards');
const rows=info.slice.map(c=>{
const exp=String(c.exp_month||'').padStart(2,'0')+'/'+String(c.exp_year||'').slice(-2);
return '
'+
'| #'+c.id+' | '+
''+esc(c.brand||c.scheme||'-')+' '+esc([c.scheme,c.type,c.prepaid?'预付':''].filter(Boolean).join(' · '))+' | '+
''+esc(cardPAN(c)||c.last4||'-')+' | '+
''+esc(exp)+' | '+
''+esc(c.bank||'-')+' '+esc(countryLabel(c.country_a2||c.country||''))+' | '+
''+(c.hidden?'已隐藏':'可用')+' | '+
''+esc(c.note||'')+' | '+
''+fmtTime(c.created_at)+' | '+
' | '+
'
';
}).join('');
$('#app').innerHTML=
''+
''+
'隐藏的卡不会出现在绑卡和购买下拉里。订单卡尾号不在本卡库的订阅,升级重试并发固定为 1。'+
'
'+
'
'+
filterSelect('显示', 'filters.cardHidden=this.value; pageNo.cards=1; render(false)', '')+
'当前 '+all.length+' / '+(cache.cards||[]).length+''+
'
'+
'| ID | 品牌 | 卡号 | 有效期 | 发卡行 | 状态 | 备注 | 入库 | |
'+
(rows||'| 还没有卡。 |
')+
'
'+pager('cards', info);
if(dock && page!=='cards') dock.innerHTML='';
}
function modalBusy(on, text){
const box=document.querySelector('#modalStack .modal')||document.querySelector('#modalRoot .modal');
if(!box) return;
box.classList.toggle('busy', !!on);
const ok=box.querySelector('#mOk');
if(ok){
if(on){
if(!ok.dataset.label) ok.dataset.label=ok.textContent;
ok.disabled=true;
ok.classList.add('busy');
ok.innerHTML=''+esc(text||'处理中');
}else{
ok.disabled=false;
ok.classList.remove('busy');
if(ok.dataset.label) ok.textContent=ok.dataset.label;
}
}
}
async function addCardDlg(){
const root=$('#modalRoot');
root.innerHTML='';
const triple=$('#cardTriple');
const fill=()=>{
const got=parseCardTriple(triple.value);
if(!got) return;
$('#cardPan').value=got.pan;
$('#cardExp').value=got.exp;
$('#cardCvc').value=got.cvc;
};
if(triple){
triple.addEventListener('input', fill);
triple.addEventListener('paste', ()=>setTimeout(fill,0));
}
const preview=async()=>{
const pan=($('#cardPan').value||'').replace(/\s/g,'');
const exp=$('#cardExp').value.trim();
const cvc=$('#cardCvc').value.trim();
const box=$('#cardPreview');
if(pan.length<12){ if(box) box.textContent=''; return; }
const j=await api('/api/cards/preview',{method:'POST',body:JSON.stringify({pan, exp, cvc})});
if(!box) return;
if(j.error){ box.textContent=j.error; return; }
box.textContent=[j.brand||j.scheme, j.type, j.bank, countryLabel(j.country_a2||j.country||''), j.prepaid?'预付':'', '尾号 '+(j.last4||'')].filter(Boolean).join(' · ');
};
['cardPan','cardExp','cardCvc'].forEach(id=>{ const el=$('#'+id); if(el) el.addEventListener('change', preview); });
const ok=await new Promise(resolve=>{
$('#mOk').onclick=()=>resolve(true);
$('#mCancel').onclick=()=>resolve(false);
bindMaskClose(root, ()=>resolve(false));
});
if(!ok){ root.innerHTML=''; return; }
const pan=($('#cardPan').value||'').trim();
const exp=($('#cardExp').value||'').trim();
const cvc=($('#cardCvc').value||'').trim();
const note=($('#cardNote').value||'').trim();
const tripleText=(triple&&triple.value||'').trim();
modalBusy(true, '保存中');
const body=tripleText?{triple:tripleText, note}:{pan, exp, cvc, note};
const j=await api('/api/cards',{method:'POST',body:JSON.stringify(body)});
root.innerHTML='';
if(j.error) return fail('无法保存', j.error);
notice('已保存', (j.brand||'卡')+' '+(j.last4||''));
await loadAll(); render(false);
}
async function setCardNoReplay(id, on){
const j=await api('/api/cards/'+id+'/no-replay',{method:'POST',body:JSON.stringify({no_replay_concurrency:!!on})});
if(j.error) return fail('无法保存', j.error);
const card=(cache.cards||[]).find(c=>c && Number(c.id)===Number(id));
if(card) card.no_replay_concurrency=!!on;
notice(on?'已禁止并发':'已允许并发', '尾号 '+((card&&card.last4)||('#'+id)));
}
async function hideCard(id, hidden){
const j=await api('/api/cards/'+id+'/hidden',{method:'POST',body:JSON.stringify({hidden:!!hidden})});
if(j.error) return fail('无法更新', j.error);
notice(hidden?'已隐藏':'已显示', '#'+id);
await loadAll(); render(false);
}
function skuOptions(pkg, selectedId){
const list=(cache.skus||[]).filter(s=>(!pkg || s.package===pkg) && String(s.note||'').indexOf('作废')<0);
if(!list.length) return '';
return list.map(s=>'').join('');
}
function skuLabel(s){
if(!s) return '';
return (s.title||s.sku)+' · '+s.sku+(s.product_type?(' · '+s.product_type):'');
}
function parseJobOffers(j){
const r=jobResult(j);
if(Array.isArray(r)) return r;
if(r && Array.isArray(r.offers)) return r.offers;
if(r && (r.offer_token||r.price||r.sku)) return [r];
return [];
}
function accountCountry(acc){
const cc=String((acc&&(acc.play_country||acc.country))||'').trim().toUpperCase();
return /^[A-Z]{2}$/.test(cc)?cc:'';
}
const replacementModes=[
{id:1, name:'按剩余时间折算'},
{id:2, name:'立即补差价'},
{id:3, name:'下次续费改价'},
{id:4, name:'立即全额收费'},
{id:5, name:'到期后切换'},
{id:6, name:'保留现有方案'}
];
function purchaseTokenOf(p){
if(!p) return '';
return p.purchase_token||'';
}
function accountSubs(aid){
return (cache.subs||[]).filter(s=>s && Number(s.account_id)===Number(aid));
}
function replacementModeHtml(selected){
selected=Number(selected||2);
return ''+replacementModes.map(m=>'').join('')+'
';
}
async function skuForm(opts){
opts=opts||{};
const upgrade=!!opts.upgrade;
const aid=Number(opts.accountId||0);
if(!(cache.skus||[]).length || (upgrade && !(cache.subs||[]).some(s=>s && Number(s.account_id)===aid))){
try{ await loadAll(['skus','subs','accounts']); }catch(e){}
}
const acc=(cache.accounts||[]).find(a=>a && Number(a.id)===aid)||{};
const pkgs=sortApps([...new Set((cache.skus||[]).map(s=>s.package).filter(Boolean))]);
const presetPkg=opts.package||'';
const presetSku=(cache.skus||[]).find(s=>s.package===presetPkg && s.sku===opts.sku);
const subs=accountSubs(aid).filter(subCurrent);
const oldOpts=subs.map(s=>'').join('');
const stacked=!!$('#modalRoot .modal-mask');
const root=stacked?$('#modalStack'):$('#modalRoot');
root.innerHTML=''+(upgrade?'升级订阅':'购买')+' · '+esc(acc.email||('#'+aid))+'
'+
'
'+
'
'+
(upgrade?('
'+replacementModeHtml(opts.replacementMode||2)+'
'):'')+
'
'+
'
'+
'
国家 '+esc(accountCountry(acc)||'-')+'
'+
'
'+
'
';
let picked=null;
const pkgEl=$('#buyPkg'), skuEl=$('#buySku');
const paintObid=()=>{
const box=$('#buyObid'); if(!box) return;
const spec=obidSpec(pkgEl&&pkgEl.value);
if(!spec){ box.innerHTML=''; return; }
const remote=spec.mode==='grok'||spec.mode==='claude';
box.innerHTML=''+(spec.profile?'':'')+(remote?'填写后会立即解析
':'');
const input=$('#buyObidInput');
if(input && remote){
let timer=0, seq=0;
const run=async()=>{
const raw=input.value.trim();
const out=$('#buyObidResult');
const mine=++seq;
if(!raw){ if(out) out.textContent='填写后会立即解析'; return; }
if(out) out.textContent='正在解析…';
try{
window._obidAccount=aid; const got=await obidValue(spec.mode, raw);
if(mine!==seq) return;
if(out){
const row=(k,v)=>''+esc(k)+' '+esc(v||'-')+'
';
let html='';
if(got.account) html+=row('obfuscated_id', got.account);
if(got.profile) html+=row('profile', got.profile);
(got.subscriptions||[]).forEach(s=>{
html+=''+String(s).split(/ +/).map(part=>{
const i=part.indexOf('=');
if(i<0) return esc(part);
return ''+esc(part.slice(0,i))+' '+esc(part.slice(i+1));
}).join(' ')+'
';
});
out.innerHTML=html||esc('没有解析到');
}
}catch(e){
if(mine===seq && out) out.textContent=e.message||String(e);
}
};
input.addEventListener('input', ()=>{ clearTimeout(timer); timer=setTimeout(run, 400); });
input.addEventListener('paste', ()=>setTimeout(run, 0));
}
};
const refill=()=>{
const pkg=pkgEl?pkgEl.value:'';
if(skuEl) skuEl.innerHTML=skuOptions(pkg, skuEl.value);
paintObid();
};
if(pkgEl && !upgrade) pkgEl.onchange=()=>{ refill(); picked=null; showLocal(); };
const drawOffers=(list)=>{
const box=$('#buyOffers');
if(!box) return;
if(!list.length){ box.innerHTML='没有报价
'; return; }
const rows=list.map((o,i)=>{
const kind=offerKindName(o.offer_kind||o.offer_type);
const price=offerPrice(o);
const dur=offerDuration(o)||'-';
return ' | '+esc(kind)+' | '+esc(price)+' | '+esc(dur)+' |
';
}).join('');
box.innerHTML='';
const choose=i=>{ picked=list[i]||null; box.querySelectorAll('input[name=offerPick]').forEach((el,n)=>{ el.checked=n===i; }); };
choose(0);
box.querySelectorAll('tr.pick').forEach(tr=>{
tr.onclick=()=>choose(Number(tr.getAttribute('data-i')));
});
};
const localOffers=sku=>{
const cc=accountCountry(acc);
return ((sku&&sku.offers)||[]).filter(o=>{ const got=String(o.country||'').toUpperCase(); return !cc || !got || got===cc || got==='XX'; });
};
const showLocal=()=>{
const sku=(cache.skus||[]).find(s=>Number(s.id)===Number(skuEl&&skuEl.value));
drawOffers(localOffers(sku));
};
if(skuEl) skuEl.onchange=()=>{ picked=null; showLocal(); };
paintObid();
showLocal();
$('#buyQuery').onclick=async()=>{
const sku=(cache.skus||[]).find(s=>Number(s.id)===Number(skuEl&&skuEl.value));
const pkg=(pkgEl&&pkgEl.value)||(sku&&sku.package)||'';
const all=(cache.skus||[]).filter(s=>s && s.package===pkg);
if(!all.length) return fail('无法查询','这个应用没有 SKU');
modalBusy(true,'刷新报价');
const byType={};
all.forEach(s=>{ const t=s.product_type||'subs'; (byType[t]=byType[t]||[]).push(s.sku); });
let firstErr='';
for(const t of Object.keys(byType)){
const j=await api('/api/sku/details',{method:'POST',body:JSON.stringify({account_id:aid, package:pkg, product_type:t, skus:byType[t], refresh:true})});
if(j.error){ firstErr=j.error; continue; }
const done=await waitJob(j.job_id, '查 SKU');
const offers=parseJobOffers(done);
const cc=accountCountry(acc)||'XX';
all.forEach(s=>{
if((s.product_type||'subs')!==t) return;
const mine=offers.filter(o=>o.sku===s.sku || o.product_id===s.sku).map(o=>Object.assign({}, o, {country:o.country||cc}));
if(mine.length) s.offers=mine;
});
}
modalBusy(false);
if(firstErr && !all.some(s=>(s.offers||[]).length)) return fail('无法查询', firstErr);
showLocal();
};
const formBody=()=>{
const sku=(cache.skus||[]).find(s=>Number(s.id)===Number(skuEl&&skuEl.value));
if(!sku){ fail('无法购买','请选择 SKU'); return null; }
const oldEl=$('#buyOld');
const oldOpt=oldEl&&oldEl.selectedOptions?oldEl.selectedOptions[0]:null;
const modeEl=root.querySelector('input[name=replMode]:checked');
return {
account_id:aid,
package:sku.package,
sku:sku.sku,
product_type:sku.product_type||'subs',
offer_token:(picked&&(picked.offer_token||picked.token))||sku.offer_token||'',
upgrade:upgrade,
old_purchase_token:upgrade?(opts.oldToken||(oldEl&&oldEl.value)||''):'',
old_package:upgrade?((oldOpt&&oldOpt.getAttribute('data-pkg'))||opts.oldPackage||sku.package):'',
old_sku:upgrade?((oldOpt&&oldOpt.getAttribute('data-sku'))||opts.oldSku||''):'',
old_order_id:upgrade?((oldOpt&&oldOpt.getAttribute('data-order'))||opts.oldOrder||''):'',
replacement_mode:upgrade?Number((modeEl&&modeEl.value)||opts.replacementMode||2):0,
obid_raw:(($('#buyObidInput')||{}).value||'').trim(),
obid_profile:(($('#buyObidProfile')||{}).value||'').trim(),
obid_mode:(obidSpec(sku.package)||{}).mode||'',
offer:picked
};
};
let cancelled=false;
let out=null;
const done=await new Promise(resolve=>{
$('#mOk').onclick=async()=>{
if(cancelled) return;
const draft=formBody();
if(!draft) return;
try{
window._obidAccount=draft.account_id||aid; const got=await obidValue(draft.obid_mode, draft.obid_raw);
draft.obfuscated_account_id=got.account||'';
draft.obfuscated_profile_id=got.profile||draft.obid_profile||'';
}catch(e){ fail('无法解析 obid', e.message||String(e)); return; }
modalBusy(true, upgrade?'确认升级':'去支付');
const ok=await showPayConfirm(draft);
modalBusy(false);
if(cancelled) return;
if(ok){ out=Object.assign({}, draft, {immediate:!!draft.immediate}); resolve(true); }
};
$('#mCancel').onclick=()=>{ cancelled=true; resolve(false); };
bindMaskClose(root, ()=>{ cancelled=true; resolve(false); });
});
root.innerHTML='';
return done?out:null;
}
async function showPayConfirm(body){
const preview=await api('/api/purchases/preview',{method:'POST',body:JSON.stringify(body)});
if(preview.error && !preview.due && !preview.price) return fail('无法预览', preview.error);
const price=preview.price||'-';
const startAt=preview.start||'';
const due=preview.due||(startAt?'$0.00':(price||'-'));
const rows=[
['本次应付', due],
['之后价格', price],
['币种', preview.currency||'-'],
['付款开始', startAt||'-'],
['首次扣款', preview.next||'-']
];
if(preview.detail) rows.push(['说明', preview.detail]);
const ok=await modal({
title: body.upgrade?'确认升级':'确认支付',
rows: rows,
message: preview.error||preview.debug||'',
okText: '确认支付',
cancelText: '取消',
stack: true,
extraBefore: '',
onOk: ()=>{ body.immediate=!!($('#payNow')&&$('#payNow').checked); }
});
return !!ok;
}
async function buyOne(ev, id, preset){
preset=preset||{};
const body=await skuForm(Object.assign({accountId:id, upgrade:!!preset.upgrade}, preset));
if(!body) return;
const payload={
account_id:body.account_id,
package:body.package,
sku:body.sku,
product_type:body.product_type,
offer_token:body.offer_token,
instrument_id:body.instrument_id||undefined,
upgrade:!!body.upgrade,
old_purchase_token:body.old_purchase_token||'',
old_package:body.old_package||'',
old_sku:body.old_sku||'',
old_order_id:body.old_order_id||'',
replacement_mode:body.replacement_mode||0,
immediate:!!body.immediate,
obfuscated_account_id:body.obfuscated_account_id||'',
obfuscated_profile_id:body.obfuscated_profile_id||''
};
const j=await api('/api/purchases',{method:'POST',body:JSON.stringify(payload)});
if(j.error) return fail('无法购买', j.error);
notice(body.upgrade?'正在升级':'正在购买', (body.package||'')+' / '+(body.sku||''));
watchAccountJob(id, 'buy', j.job_id, body.upgrade?'升级':'购买');
refreshList();
}
async function buySelected(ev){
const btn=clickBtn(ev);
const ids=[...selected];
if(!ids.length) return fail('无法购买','请先勾选账号');
const body=await skuForm({accountId:ids[0], upgrade:false});
if(!body) return;
const ok=await modal({title:'批量购买', message:'将对 '+ids.length+' 个账号购买 '+body.package+' / '+body.sku+'。', okText:'确认', cancelText:'取消'});
if(!ok) return;
const j=await api('/api/purchases/batch',{method:'POST',body:JSON.stringify({
account_ids:ids, package:body.package, sku:body.sku, product_type:body.product_type, offer_token:body.offer_token, confirm:true
})});
if(j.error) return fail('无法购买', j.error);
if(j.need_confirm){
const again=await api('/api/purchases/batch',{method:'POST',body:JSON.stringify({
account_ids:ids, package:body.package, sku:body.sku, product_type:body.product_type, offer_token:body.offer_token, confirm:true
})});
if(again.error) return fail('无法购买', again.error);
await waitJobs(again.job_ids||[], '购买', btn);
return;
}
await waitJobs(j.job_ids||[], '购买', btn);
}
function sourcePill(src){
const k=String(src||'');
if(!k) return '-';
return pill(k);
}
function renewPill(on){
if(on) return '自动续订';
return '已关闭续订';
}