File size: 4,077 Bytes
845178e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | #!/usr/bin/env python3
"""
从运行中的 WorkBuddy 提取 Token(通过 CDP)。
用法:
python extract_token.py # 默认 CDP 端口 9222
python extract_token.py --port 9223 # 自定义端口
python extract_token.py --save # 提取并保存到 data/token.json
前提: WorkBuddy 以 --remote-debugging-port=9222 启动。
"""
import argparse
import asyncio
import json
import sys
from pathlib import Path
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
try:
import httpx
except ImportError:
sys.exit("请先安装依赖: pip install httpx")
async def extract(cdp_port: int = 9222) -> dict | None:
base = f"http://127.0.0.1:{cdp_port}"
async with httpx.AsyncClient() as client:
try:
resp = await client.get(f"{base}/json", timeout=5)
except httpx.ConnectError:
print(f"无法连接 CDP ({base}),请确认 WorkBuddy 已用调试模式启动")
return None
targets = resp.json()
ws_url = None
for t in targets:
if t.get("type") == "page" and "workbench" in t.get("url", ""):
ws_url = t.get("webSocketDebuggerUrl")
break
if not ws_url:
for t in targets:
if t.get("type") == "page":
ws_url = t.get("webSocketDebuggerUrl")
break
if not ws_url:
print("未找到可用的 CDP 页面目标")
return None
try:
import websockets
except ImportError:
sys.exit("请安装 websockets: pip install websockets")
async with websockets.connect(ws_url) as ws:
cmd = {
"id": 1,
"method": "Runtime.evaluate",
"params": {
"expression": """
(async () => {
try {
const s = await window.vscode.ipcRenderer.invoke(
'vscode:genie:auth:getSession'
);
return JSON.stringify(s);
} catch(e) {
return JSON.stringify({error: e.message});
}
})()
""",
"awaitPromise": True,
"returnByValue": True,
},
}
await ws.send(json.dumps(cmd))
result = json.loads(await asyncio.wait_for(ws.recv(), timeout=10))
value = result.get("result", {}).get("result", {}).get("value", "")
if not value:
print("CDP 返回为空")
return None
session = json.loads(value)
if session.get("error"):
print(f"CDP 错误: {session['error']}")
return None
return session
def main():
parser = argparse.ArgumentParser(description="从 WorkBuddy 提取 Token")
parser.add_argument("--port", type=int, default=9222, help="CDP 端口 (默认 9222)")
parser.add_argument("--save", action="store_true", help="保存到 data/token.json")
args = parser.parse_args()
session = asyncio.run(extract(args.port))
if not session:
sys.exit(1)
# 兼容新版(嵌套 auth)和旧版(扁平)结构
auth = session.get("auth", session)
access_token = auth.get("accessToken", "")
refresh_token = auth.get("refreshToken", "")
if not access_token:
print("未获取到 accessToken")
sys.exit(1)
print(f"accessToken: {access_token[:40]}... (len={len(access_token)})")
print(f"refreshToken: {refresh_token[:40]}... (len={len(refresh_token)})")
if args.save:
import time
out = Path(__file__).parent / "data" / "token.json"
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(json.dumps({
"access_token": access_token,
"refresh_token": refresh_token,
"saved_at": time.strftime("%Y-%m-%d %H:%M:%S"),
}, indent=2))
print(f"\n已保存到 {out}")
if __name__ == "__main__":
main()
|