Files
Cyrene/debug/cache/test_cdp_token_investigation.py
T
AskaEth b15e1c9541 fix: 第二轮深度调试修复 - useSpeechSynthesis守卫+NPE防护+E2E测试完善
- P0: useSpeechSynthesis.ts cancel()增加isSupported守卫
- P0: iot_provider.go 添加loader nil检查防止NPE panic
- 新增CDP E2E v4测试脚本 14项全绿通过
- 生成第二轮修复报告 docs/debug/2026-05-21-round2-fixes.md
2026-05-22 00:10:37 +08:00

154 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""调查 test-token-cyrene 的来源——检查 localStorage 和前端代码行为"""
import json, time, urllib.request
from websocket import create_connection
# 先获取真实 JWT
print("=== Step 0: 获取真实 JWT ===")
login_req = urllib.request.Request(
'http://localhost:8080/api/v1/auth/login',
data=json.dumps({"username": "yeij0942", "password": "Jiang1143218570"}).encode(),
headers={"Content-Type": "application/json"},
method='POST'
)
try:
login_resp = urllib.request.urlopen(login_req, timeout=10)
login_data = json.loads(login_resp.read())
real_token = login_data.get('data', {}).get('access_token', '')
print(f" Real token (first 20 chars): {real_token[:20]}...")
print(f" Login success: {bool(real_token)}")
except Exception as e:
print(f" Login failed: {e}")
real_token = ""
# 连接到 Chromium
print("\n=== Step 1: 创建新页面(about:blank,无旧 localStorage===")
req = urllib.request.Request('http://127.0.0.1:9225/json/new?url=about:blank', method='PUT')
resp = urllib.request.urlopen(req, timeout=10)
page = json.loads(resp.read())
ws_url = page['webSocketDebuggerUrl']
print(f" Page ID: {page.get('id')}")
print(f" URL: {page.get('url')}")
ws = create_connection(ws_url, timeout=10)
def cdp(method, params=None, msg_id=1):
ws.send(json.dumps({"id": msg_id, "method": method, "params": params or {}}))
def recv_all(timeout=3):
ws.settimeout(timeout)
msgs = []
try:
while True:
msgs.append(ws.recv())
except:
pass
return msgs
# 启用 domains
cdp("Page.enable", {}, 1)
cdp("Network.enable", {}, 2)
cdp("Runtime.enable", {}, 3)
time.sleep(0.5)
recv_all(0.5)
# === 检查 about:blank 的 localStorage ===
print("\n=== Step 2: 检查 about:blank localStorage(应为空)===")
cdp("Runtime.evaluate", {
"expression": "JSON.stringify({token: localStorage.getItem('token'), allKeys: Object.keys(localStorage)})"
}, 10)
time.sleep(0.5)
msgs = recv_all(1)
for m in msgs:
d = json.loads(m)
if d.get('id') == 10:
val = d.get('result', {}).get('result', {}).get('value', '')
print(f" about:blank localStorage: {val}")
# 如果有 token 就清除
cdp("Runtime.evaluate", {"expression": "localStorage.clear(); 'cleared'"}, 11)
time.sleep(0.5)
recv_all(0.5)
# === 导航到 5199 ===
print("\n=== Step 3: 导航到 localhost:5199 ===")
cdp("Page.navigate", {"url": "http://localhost:5199/"}, 20)
time.sleep(5)
all_msgs = recv_all(3)
# 分析网络请求
print("\n=== Step 4: 网络请求分析 ===")
for m in all_msgs:
d = json.loads(m)
method = d.get('method', '')
params = d.get('params', {})
if method == 'Network.requestWillBeSent':
req = params.get('request', {})
headers = req.get('headers', {})
auth = headers.get('Authorization', '') or headers.get('authorization', '')
url_short = req.get('url', '')[:100]
if auth:
print(f" AUTH: {req.get('method','?')} {url_short}")
print(f" Authorization: {auth[:80]}")
elif '/api/' in url_short:
print(f" NO_AUTH: {req.get('method','?')} {url_short}")
elif method == 'Runtime.consoleAPICalled':
args = params.get('args', [])
texts = [str(a.get('value', '') or a.get('description', ''))[:150] for a in args]
msg_type = params.get('type', 'log')
print(f" [CONSOLE:{msg_type}] {' '.join(texts)}")
elif method == 'Runtime.exceptionThrown':
exc = params.get('exceptionDetails', {})
print(f" [EXCEPTION] {exc.get('text', '')} at line {exc.get('lineNumber', '')}")
# === 检查 localStorage ===
print("\n=== Step 5: 检查导航后 localStorage ===")
cdp("Runtime.evaluate", {
"expression": "JSON.stringify({token: localStorage.getItem('token'), refresh_token: localStorage.getItem('refresh_token'), user_id: localStorage.getItem('user_id'), allKeys: Object.keys(localStorage)})"
}, 30)
time.sleep(0.5)
msgs = recv_all(2)
for m in msgs:
d = json.loads(m)
if d.get('id') == 30:
val = d.get('result', {}).get('result', {}).get('value', '')
print(f" localStorage: {val}")
# === 如果 token 是 test-token-cyrene,手动覆盖为真实 token 并测试 ===
print("\n=== Step 6: 注入真实 token ===")
if real_token:
cdp("Runtime.evaluate", {
"expression": f"localStorage.setItem('token', '{real_token}'); 'done'"
}, 40)
time.sleep(0.5)
recv_all(1)
# 重新加载
cdp("Page.reload", {}, 41)
time.sleep(4)
msgs = recv_all(3)
# 查看请求
print(" 重新加载后的网络请求:")
for m in msgs:
d = json.loads(m)
method = d.get('method', '')
params = d.get('params', {})
if method == 'Network.requestWillBeSent':
req = params.get('request', {})
headers = req.get('headers', {})
auth = headers.get('Authorization', '') or headers.get('authorization', '')
url_short = req.get('url', '')[:100]
if auth or '/api/' in url_short:
if auth:
print(f" AUTH: {req.get('method','?')} {url_short} -> {auth[:80]}")
else:
print(f" NO_AUTH: {req.get('method','?')} {url_short}")
elif method == 'Runtime.consoleAPICalled':
args = params.get('args', [])
texts = [str(a.get('value', '') or a.get('description', ''))[:150] for a in args]
print(f" [CONSOLE:{params.get('type','log')}] {' '.join(texts)}")
ws.close()
print("\nDone.")