#!/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.")
