cdp_full_chain.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. """Extract the _captcha_ token from 996box localStorage via CDP, then use our
  2. REAL SDK (Box996Login) to complete the full chain:
  3. login_with_password(captcha=reused_token)
  4. -> getTodayOpen
  5. -> EnterGameClient(serverid)
  6. -> 996box spawns cq.exe -> cq2.exe -> real TCP login traffic
  7. -> (capture running in background records everything)
  8. """
  9. import asyncio
  10. import base64
  11. import json
  12. import sys
  13. from pathlib import Path
  14. import httpx
  15. import websockets
  16. sys.path.insert(0, "src")
  17. from cq2_sdk.env_loader import load_env
  18. load_env()
  19. async def get_targets():
  20. async with httpx.AsyncClient(timeout=5) as c:
  21. r = await c.get("http://127.0.0.1:9222/json/list")
  22. return r.json()
  23. async def cdp_eval(ws, expr: str, msg_id: int) -> dict:
  24. await ws.send(json.dumps({"id": msg_id, "method": "Runtime.evaluate",
  25. "params": {"expression": expr, "returnByValue": True}}))
  26. while True:
  27. msg = json.loads(await ws.recv())
  28. if msg.get("id") == msg_id:
  29. return msg.get("result", {})
  30. async def get_captcha_from_localstorage() -> dict | None:
  31. targets = await get_targets()
  32. login = next((t for t in targets if "hzwlan" in t.get("url", "") or "996box" in t.get("url", "")), None)
  33. if not login:
  34. print("no hzwlan/996box target")
  35. return None
  36. async with websockets.connect(login["webSocketDebuggerUrl"], max_size=10**7) as ws:
  37. res = await cdp_eval(ws, "localStorage.getItem('_captcha_')", 1)
  38. val = res.get("result", {}).get("value")
  39. if not val:
  40. print("_captcha_ empty")
  41. return None
  42. # decode base64 -> JSON
  43. try:
  44. padded = val + "=" * (-len(val) % 4)
  45. decoded = base64.urlsafe_b64decode(padded).decode("utf-8")
  46. cap = json.loads(decoded)
  47. print(f"captcha fields: {list(cap.keys())}")
  48. print(f" captchaId: {cap.get('captchaId','?')[:20]}...")
  49. print(f" genTime: {cap.get('genTime','?')}")
  50. return cap
  51. except Exception as e:
  52. print(f"decode err: {e}")
  53. return None
  54. async def main() -> int:
  55. cap = await get_captcha_from_localstorage()
  56. if not cap:
  57. return 1
  58. # Use our REAL SDK
  59. from cq2_sdk.login.box_996 import Box996Login
  60. async def run():
  61. box = Box996Login()
  62. try:
  63. print()
  64. print("=== SDK login_with_password (reused captcha token) ===")
  65. try:
  66. session = await box.login_with_password("longwu988", "Longwu1988", captcha=cap)
  67. print(f"*** LOGIN OK: uid={session.uid} token={session.token[:25]}... ***")
  68. except Exception as e:
  69. print(f"login failed: {type(e).__name__}: {e}")
  70. print("(captcha likely single-use/expired — expected fallback)")
  71. print()
  72. print("=== getTodayOpen (uses stored JWT if login above worked) ===")
  73. try:
  74. servers = await box.get_today_open(206923)
  75. print(f"today's servers: {len(servers)}")
  76. for s in servers[:5]:
  77. print(f" {s.server_name} sid={s.serverid} opens={s.section.strip()}")
  78. if servers:
  79. print()
  80. print("=== EnterGameClient on the LATEST server ===")
  81. target = servers[-1]
  82. data = await box.enter_game_client(206923, target.serverid)
  83. print(f"launch OK -> {str(data)[:100]}")
  84. print()
  85. print("*** 996box Electron should now spawn cq.exe -> cq2.exe ***")
  86. print("*** background capture (if running) records the TCP login ***")
  87. return 0
  88. except Exception as e:
  89. print(f"game API failed: {type(e).__name__}: {e}")
  90. finally:
  91. await box.close()
  92. return 1
  93. return await run()
  94. sys.exit(asyncio.run(main()))