capture_bypwd.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. """Capture the byPwd response body to see if we got a real JWT.
  2. Recent debug run showed POST .../byPwd was sent and returned 200, but
  3. we never read the body. If 200 = JWT, save it; if 200 = captcha required,
  4. note the error code.
  5. """
  6. import asyncio
  7. import base64
  8. import json
  9. import sys
  10. from pathlib import Path
  11. _HERE = Path(__file__).resolve().parent
  12. sys.path.insert(0, str(_HERE.parent / "src"))
  13. from cq2_sdk.env_loader import load_env
  14. load_env(_HERE.parent / ".env")
  15. from cq2_sdk.login.box_996 import Box996Login
  16. from cq2_sdk.store import UserStore, connection
  17. from cq2_sdk.debug_log import DebugLogger
  18. EDGE = r"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe"
  19. URL = "https://pc.hzwlan.com/login/account"
  20. async def main():
  21. log = DebugLogger(extra={"task": "capture_bypwd_response"})
  22. from playwright.async_api import async_playwright
  23. async with async_playwright() as p:
  24. browser = await p.chromium.launch(executable_path=EDGE, headless=True)
  25. ctx = await browser.new_context(viewport={"width": 1366, "height": 768})
  26. page = await ctx.new_page()
  27. # Capture byPwd response (Playwright sync API's r.text() is a coroutine
  28. # and must be awaited; the event handler is sync, so we collect
  29. # the coroutine and run it after the page closes).
  30. bypwd_response = {}
  31. pending_text: list = []
  32. def on_response(r):
  33. if "/auth/v3/login/safe/byPwd" in r.url:
  34. bypwd_response["status"] = r.status
  35. bypwd_response["url"] = r.url
  36. pending_text.append(r.text())
  37. page.on("response", on_response)
  38. await page.goto(URL, wait_until="networkidle", timeout=30000)
  39. await page.evaluate(
  40. "([u, p]) => {"
  41. " const setVal = (sel, v) => {"
  42. " const el = document.querySelector(sel);"
  43. " Object.getOwnPropertyDescriptor("
  44. " window.HTMLInputElement.prototype, 'value').set.call(el, v);"
  45. " el.dispatchEvent(new Event('input', {bubbles: true}));"
  46. " };"
  47. " setVal('input#username', u);"
  48. " setVal('input#password', p);"
  49. " const btn = document.querySelector("
  50. " 'button.login-form_box__submit_button');"
  51. " if (btn) { btn.disabled = false; btn.classList.remove('disabled'); }"
  52. "}",
  53. ["longwu988", "Longwu1988"],
  54. )
  55. await page.wait_for_timeout(300)
  56. await page.locator("button.login-form_box__submit_button").first.click(force=True)
  57. await page.wait_for_timeout(8000)
  58. await browser.close()
  59. if pending_text:
  60. body = pending_text[0]
  61. if asyncio.iscoroutine(body):
  62. body = await body
  63. else:
  64. body = ""
  65. print(f"=== byPwd response ===")
  66. print(f"status: {bypwd_response.get('status')}")
  67. print(f"body ({len(body)} chars): {body[:1000]}")
  68. if not body:
  69. print("no response captured")
  70. return
  71. try:
  72. data = json.loads(body)
  73. print(f"\nparsed JSON keys: {list(data.keys())}")
  74. token = data.get('data', {}).get('token', '')
  75. if token:
  76. print(f"\n*** TOKEN FOUND ({len(token)} chars) ***")
  77. print(f" {token[:40]}...")
  78. # Save to MySQL
  79. with connection() as conn:
  80. u = UserStore(conn).get_by_username("longwu988")
  81. if u:
  82. UserStore(conn).update_token(user_id=u.id, token=token)
  83. print(f"saved to MySQL users.id={u.id}")
  84. else:
  85. print("user longwu988 not in MySQL, run scaffold first")
  86. else:
  87. print(f"response code: {data.get('code')}, msg: {data.get('msg')}")
  88. except Exception as e:
  89. print(f"JSON parse error: {e}")
  90. asyncio.run(main())