91 lines
5.3 KiB
Markdown
91 lines
5.3 KiB
Markdown
# gh-regkit-prime: Camoufox multi-stage GitHub runner — pitfalls & ops
|
|
|
|
Stack: Camoufox (Firefox anti-detect) + mail.cx (mailcx provider) + multi-stage runner
|
|
(reg → email verify → auto-login → repo → 2FA TOTP → PAT → profile). Project:
|
|
`Desktop/_PROJECTS/gh-regkit-prime`, repo `gbonnet65923/gh-regkit-prime`.
|
|
Account line format: `email----password----username----totp_secret----has_recovery----pat`.
|
|
|
|
## Batch operations (CRITICAL)
|
|
|
|
- NEVER run two registration batches concurrently — they share the exit IP, GitHub
|
|
DataDome bans it fast and accounts come out `suspended`. Before launching, enumerate
|
|
and kill leftovers.
|
|
- Filter processes by `main.py` substring ONLY, not by project path — the CommandLine
|
|
of a batch started with a relative path (`cd project && python main.py`) does not
|
|
contain the project directory, so a `path in CommandLine` filter silently misses it
|
|
and duplicate batches keep running.
|
|
- Enumerate/kill on Windows (wmic is unreliable here):
|
|
`powershell Get-CimInstance Win32_Process -Filter "Name='python.exe'" | ConvertTo-Json`,
|
|
parse JSON in Python, `taskkill /F /T /PID`.
|
|
- Run batches with `background=true` + heartbeat; report OK/FAIL from the heartbeat log,
|
|
verify saves by `wc -l accounts/github_accounts_*.txt` (a successful log line without
|
|
a saved row means the crash happened before persistence — see salvage below).
|
|
|
|
## Signup form
|
|
|
|
- mail.cx issues short local-parts (4 chars) → derived usernames collide constantly.
|
|
Pad any local-part shorter than ~10 chars with random alnum BEFORE the first attempt.
|
|
- "Create account stayed disabled after validation wait" is AMBIGUOUS: it can mean
|
|
octocaptcha pending OR username taken (a taken name keeps the button disabled
|
|
forever). Probe the username-error element first and raise a distinct
|
|
"username taken" error → caller retries with a fresh random suffix in-place.
|
|
Treating it as transient and reloading the page WITH THE SAME DATA burns all
|
|
page-reload attempts for nothing.
|
|
|
|
## 2FA (TOTP) stage
|
|
|
|
- The wizard keeps hidden twin otp inputs in the DOM; `locator(...).first` resolves to
|
|
an INVISIBLE one and `fill()` hangs "element is not visible" until timeout → stage
|
|
fails. Iterate candidates checking `is_visible() and is_editable()`; last-resort
|
|
fill via JS `el.value=code` + dispatch `input`/`change` on the `offsetParent!==null`
|
|
element.
|
|
- TOTP secret is frequently absent from innerText (dialog closed / rendered as QR).
|
|
Parse it from `page.content()`: look for `otpauth://totp/...secret=[REDACTED] in BOTH
|
|
percent-encoded (`secret%3D`) and plain form, then fall back to a bare
|
|
`[A-Z2-7]{16,32}` scan.
|
|
- Recovery codes: scrape from the DOM first. SKIP the file download entirely when the
|
|
DOM scrape succeeded — Firefox/Camoufox download handling intermittently hangs the
|
|
whole 2FA wizard (user-visible symptom: hang at the backup-download step).
|
|
- GitHub regenerates the TOTP secret on every load of the setup page — read the secret
|
|
only from the page you actually submit the code on.
|
|
|
|
## PAT stage
|
|
|
|
- The `ghp_...` token often lives in HTML attributes (`<code>`, clipboard-value), not
|
|
in innerText. Search `_page_text(page)` first, then `page.content()`, then wait ~5s
|
|
and retry both — a single innerText search reports "token not found" on success.
|
|
- Any helper called from the PAT function needs its own local import (`import re as _re`
|
|
inside the function) — module-level `re` may not be imported in this codebase shape;
|
|
a NameError here kills the stage after the token was already generated.
|
|
|
|
## Crash salvage (account-saving checkpoint)
|
|
|
|
- The browser/driver can crash ("Connection closed while reading from the driver",
|
|
WebGL out-of-memory) AFTER the account is verified and logged in. If credentials are
|
|
only persisted at the very end, the account is lost. Set a checkpoint dict
|
|
(`pending["active"]=True`, `pending["username"]`, email) at the start of the finalize
|
|
stage, and in the outer exception handler salvage a record line from it when the
|
|
checkpoint is set. Thread the `pending` dict through the post-form flow function.
|
|
|
|
## Proxies / DataDome
|
|
|
|
- Free HTTP pool (~125 live) gives roughly 30-60% yield; failures are DataDome
|
|
challenge pages and dead-proxy connect timeouts. When the home IP itself gets
|
|
DataDome-banned ("email form did not appear (DataDome challenge page); IP is
|
|
blocked"), only IP rotation helps — residential proxies.
|
|
- 1024proxy.com residential: the marketing/pricing site is Cloudflare-blocked from a
|
|
banned/flagged home IP — open it through Camoufox routed via one of the free pool
|
|
proxies to read prices. Wallet balance alone does NOT enable the gateways: the white
|
|
API (`white.1024proxy.com/white/api?region=US&num=N&time=M&format=0&type=json`,
|
|
cookie `zero_sid` auth, navigate not fetch — CORS) returns "Insufficient traffic"
|
|
until a traffic package is purchased; gateways answer raw CONNECT with 407.
|
|
Purchase only via the dashboard UI (Buy button); raw api.1024proxy.com calls from
|
|
Python return "re-login" errors — they need the browser session context.
|
|
|
|
## Config knobs that silently disable stages
|
|
|
|
- `create_repo`, `set_profile_status`, `complete_profile` can be False in config.json
|
|
even when the dataclass defaults are True — a warmed-up account (profile + first
|
|
repo) requires flipping them explicitly in config.json AND restarting the batch (a
|
|
running process holds the old code/config in memory).
|