#!/usr/bin/env python3 """ Mint a rex_clearance + token via nodriver on this Mac, then verify whether those credentials work: A) from a plain curl on this Mac (same IP, no browser) B) with an iOS Safari UA instead of Chrome UA C) from a DIFFERENT IP (Anthropic infra via fly.io ipv6 / etc.) Outputs the captured cookie + token so we can hardcode and replay. """ import asyncio, json, subprocess, sys import nodriver as uc BASE = "https://route-explorer.com" SAFARI_UA = ( "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) " "AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 " "Mobile/15E148 Safari/604.1" ) async def mint() -> tuple[str, str, str]: """Returns (rex_clearance_value, am_user_session_value, token).""" # Use nodriver's default Chrome stealth profile. Overriding UA at the # process level breaks its detection-evasion shims. We test cross-UA # replay separately after minting. browser = await uc.start(headless=False) tab = await browser.get(BASE + "/") # accept cookies await tab.evaluate(""" for (const b of document.querySelectorAll('button')) { if (/accept|agree|allow/i.test((b.innerText||'').trim())) b.click(); } """) for tick in range(1, 60): await asyncio.sleep(1) status = await tab.evaluate(""" (async () => { try { const r = await fetch('/api/token', { credentials: 'include' }); return r.status; } catch (e) { return -1; } })() """, await_promise=True) if status == 200: print(f" cleared at t+{tick}s") break else: browser.stop() raise RuntimeError("Never cleared.") body = await tab.evaluate(""" (async () => (await (await fetch('/api/token', {credentials:'include'})).text()))() """, await_promise=True) token = json.loads(body)["token"] cookies = await browser.cookies.get_all() rex = next((c for c in cookies if c.name == "rex_clearance"), None) am = next((c for c in cookies if c.name == "am_user_session"), None) if not rex: browser.stop() raise RuntimeError("Cleared but no rex_clearance cookie found.") print(f"\n rex_clearance: {rex.value}") print(f" am_user_session: {am.value if am else ''}") print(f" token: {token}") print(f" cookie expires: {getattr(rex, 'expires', None)}") browser.stop() return rex.value, am.value if am else "", token def curl(cookie_jar: str, ua: str, label: str) -> int: """Replay /api/token via curl with given cookies + UA, return HTTP status.""" cmd = [ "/usr/bin/curl", "-s", "-o", "/tmp/replay_body", "-w", "%{http_code}", f"{BASE}/api/token", "-H", f"User-Agent: {ua}", "-H", "Accept: application/json", "-H", f"Origin: {BASE}", "-H", f"Referer: {BASE}/", "-H", f"Cookie: {cookie_jar}", ] r = subprocess.run(cmd, capture_output=True, text=True, timeout=15) code = int(r.stdout.strip() or 0) body = open("/tmp/replay_body").read()[:200] print(f" {label}: HTTP {code} body: {body}") return code def main(): print("Minting credentials via nodriver…") rex_val, am_val, token = uc.loop().run_until_complete(mint()) cookie_jar = f"rex_clearance={rex_val}; am_user_session={am_val}" print("\n=== A: same Mac IP, iOS Safari UA, captured cookies ===") curl(cookie_jar, SAFARI_UA, " same-IP/iOS-UA") print("\n=== B: same Mac IP, Chrome UA (UA mismatch test) ===") chrome_ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120 Safari/537.36" curl(cookie_jar, chrome_ua, " same-IP/Chrome-UA") print("\n=== C: flight-search with captured token ===") cmd = [ "/usr/bin/curl", "-s", "-o", "/tmp/fs_body", "-w", "%{http_code}", "-X", "POST", f"{BASE}/api/flight-search", "-H", f"User-Agent: {SAFARI_UA}", "-H", "Content-Type: application/json", "-H", f"Origin: {BASE}", "-H", f"Referer: {BASE}/", "-H", f"Cookie: {cookie_jar}", "-H", f"X-API-Token: {token}", "-d", json.dumps({ "endpoint": "/route", "body": {"json": { "departureAirportIata": "DAL", "arrivalAirportIata": "HOU", "departureDates": ["2026-05-31"], "maxStops": 0, "limit": 20, "includeAppendix": True, }}, }), ] r = subprocess.run(cmd, capture_output=True, text=True, timeout=15) fs_code = int(r.stdout.strip() or 0) body = open("/tmp/fs_body").read() print(f" /api/flight-search: HTTP {fs_code}") if fs_code == 200: data = json.loads(body) conns = data.get("json", {}).get("connections", []) print(f" → {len(conns)} connections") for c in conns[:5]: for f in c.get("flights", []): print(f" {f['carrierIata']}{f['flightNumber']} " f"{f['departure']['airportIata']}@{f['departure']['dateTime'][11:16]}" f" → {f['arrival']['airportIata']}@{f['arrival']['dateTime'][11:16]} " f"({f.get('equipmentIata','?')})") else: print(f" body: {body[:300]}") print(f"\n=== CAPTURED FOR HARDCODING ===") print(f"REX_CLEARANCE = {rex_val!r}") print(f"AM_USER_SESSION = {am_val!r}") print(f"TOKEN = {token!r}") if __name__ == "__main__": main()