Files
universal-autoreg/providers/xkiro_tg_verify.py

260 lines
10 KiB
Python

# -*- coding: utf-8 -*-
"""xkiro_farm.py — FULL E2E: GH OAuth -> login -> TG ticket -> bot verify (30M tokens) -> API key -> bank.
One cffi session per account (middleware rotates __xt_rt single-use — cookies MUST stay in-session).
Usage: PYTHONPATH="" Python311 xkiro_farm.py <count> [start]
Bank: C:/Users/User/tmp/xkiro/xkiro_bank.jsonl
"""
import os
import sys, os, json, time, re, asyncio, argparse
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'lib'))
sys.path.insert(0, 'C:/Users/User/tmp/regfarm/github_oauth')
from curl_cffi import requests as cq
import gh_http
XK = 'https://xkiro.com'
API = 'https://api.xkiro.com'
CID = 'Ov23li0EyjNfkXUSKZel'
BANK = r'C:/Users/User/tmp/xkiro/xkiro_bank.jsonl'
GOOD_TG = r'C:/Users/User/tmp/xkiro/xkiro_good_tg.json' # proven REUSABLE sessions (verified 2+ accounts)
POOL = r'C:/Users/User/tmp/gh_accounts.json'
USED = r'C:/Users/User/tmp/xkiro/xkiro_used_tg.json'
AVAIL = r'C:/Users/User/tmp/mia_avail_sessions.json'
DIRS = [r'C:/Users/User/Desktop/CLEAN_ALIVE_SESSIONS', r'C:/Users/User/.orca/sessions']
IMP = 'chrome131'
H = {'Accept': 'application/json', 'Content-Type': 'application/json',
'Referer': XK + '/dashboard', 'Origin': XK}
# TG creds
import glob as _g
TG_ID, TG_HASH = None, None
for p in [r'C:/Users/User/tmp/mia_verify_slow.py', r'C:/Users/User/tmp/freemodel/freemodel_full.py']:
try:
t = open(p, encoding='utf-8').read()
m1 = re.search(r'API_ID\s*=\s*(\d+)', t)
m2 = re.search(r'API_HASH\s*=\s*[\'"]([a-f0-9]+)[\'"]', t)
if m1 and m2:
TG_ID, TG_HASH = int(m1.group(1)), m2.group(1)
break
except Exception:
pass
def log(*a):
print(*a, flush=True)
def good_sessions():
"""Proven reusable TG sessions (rotate, no consumption)."""
out = []
try:
for p in json.load(open(GOOD_TG)):
if os.path.exists(p):
out.append(p)
except Exception:
pass
return out
def mark_good(path):
try:
g = json.load(open(GOOD_TG))
except Exception:
g = []
if path not in g:
g.append(path)
json.dump(g, open(GOOD_TG, 'w'))
def tg_sessions(n=4):
names = json.load(open(AVAIL))
try:
used = set(json.load(open(USED)))
except Exception:
used = set()
# exclude sessions already consumed by miarouter verifier (avoid AuthKeyDuplicated)
try:
mstate = json.load(open(r'C:/Users/User/Desktop/farm/miarouter/verifier_state.json'))
used |= set(mstate.get('used_tg', []))
except Exception:
pass
tail = [b for b in names if b not in used]
tail = tail[-n:] # TAIL: miarouter verifier walks head-first
out = []
for b in tail:
for d in DIRS:
p = os.path.join(d, b)
if os.path.exists(p):
out.append(p)
break
return out
def mark_tg_used(basename):
try:
used = set(json.load(open(USED)))
except Exception:
used = set()
used.add(basename)
json.dump(sorted(used), open(USED, 'w'))
async def bot_start(sess_path, ticket):
from telethon import TelegramClient
name = os.path.basename(sess_path)
client = TelegramClient(sess_path.replace('.session', ''), TG_ID, TG_HASH)
try:
await asyncio.wait_for(client.connect(), 45)
if not await client.is_user_authorized():
return name, 'NOT_AUTH'
await client.send_message('xkiro_official_bot', '/start ' + ticket)
await asyncio.sleep(9)
msgs = await client.get_messages('xkiro_official_bot', limit=4)
txt = ' '.join((m.message or '')[:200] for m in msgs if not m.out).lower()
if 'verified successfully' in txt or "you've received" in txt:
return name, 'OK'
if 'join' in txt or 'channel' in txt:
from telethon.tl.functions.channels import JoinChannelRequest
try:
await client(JoinChannelRequest('xtrouter'))
await asyncio.sleep(3)
await client.send_message('xkiro_official_bot', '/start ' + ticket)
await asyncio.sleep(8)
msgs = await client.get_messages('xkiro_official_bot', limit=4)
txt = ' '.join((m.message or '')[:200] for m in msgs if not m.out).lower()
if 'verified' in txt:
return name, 'OK'
return name, 'REPLY:' + txt[:120]
except Exception as e:
return name, 'JOIN_FAIL:' + type(e).__name__
return name, 'REPLY:' + txt[:120]
finally:
try:
await client.disconnect()
except Exception:
pass
def farm_one(acc, tgsess):
lg = acc['login']
rec = {'gh_login': lg, 'ts': time.strftime('%H:%M:%S')}
s = cq.Session(impersonate=IMP)
# 1 state
try:
r = s.get(API + '/api/v1/auth/github', headers={**H, 'Accept': 'text/html', 'Sec-Fetch-Site': 'none'},
allow_redirects=False, timeout=30)
loc = r.headers.get('Location', '') or ''
m = re.search(r'state=([a-f0-9]{16,})', loc)
if not m:
m = re.search(r'state=([a-f0-9]{16,})', r.text or '')
if not m:
rec['stage'] = 'state'; rec['err'] = f'http={r.status_code}'
return rec
state = m.group(1)
except Exception as e:
rec['stage'] = 'state'; rec['err'] = str(e)[:100]; return rec
# 2 gh code
gh = gh_http.GHSession(bind=False)
ok, err = gh.login(lg, acc['password'], acc.get('totp'))
if not ok:
rec['stage'] = 'gh_login'; rec['err'] = err; return rec
code, cerr = gh.oauth_code(CID, state, scope='read:user user:email')
if not code:
rec['stage'] = 'gh_code'; rec['err'] = cerr; return rec
# 3 callback (same session!)
try:
r3 = s.get(API + f'/api/v1/auth/github/callback?code={code}&state={state}',
headers={**H, 'Accept': 'text/html', 'Sec-Fetch-Site': 'cross-site',
'Referer': 'https://github.com/'}, timeout=40)
cks = dict(s.cookies)
if not cks.get('__xt_at'):
rec['stage'] = 'callback'; rec['err'] = f'http={r3.status_code} no __xt_at'
return rec
rec['cookies'] = cks
except Exception as e:
rec['stage'] = 'callback'; rec['err'] = str(e)[:100]; return rec
# 4 ticket via xkiro.com proxy (cookies same names, set on xkiro.com)
s2 = cq.Session(impersonate=IMP)
for k, v in cks.items():
s2.cookies.set(k, v, domain='xkiro.com')
s2.cookies.set(k, v, domain='.xkiro.com')
if not tgsess:
rec['tg'] = 'NO_TG_SESSION'
else:
try:
rt = s2.post(XK + '/api/v1/me/telegram/ticket', headers=H, data='{}', timeout=25)
j = rt.json()
data = j.get('data') or {}
if data.get('alreadyVerified'):
rec['tg'] = 'already'
else:
dl = data.get('deepLink', '')
ticket = dl.split('start=')[-1] if 'start=' in dl else ''
if not ticket:
rec['stage'] = 'ticket'; rec['err'] = rt.text[:120]; return rec
# 5 bot verify
try:
sp, res = asyncio.run(bot_start(tgsess, ticket))
except Exception as be:
res = f'EXC:{type(be).__name__}:{str(be)[:60]}'
rec['tg'] = res; rec['tg_sess'] = os.path.basename(tgsess)
if res == 'OK':
mark_tg_used(os.path.basename(tgsess)) # consumed: 1 TG acct = 1 xkiro verification
else:
mark_tg_used(os.path.basename(tgsess)) # any failure: never reuse (dup/NOT_AUTH/burned)
except Exception as e:
rec['stage'] = 'ticket'; rec['err'] = str(e)[:100]
# refresh cookies after middleware rotation
fresh = dict(s2.cookies)
if fresh.get('__xt_at'):
rec['cookies'] = {**cks, **fresh}
# 6 key + wallet + status
try:
rk = s2.post(XK + '/api/v1/keys', headers=H, data=json.dumps({'name': 'farm'}), timeout=25)
jk = rk.json()
rec['key'] = (jk.get('data') or {}).get('plaintext')
rec['key_id'] = ((jk.get('data') or {}).get('key') or {}).get('id')
except Exception as e:
rec['key_err'] = str(e)[:80]
try:
rec['wallet'] = s2.get(XK + '/api/v1/wallet', headers=H, timeout=20).json().get('data')
rec['tg_status'] = s2.get(XK + '/api/v1/me/telegram/status', headers=H, timeout=20).json().get('data')
except Exception:
pass
rec['stage'] = 'done'
return rec
def main():
ap = argparse.ArgumentParser()
ap.add_argument('count', type=int, nargs='?', default=1)
ap.add_argument('start', type=int, nargs='?', default=0)
args = ap.parse_args()
pool = json.load(open(POOL))
done = set()
try:
for line in open(BANK, encoding='utf-8'):
r = json.loads(line)
if r.get('stage') == 'done' or r.get('key'):
done.add(r['gh_login'])
except Exception:
pass
cand = [a for a in pool if a['login'] not in done]
log(f'=== xkiro farm: {args.count}, candidates {len(cand)}, TG_ID set: {TG_ID is not None}')
tgs = tg_sessions(args.count + 2)
log('tg sessions:', len(tgs))
n = 0
for i, a in enumerate(cand[args.start:]):
if n >= args.count:
break
goods = good_sessions()
if goods:
tg = goods[n % len(goods)] # REUSE: proven sessions verify unlimited accounts
else:
tgs = tg_sessions(1) # fresh per account: excludes xkiro-used + miarouter used_tg
tg = tgs[0] if tgs else None
log(f'--- {a["login"]} (tg: {os.path.basename(tg) if tg else "NONE"})')
try:
rec = farm_one(a, tg)
except Exception as e:
rec = {'gh_login': a['login'], 'stage': 'exc', 'err': f'{type(e).__name__}:{e}'[:120]}
with open(BANK, 'a', encoding='utf-8') as f:
f.write(json.dumps(rec, ensure_ascii=False) + '\n')
log(' ', {k: (str(v)[:60] if k not in ('cookies',) else '<saved>') for k, v in rec.items() if k != 'gh_login'})
n += 1
time.sleep(25)
if __name__ == '__main__':
main()