1414import hashlib
1515import os
1616import json
17+ import re
1718import random
1819import logging
20+ import asyncio
1921import httpx
2022from pathlib import Path
2123from typing import Optional , List , Dict , Any
@@ -203,7 +205,56 @@ def get_db_key_workflow():
203205
204206# 远程 API 配置
205207REMOTE_URL = "https://view.free.c3o.re/dashboard"
206- NEXT_ACTION_ID = "7c8f99280c70626ccf5960cc4a68f368197e15f8e9"
208+ BASE_URL = "https://view.free.c3o.re" # 用于拼接js
209+
210+ # NEXT_ACTION_ID = "7c8f99280c70626ccf5960cc4a68f368197e15f8e9" # 不可以硬编码
211+
212+
213+ async def fetch_js_and_scan (client : httpx .AsyncClient , js_path : str ) -> Optional [str ]:
214+ """
215+ 异步下载单个 JS 文件并匹配 Action ID
216+ """
217+ full_url = f"{ BASE_URL } { js_path } " if js_path .startswith ("/" ) else js_path
218+ try :
219+ response = await client .get (full_url )
220+ if response .status_code != 200 :
221+ return None
222+
223+ content = response .text
224+
225+ action_id_pattern = re .compile (r'createServerReference.*?["\']([a-f0-9]{42})["\'].*?["\']getUserConfigFromBytes["\']' )
226+
227+ match = action_id_pattern .search (content )
228+ if match :
229+ found_id = match .group (1 )
230+ return found_id
231+
232+ except Exception as e :
233+ logger .error (f"Error fetching { js_path } : { e } " )
234+ return None
235+
236+
237+ async def _get_next_action_id_async () -> str :
238+ async with httpx .AsyncClient (timeout = 10.0 ) as client :
239+
240+ resp = await client .get (REMOTE_URL )
241+ html = resp .text
242+
243+ js_file_pattern = re .compile (r'src="(/_next/static/chunks/[^"]+\.js)"' )
244+ js_files = set (js_file_pattern .findall (html ))
245+
246+ if not js_files :
247+ raise Exception ("未找到任何 Next.js chunk 文件,可能页面结构已变动。" )
248+
249+ tasks = [fetch_js_and_scan (client , js_path ) for js_path in js_files ]
250+
251+ results = await asyncio .gather (* tasks )
252+
253+ for res in results :
254+ if res :
255+ return res
256+
257+ raise Exception ("遍历了所有 JS 文件,但未找到匹配的 createServerReference ID。" )
207258
208259
209260def get_wechat_internal_global_config (wx_dir : Path , file_name1 ) -> bytes :
@@ -227,6 +278,14 @@ async def fetch_and_save_remote_keys(account: Optional[str] = None) -> Dict[str,
227278 wx_id_dir = _resolve_account_wxid_dir (account_dir )
228279 wxid = wx_id_dir .name
229280
281+ logger .info ("尝试获取next_action_id" )
282+ try :
283+ next_action_id = await _get_next_action_id_async ()
284+ logger .info (f"获取next_action_id成功: { next_action_id } " )
285+ except Exception as e :
286+ raise RuntimeError (f"获取next_action_id失败:{ e } " )
287+
288+
230289 logger .info (f"正在为账号 { wxid } 获取密钥..." )
231290
232291 try :
@@ -245,7 +304,7 @@ async def fetch_and_save_remote_keys(account: Optional[str] = None) -> Dict[str,
245304
246305 headers = {
247306 "Accept" : "text/x-component" ,
248- "Next-Action" : NEXT_ACTION_ID ,
307+ "Next-Action" : next_action_id ,
249308 "Next-Router-State-Tree" : "%5B%22%22%2C%7B%22children%22%3A%5B%22dashboard%22%2C%7B%22children%22%3A%5B%22__PAGE__%22%2C%7B%7D%2Cnull%2Cnull%5D%7D%2Cnull%2Cnull%5D%7D%2Cnull%2Cnull%2Ctrue%5D" ,
250309 "Origin" : "https://view.free.c3o.re" ,
251310 "Referer" : "https://view.free.c3o.re/dashboard" ,
0 commit comments