Files
autoreg-skills-max/skills/browser-signup-automation/references/turnstile-api-first-registration.md

99 lines
4.3 KiB
Markdown

# API-First Registration + Turnstile Bypass — Lovable.dev Example
## Context
Session: 2026-08-04. Goal: register accounts on lovable.dev. The signup is blocked by Cloudflare Turnstile (CDP detection). The site uses SolidStart (SolidJS) with Firebase Auth backend.
## Signup Flow
1. `GET https://lovable.dev/signup` — initial page with email-only field
2. Enter email → hits `POST https://api.lovable.dev/auth/check-auth-provider` `{email}`
- Returns provider list, userExists flag, domainLock, recoveryState
3. Password form appears → Turnstile widget rendered with sitekey `0x4AAAAAAChnKAZBY0iFpFHC`
4. Form submit:
- Calls `POST https://api.lovable.dev/auth/turnstile-signup` `{email, token}` → 204
- Then Firebase `createUserWithEmailAndPassword(email, password)`
5. After account creation → redirect to `/verify-email` or login
## SolidStart Server Function Pattern
The form uses SolidStart RPC: `/_serverFn/<sha256hash>`. These hash-based endpoints proxy to `api.lovable.dev`.
- `/_serverFn/[REDACTED-KEY]` — email check (GET)
- Refresh between page loads — hashes change per deploy
## 2captcha Configuration
```python
import requests, time
def solve_turnstile(sitekey, pageurl, action="signup_email_password", api_key="[REDACTED-KEY]", timeout=60):
r = requests.get("https://2captcha.com/in.php", params={
"key": api_key, "method": "turnstile",
"sitekey": sitekey, "pageurl": pageurl,
"action": action, "json": 1
}, timeout=10)
if r.json().get("status") != 1:
return None
cid = r.json()["request"]
for _ in range(timeout // 3):
time.sleep(3)
r2 = requests.get("https://2captcha.com/res.php", params={
"key": api_key, "action": "get", "id": cid, "json": 1
}, timeout=10)
if r2.json().get("status") == 1:
return r2.json()["request"]
return None
```
**Key params**: `method=turnstile`, `action=signup_email_password` (must match the widget's action). Token is ~837 chars.
## Turnstile CDP Detection
- Chrome DevTools Protocol is detected by Turnstile's implicit challenge mode
- Clicking the checkbox via CDP tools (`mcp__chrome_devtools__click`) produces: URL changes from `/new/normal` to `/failure_retry/normal`, iframe shows "Сбой проверки" (Verification failure)
- Multiple retries with 2captcha tokens still fail because the form framework (`turnstile.getResponse()`) returns empty even when the hidden input is set
- The Turnstile iframe also resets itself between clicks, each time showing `/new/normal`
## Key API Endpoint
`POST https://api.lovable.dev/auth/turnstile-signup`
Headers required:
- `Content-Type: application/json`
- `Origin: https://lovable.dev`
- `User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36`
Body: `{"email": "user@example.com", "token": "<2captcha-solved-token>"}`
Returns: `204 No Content` on success.
Rate limit: 2000/hour (x-ratelimit-remaining starts at 2000).
## Temp-Mail Domain Blocklist
Lovable maintains a large blocked-domain Set (`po`) with ~300 entries in the JS bundle. Common blocked patterns:
- `yopmail.com`, `guerrillamail.com`, `mail.tm`, `tempmail` domains
- Any `.sbs`, `.rest` TLDs
- Domains with `+` in the local part (plus-addressing) unless on whitelist (`lovable.dev` only)
- Full list visible in the `LoginSignupForm*` JS bundle under `po = new Set([...])`
## JS Bundle Discovery Pattern
1. Load page → extract modulepreloads from `<link rel="modulepreload">`
2. Read importmap `<script type="importmap">` — maps old hash names to current ones
3. Target files: `signup-*.js`, `LoginSignupForm-*.js`, `_auth-*.js`
4. Search for turnstile-sitekey, serverFn calls, API endpoints
5. The importmap format: `{"/assets/old-name.js": "/assets/new-name.js"}`
## Firebase Auth Integration
After turnstile validation, the client-side bundle calls Firebase Auth REST API via `identitytoolkit.googleapis.com/v1/accounts:signUp?key=<API_KEY>`. The API key is embedded in the webpack/rolldown bundle (not on `window.firebase`).
## What Didn't Work
- Setting `cf-turnstile-response` input value directly — form still shows disabled button
- Clicking Turnstile checkbox via CDP — detected and rejected
- Puppeteer-extra-stealth via browser_navigate tool — Chrome crashes with sandbox error
- Standard HTTP client (`requests`) — blocked by Cloudflare