diff --git a/frontend/composables/useApi.js b/frontend/composables/useApi.js
index ffe5601..9ae1de6 100644
--- a/frontend/composables/useApi.js
+++ b/frontend/composables/useApi.js
@@ -530,8 +530,8 @@ export const useApi = () => {
}
// 获取数据库密钥
- const getDbKey = async () => {
- return await request('/get_db_key')
+ const getKeys = async () => {
+ return await request('/get_keys')
}
// 获取图片密钥
@@ -589,7 +589,7 @@ export const useApi = () => {
getWrappedAnnual,
getWrappedAnnualMeta,
getWrappedAnnualCard,
- getDbKey,
+ getKeys,
getImageKey,
getWxStatus,
}
diff --git a/frontend/pages/decrypt.vue b/frontend/pages/decrypt.vue
index 148ec45..4d60b64 100644
--- a/frontend/pages/decrypt.vue
+++ b/frontend/pages/decrypt.vue
@@ -58,7 +58,7 @@
- {{ isGettingDbKey ? '获取中...' : '自动获取' }}
+ {{ isGettingDbKey ? '获取中...' : '一键获取全部密钥' }}
@@ -71,7 +71,7 @@
- 尝试自动获取,或者使用 wx_key 等工具获取的64位十六进制字符串
+ 点击按钮将自动获取【数据库】与【图片】双重密钥。您也可以手动输入已知的64位密钥(使用wx_key等工具获取)。
@@ -183,53 +183,37 @@
-
手动输入或通过微信获取
-
+
此步骤将为您解密微信聊天中的图片
+
+
+ 如果您在第一步使用了“一键获取”或触发了云端解析,下方输入框已被自动填充。您也可可以使用wx_key等工具手动获取。
+
-
-
-
- 尝试自动获取,或使用 wx_key 获取图片密钥;AES 可选(V4-V2 需要)
-
@@ -450,7 +434,7 @@
import { ref, reactive, computed, onMounted, onBeforeUnmount } from 'vue'
import { useApi } from '~/composables/useApi'
-const { decryptDatabase, saveMediaKeys, getSavedKeys, getDbKey, getImageKey, getWxStatus } = useApi()
+const { decryptDatabase, saveMediaKeys, getSavedKeys, getKeys, getImageKey, getWxStatus } = useApi()
const loading = ref(false)
const error = ref('')
@@ -458,7 +442,6 @@ const warning = ref('') // 警告,用于密钥提示
const currentStep = ref(0)
const mediaAccount = ref('')
const isGettingDbKey = ref(false)
-const isGettingImageKey = ref(false)
// 步骤定义
const steps = [
@@ -548,74 +531,45 @@ const handleGetDbKey = async () => {
formErrors.key = ''
try {
- const statusRes = await getWxStatus() // pid不是主进程,但是没关系
+ const statusRes = await getWxStatus()
const wxStatus = statusRes?.wx_status
if (wxStatus?.is_running) {
- warning.value = '检测到微信正在运行,5秒后将终止进程并重启以获取密钥!!'
+ warning.value = '检测到微信正在运行,5秒后将终止进程并重启以获取全套密钥!'
await new Promise(resolve => setTimeout(resolve, 5000))
- } else {
- // 没有逻辑
}
- warning.value = '正在启动微信以获取密钥,请确保微信未开启“自动登录”,并在启动后 1 分钟内完成登录操作。'
+ warning.value = '正在启动微信,请确保微信未开启“自动登录”,并在弹窗中正常登录。'
- const res = await getDbKey()
+ const res = await getKeys()
if (res && res.status === 0) {
if (res.data?.db_key) {
formData.key = res.data.db_key
- warning.value = ''
}
-
- if (res.errmsg && res.errmsg !== 'ok') {
- warning.value = res.errmsg
+ // 直接把图片密钥也存好
+ if (res.data?.xor_key) {
+ manualKeys.xor_key = res.data.xor_key
}
+ if (res.data?.aes_key) {
+ manualKeys.aes_key = res.data.aes_key
+ }
+ warning.value = '🎉 数据库与图片密钥均已获取成功!'
+ // 3秒后清除成功提示,保持 UI 干净
+ setTimeout(() => { if(warning.value.includes('获取成功')) warning.value = '' }, 3000)
} else {
error.value = '获取失败: ' + (res?.errmsg || '未知错误')
+ warning.value = ''
}
} catch (e) {
console.error(e)
error.value = '系统错误: ' + e.message
+ warning.value = ''
} finally {
isGettingDbKey.value = false
}
}
-const handleGetImageKey = async () => {
- if (isGettingImageKey.value) return
- isGettingImageKey.value = true
- manualKeyErrors.xor_key = ''
- manualKeyErrors.aes_key = ''
-
- error.value = ''
- warning.value = ''
-
- try {
- const res = await getImageKey()
-
- if (res && res.status === 0) {
- if (res.data?.aes_key) {
- manualKeys.aes_key = res.data.aes_key
- }
- if (res.data?.xor_key) {
- // 后端记得处理为16进制再返回!!!
- manualKeys.xor_key = res.data.xor_key
- }
-
- if (res.errmsg && res.errmsg !== 'ok') {
- error.value = res.errmsg
- }
- } else {
- error.value = '获取失败: ' + (res?.errmsg || '未知错误')
- }
- } catch (e) {
- console.error(e)
- error.value = '系统错误: ' + e.message
- } finally {
- isGettingImageKey.value = false
- }
-}
const applyManualKeys = () => {
manualKeyErrors.xor_key = ''
@@ -749,13 +703,13 @@ const handleDecrypt = async () => {
if (!validateForm()) {
return
}
-
+
loading.value = true
error.value = ''
warning.value = ''
resetDbDecryptProgress()
-
+
try {
const canSse = process.client && typeof window !== 'undefined' && typeof EventSource !== 'undefined'
@@ -776,9 +730,26 @@ const handleDecrypt = async () => {
if (accounts.length > 0) mediaAccount.value = accounts[0]
} catch (e) {}
- clearManualKeys()
currentStep.value = 1
await prefillKeysForAccount(mediaAccount.value)
+
+ if (!manualKeys.xor_key && !manualKeys.aes_key) {
+ warning.value = '正在通过云端备选方案自动获取图片密钥,请稍候...'
+ try {
+ const imgRes = await getImageKey({ account: mediaAccount.value })
+ if (imgRes && imgRes.status === 0) {
+ if (imgRes.data?.xor_key) manualKeys.xor_key = imgRes.data.xor_key
+ if (imgRes.data?.aes_key) manualKeys.aes_key = imgRes.data.aes_key
+ warning.value = '已通过云端成功获取图片密钥!'
+ setTimeout(() => { if(warning.value.includes('成功获取')) warning.value = '' }, 3000)
+ } else {
+ warning.value = '云端获取图片密钥失败,您可以尝试手动填写。'
+ }
+ } catch (e) {
+ warning.value = '网络请求失败,请手动填写图片密钥。'
+ }
+ }
+
} else if (result.status === 'failed') {
if (result.failure_count > 0 && result.success_count === 0) {
error.value = result.message || '所有文件解密失败'
@@ -855,9 +826,26 @@ const handleDecrypt = async () => {
loading.value = false
if (data.status === 'completed') {
- clearManualKeys()
currentStep.value = 1
await prefillKeysForAccount(mediaAccount.value)
+
+ // 【重点】如果刚才没有通过双 Hook 拿到图片密钥,触发云端 API 备用方案自动获取
+ if (!manualKeys.xor_key && !manualKeys.aes_key) {
+ warning.value = '正在通过云端备选方案自动获取图片密钥,请稍候...'
+ try {
+ const imgRes = await getImageKey({ account: mediaAccount.value })
+ if (imgRes && imgRes.status === 0) {
+ if (imgRes.data?.xor_key) manualKeys.xor_key = imgRes.data.xor_key
+ if (imgRes.data?.aes_key) manualKeys.aes_key = imgRes.data.aes_key
+ warning.value = '已通过云端成功获取图片密钥!'
+ setTimeout(() => { if(warning.value.includes('成功获取')) warning.value = '' }, 3000)
+ } else {
+ warning.value = '云端获取图片密钥失败,您可以尝试手动填写。'
+ }
+ } catch (e) {
+ warning.value = '网络请求失败,请手动填写图片密钥。'
+ }
+ }
} else if (data.status === 'failed') {
error.value = data.message || '所有文件解密失败'
} else {
diff --git a/pyproject.toml b/pyproject.toml
index 567fc1a..e37fa6d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -20,7 +20,7 @@ dependencies = [
"pilk>=0.2.4",
"pypinyin>=0.53.0",
"jieba>=0.42.1",
- "wx_key",
+ "wx_key>=1.1.0",
"packaging",
"httpx",
]
diff --git a/src/wechat_decrypt_tool/key_service.py b/src/wechat_decrypt_tool/key_service.py
index 69a93d3..215003d 100644
--- a/src/wechat_decrypt_tool/key_service.py
+++ b/src/wechat_decrypt_tool/key_service.py
@@ -35,10 +35,12 @@ logger = logging.getLogger(__name__)
@dataclass
class HookConfig:
min_version: str
- pattern: str # 用 00 不要用 ? !!!! 否则C++内存会炸
+ pattern: str
mask: str
offset: int
-
+ md5_pattern: str = ""
+ md5_mask: str = ""
+ md5_offset: int = 0
class WeChatKeyFetcher:
def __init__(self):
@@ -50,13 +52,13 @@ class WeChatKeyFetcher:
return " ".join([f"{b:02X}" for b in hex_array])
def _get_hook_config(self, version_str: str) -> Optional[HookConfig]:
- """搬运自wx_key代码,未来用ida脚本直接获取即可"""
try:
v_curr = pkg_version.parse(version_str)
except Exception as e:
logger.error(f"版本号解析失败: {version_str} || {e}")
return None
+
if v_curr > pkg_version.parse("4.1.6.14"):
return HookConfig(
min_version=">4.1.6.14",
@@ -66,7 +68,10 @@ class WeChatKeyFetcher:
0x89, 0xCE, 0x48, 0x89
]),
mask="xxxxxxxxxxxxxxxxxxxxxxxx",
- offset=-3
+ offset=-3,
+ md5_pattern="48 8D 4D 00 48 89 4D B0 48 89 45 B8 48 8D 7D 00 48 8D 55 B0 48 89 F9",
+ md5_mask="xxx?xxxxxxxxxxx?xxxxxxx",
+ md5_offset=4
)
if pkg_version.parse("4.1.4") <= v_curr <= pkg_version.parse("4.1.6.14"):
@@ -78,10 +83,14 @@ class WeChatKeyFetcher:
0x83, 0xec, 0x50, 0x41
]),
mask="xxxxxxxxxx?xxxx?xxxxxxxx",
- offset=-3
+ offset=-3,
+ md5_pattern="48 8D 4D 00 48 89 4D B0 48 89 45 B8 48 8D 7D 00 48 8D 55 B0 48 89 F9",
+ md5_mask="xxx?xxxxxxxxxxx?xxxxxxx",
+ md5_offset=4
)
if v_curr < pkg_version.parse("4.1.4"):
+ """图片密钥可能是错的,版本过低没有测试"""
return HookConfig(
min_version="<4.1.4",
pattern=self._hex_array_to_str([
@@ -90,7 +99,10 @@ class WeChatKeyFetcher:
0x89, 0xce, 0x48, 0x89
]),
mask="xxxxxxxxxxxxxxxxxxxxxxxx",
- offset=-15 # -0xf
+ offset=-15, # -0xf
+ md5_pattern="48 8D 4D 00 48 89 4D B0 48 89 45 B8 48 8D 7D 00 48 8D 55 B0 48 89 F9",
+ md5_mask="xxx?xxxxxxxxxxx?xxxxxxx",
+ md5_offset=4
)
return None
@@ -134,13 +146,12 @@ class WeChatKeyFetcher:
logger.error(f"启动微信失败: {e}")
raise RuntimeError(f"无法启动微信: {e}")
- def fetch_key(self) -> str:
- """没有wx_key模块无法自动获取密钥"""
+ def fetch_key(self) -> dict:
+ """调用 wx_key 获取双密钥"""
if wx_key is None:
raise RuntimeError("wx_key 模块未安装或加载失败")
install_info = detect_wechat_installation()
-
exe_path = install_info.get('wechat_exe_path')
version = install_info.get('wechat_version')
@@ -151,30 +162,34 @@ class WeChatKeyFetcher:
config = self._get_hook_config(version)
if not config:
- raise RuntimeError(f"不支持的微信版本: {version}")
+ raise RuntimeError(f"原生获取失败:当前微信版本 ({version}) 过低,为保证稳定性,仅支持 4.1.5 及以上版本使用原生获取。")
self.kill_wechat()
-
pid = self.launch_wechat(exe_path)
logger.info(f"WeChat launched, PID: {pid}")
- logger.info(f"Initializing Hook with pattern: {config.pattern[:20]}... Offset: {config.offset}")
-
- if not wx_key.initialize_hook(pid, "", config.pattern, config.mask, config.offset):
+ if not wx_key.initialize_hook(pid, "", config.pattern, config.mask, config.offset,
+ config.md5_pattern, config.md5_mask, config.md5_offset):
err = wx_key.get_last_error_msg()
raise RuntimeError(f"Hook初始化失败: {err}")
start_time = time.time()
-
+ found_db_key = None
+ found_md5_data = None
try:
while True:
if time.time() - start_time > self.timeout_seconds:
- raise TimeoutError("获取密钥超时 (60s)")
+ raise TimeoutError("获取密钥超时 (60s),请确保在弹出的微信中完成登录。")
- key = wx_key.poll_key_data()
- if key:
- found_key = key
+ key_data = wx_key.poll_key_data()
+ if key_data:
+ if 'key' in key_data:
+ found_db_key = key_data['key']
+ if 'md5' in key_data:
+ found_md5_data = key_data['md5']
+
+ if found_db_key and found_md5_data:
break
while True:
@@ -185,15 +200,22 @@ class WeChatKeyFetcher:
logger.error(f"[Hook Error] {msg}")
time.sleep(0.1)
-
finally:
logger.info("Cleaning up hook...")
wx_key.cleanup_hook()
- if found_key:
- return found_key
- else:
- raise RuntimeError("未知错误,未获取到密钥")
+ aes_key = None # gemini !!! ???
+ xor_key = None
+
+ if found_md5_data and "|" in found_md5_data:
+ aes_key, xor_key_dec = found_md5_data.split("|")
+ xor_key = f"0x{int(xor_key_dec):02X}"
+
+ return {
+ "db_key": found_db_key,
+ "aes_key": aes_key,
+ "xor_key": xor_key
+ }
def get_db_key_workflow():
fetcher = WeChatKeyFetcher()
@@ -202,73 +224,11 @@ def get_db_key_workflow():
# ============================== 以下是图片密钥逻辑 =====================================
-
-# 远程 API 配置
-REMOTE_URL = "https://view.free.c3o.re/dashboard"
-BASE_URL = "https://view.free.c3o.re" # 用于拼接js
-
-# NEXT_ACTION_ID = "7c8f99280c70626ccf5960cc4a68f368197e15f8e9" # 不可以硬编码
-
-
-async def fetch_js_and_scan(client: httpx.AsyncClient, js_path: str) -> Optional[str]:
- """
- 异步下载单个 JS 文件并匹配 Action ID
- """
- full_url = f"{BASE_URL}{js_path}" if js_path.startswith("/") else js_path
- try:
- response = await client.get(full_url)
- if response.status_code != 200:
- return None
-
- content = response.text
-
- action_id_pattern = re.compile(r'createServerReference.*?["\']([a-f0-9]{42})["\'].*?["\']getUserConfigFromBytes["\']')
-
- match = action_id_pattern.search(content)
- if match:
- found_id = match.group(1)
- return found_id
-
- except Exception as e:
- logger.error(f"Error fetching {js_path}: {e}")
- return None
-
-
-async def _get_next_action_id_async() -> str:
- async with httpx.AsyncClient(timeout=10.0) as client:
-
- resp = await client.get(REMOTE_URL)
- html = resp.text
-
- js_file_pattern = re.compile(r'src="(/_next/static/chunks/[^"]+\.js)"')
- js_files = set(js_file_pattern.findall(html))
-
- if not js_files:
- raise Exception("未找到任何 Next.js chunk 文件,可能页面结构已变动。")
-
- tasks = [fetch_js_and_scan(client, js_path) for js_path in js_files]
-
- results = await asyncio.gather(*tasks)
-
- for res in results:
- if res:
- return res
-
- raise Exception("遍历了所有 JS 文件,但未找到匹配的 createServerReference ID。")
-
-
def get_wechat_internal_global_config(wx_dir: Path, file_name1) -> bytes:
- """
- 读微信目录下的主配置文件
- """
xwechat_files_root = wx_dir.parent
-
target_path = os.path.join(xwechat_files_root, "all_users", "config", file_name1)
-
if not os.path.exists(target_path):
- logger.error(f"未找到微信内部 global_config: {target_path}")
- raise FileNotFoundError(f"找不到文件: {target_path},请确认微信数据目录结构是否完整")
-
+ raise FileNotFoundError(f"找不到配置文件: {target_path},请确认微信数据目录结构是否完整")
return Path(target_path).read_bytes()
@@ -278,90 +238,36 @@ async def fetch_and_save_remote_keys(account: Optional[str] = None) -> Dict[str,
wx_id_dir = _resolve_account_wxid_dir(account_dir)
wxid = wx_id_dir.name
- logger.info("尝试获取next_action_id")
- try:
- next_action_id = await _get_next_action_id_async()
- logger.info(f"获取next_action_id成功: {next_action_id}")
- except Exception as e:
- raise RuntimeError(f"获取next_action_id失败:{e}")
+ url = "https://view.free.c3o.re/api/key"
+ data = {"weixinIDFolder": wxid}
-
- logger.info(f"正在为账号 {wxid} 获取密钥...")
+ logger.info(f"正在为账号 {wxid} 获取云端备选图片密钥...")
try:
- blob1_bytes = get_wechat_internal_global_config(wx_id_dir, file_name1= "global_config") # 估计这是唯一有效的数据!!
- logger.info(f"获取微信内部配置成功,大小: {len(blob1_bytes)} bytes")
+ blob1_bytes = get_wechat_internal_global_config(wx_id_dir, file_name1="global_config")
+ blob2_bytes = get_wechat_internal_global_config(wx_id_dir, file_name1="global_config.crc")
except Exception as e:
raise RuntimeError(f"读取微信内部文件失败: {e}")
- try:
- blob2_bytes = get_wechat_internal_global_config(wx_id_dir, file_name1= "global_config.crc")
- logger.info(f"获取微信内部配置成功,大小: {len(blob2_bytes)} bytes")
- except Exception as e:
- raise RuntimeError(f"读取微信内部文件失败: {e}")
-
- blob3_bytes = b""
-
- headers = {
- "Accept": "text/x-component",
- "Next-Action": next_action_id,
- "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",
- "Origin": "https://view.free.c3o.re",
- "Referer": "https://view.free.c3o.re/dashboard",
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
- }
-
files = {
- '1': ('blob', blob1_bytes, 'application/octet-stream'),
- '2': ('blob', blob2_bytes, 'application/octet-stream'),
- '3': ('blob', blob3_bytes, 'application/octet-stream'),
- '0': (None, json.dumps([wxid, "$A1", "$A2", "$A3", 0],separators=(",",":")).encode('utf-8')),
+ 'fileBytes': ('file', blob1_bytes, 'application/octet-stream'),
+ 'crcBytes': ('file.crc', blob2_bytes, 'application/octet-stream'),
}
-
async with httpx.AsyncClient(timeout=30) as client:
- logger.info("向远程服务器发送请求...")
- response = await client.post(REMOTE_URL, headers=headers, files=files)
+ logger.info("向云端 API 发送请求...")
+ response = await client.post(url, data=data, files=files)
if response.status_code != 200:
- raise RuntimeError(f"远程服务器错误: {response.status_code} - {response.text[:100]}")
+ raise RuntimeError(f"云端服务器错误: {response.status_code} - {response.text[:100]}")
+ config = response.json()
+ if not config:
+ raise RuntimeError("云端解析失败: 返回数据为空")
- result_data = {}
- lines = response.text.split('\n')
-
- found_config = False
- for line in lines:
- line = line.strip()
- if not line:
- continue
-
- if line.startswith('1:'):
- try:
- json_part = line[2:] # 去掉 "1:"
- data_obj = json.loads(json_part)
-
- if "config" in data_obj:
- config = data_obj["config"]
- result_data = {
- "xor_key": config.get("xor_key", ""),
- "aes_key": config.get("aes_key", ""),
- "nick_name": config.get("nick_name", ""),
- "avatar_url": config.get("avatar_url", "")
- }
- found_config = True
- break
- except Exception as e:
- logger.warning(f"解析响应行失败: {e}")
- continue
-
- if not found_config or not result_data.get("aes_key"):
- logger.error(f"响应中未找到密钥信息。Full Response: {response.text[:500]}")
- raise RuntimeError("解析失败: 服务器未返回 config 数据")
-
- # 6. 处理并保存密钥
- xor_raw = str(result_data["xor_key"])
- aes_val = str(result_data["aes_key"])
+ # 新 API 的字段兼容处理
+ xor_raw = str(config.get("xorKey", config.get("xor_key", "")))
+ aes_val = str(config.get("aesKey", config.get("aes_key", "")))
try:
if xor_raw.startswith("0x"):
@@ -382,6 +288,5 @@ async def fetch_and_save_remote_keys(account: Optional[str] = None) -> Dict[str,
"wxid": wxid,
"xor_key": xor_hex_str,
"aes_key": aes_val,
- "nick_name": result_data["nick_name"]
- }
-
+ "nick_name": config.get("nickName", config.get("nick_name", ""))
+ }
\ No newline at end of file
diff --git a/src/wechat_decrypt_tool/routers/chat.py b/src/wechat_decrypt_tool/routers/chat.py
index f741b8a..4a00212 100644
--- a/src/wechat_decrypt_tool/routers/chat.py
+++ b/src/wechat_decrypt_tool/routers/chat.py
@@ -4114,8 +4114,7 @@ def _collect_chat_messages(
render_type = "system"
template = _extract_xml_tag_text(raw_text, "template")
if template:
- import re
-
+ # import re
pat_usernames.update({m.group(1) for m in re.finditer(r"\$\{([^}]+)\}", template) if m.group(1)})
content_text = "[拍一拍]"
else:
@@ -4255,8 +4254,7 @@ def _collect_chat_messages(
elif local_type == 50:
render_type = "voip"
try:
- import re
-
+ # import re
block = raw_text
m_voip = re.search(
r"(]*>.*?)",
@@ -5013,7 +5011,7 @@ def list_chat_messages(
render_type = "system"
template = _extract_xml_tag_text(raw_text, "template")
if template:
- import re
+ # import re
pat_usernames.update({m.group(1) for m in re.finditer(r"\$\{([^}]+)\}", template) if m.group(1)})
content_text = "[拍一拍]"
@@ -5145,7 +5143,7 @@ def list_chat_messages(
elif local_type == 50:
render_type = "voip"
try:
- import re
+ # import re
block = raw_text
m_voip = re.search(
@@ -5494,6 +5492,7 @@ def list_chat_messages(
if existing_local:
try:
+ # import re
cur = str(m.get("emojiUrl") or "")
if cur and re.match(r"^https?://", cur, flags=re.I) and ("/api/chat/media/emoji" not in cur):
m["emojiRemoteUrl"] = cur
diff --git a/src/wechat_decrypt_tool/routers/keys.py b/src/wechat_decrypt_tool/routers/keys.py
index 101f9e5..2a4da9a 100644
--- a/src/wechat_decrypt_tool/routers/keys.py
+++ b/src/wechat_decrypt_tool/routers/keys.py
@@ -53,31 +53,28 @@ async def get_saved_keys(account: Optional[str] = None):
}
-@router.get("/api/get_db_key", summary="自动获取微信数据库密钥")
+@router.get("/api/get_keys", summary="自动获取微信数据库与图片密钥")
async def get_wechat_db_key():
"""
自动流程:
1. 结束微信进程
2. 启动微信
- 3. 根据版本注入 Hook
- 4. 抓取密钥并返回
+ 3. 根据版本注入双 Hook
+ 4. 抓取 DB 与 图片密钥(AES + XOR)并返回
"""
try:
- # 不需要async吧,我相信fastapi的线程池
- db_key = get_db_key_workflow()
+ keys_data = get_db_key_workflow()
return {
"status": 0,
"errmsg": "ok",
- "data": {
- "db_key": db_key
- }
+ "data": keys_data # 现在完美包含了 db_key, aes_key, xor_key
}
except TimeoutError:
return {
"status": -1,
- "errmsg": "获取超时,请确保微信没有开启自动登录 或者 加快手速",
+ "errmsg": "获取超时,请确保微信没有开启自动登录并且在弹窗中完成了登录",
"data": {}
}
except Exception as e:
@@ -88,6 +85,7 @@ async def get_wechat_db_key():
}
+
@router.get("/api/get_image_key", summary="获取并保存微信图片密钥")
async def get_image_key(account: Optional[str] = None):
"""
diff --git a/tools/key_wheels/wx_key-1.0.0-cp310-cp310-win_amd64.whl b/tools/key_wheels/wx_key-1.0.0-cp310-cp310-win_amd64.whl
deleted file mode 100644
index 0276318..0000000
Binary files a/tools/key_wheels/wx_key-1.0.0-cp310-cp310-win_amd64.whl and /dev/null differ
diff --git a/tools/key_wheels/wx_key-1.0.0-cp311-cp311-win_amd64.whl b/tools/key_wheels/wx_key-1.0.0-cp311-cp311-win_amd64.whl
deleted file mode 100644
index b286145..0000000
Binary files a/tools/key_wheels/wx_key-1.0.0-cp311-cp311-win_amd64.whl and /dev/null differ
diff --git a/tools/key_wheels/wx_key-1.0.0-cp312-cp312-win_amd64.whl b/tools/key_wheels/wx_key-1.0.0-cp312-cp312-win_amd64.whl
deleted file mode 100644
index c049ea0..0000000
Binary files a/tools/key_wheels/wx_key-1.0.0-cp312-cp312-win_amd64.whl and /dev/null differ
diff --git a/tools/key_wheels/wx_key-1.0.0-cp313-cp313-win_amd64.whl b/tools/key_wheels/wx_key-1.0.0-cp313-cp313-win_amd64.whl
deleted file mode 100644
index 42afeda..0000000
Binary files a/tools/key_wheels/wx_key-1.0.0-cp313-cp313-win_amd64.whl and /dev/null differ
diff --git a/tools/key_wheels/wx_key-1.0.0-cp314-cp314-win_amd64.whl b/tools/key_wheels/wx_key-1.0.0-cp314-cp314-win_amd64.whl
deleted file mode 100644
index d19b6f4..0000000
Binary files a/tools/key_wheels/wx_key-1.0.0-cp314-cp314-win_amd64.whl and /dev/null differ
diff --git a/tools/key_wheels/wx_key-1.1.0-cp310-cp310-win_amd64.whl b/tools/key_wheels/wx_key-1.1.0-cp310-cp310-win_amd64.whl
new file mode 100644
index 0000000..3d8ae63
Binary files /dev/null and b/tools/key_wheels/wx_key-1.1.0-cp310-cp310-win_amd64.whl differ
diff --git a/tools/key_wheels/wx_key-1.1.0-cp311-cp311-win_amd64.whl b/tools/key_wheels/wx_key-1.1.0-cp311-cp311-win_amd64.whl
new file mode 100644
index 0000000..c628766
Binary files /dev/null and b/tools/key_wheels/wx_key-1.1.0-cp311-cp311-win_amd64.whl differ
diff --git a/tools/key_wheels/wx_key-1.1.0-cp312-cp312-win_amd64.whl b/tools/key_wheels/wx_key-1.1.0-cp312-cp312-win_amd64.whl
new file mode 100644
index 0000000..2a39ad4
Binary files /dev/null and b/tools/key_wheels/wx_key-1.1.0-cp312-cp312-win_amd64.whl differ
diff --git a/tools/key_wheels/wx_key-1.1.0-cp313-cp313-win_amd64.whl b/tools/key_wheels/wx_key-1.1.0-cp313-cp313-win_amd64.whl
new file mode 100644
index 0000000..f00eccc
Binary files /dev/null and b/tools/key_wheels/wx_key-1.1.0-cp313-cp313-win_amd64.whl differ
diff --git a/tools/key_wheels/wx_key-1.1.0-cp314-cp314-win_amd64.whl b/tools/key_wheels/wx_key-1.1.0-cp314-cp314-win_amd64.whl
new file mode 100644
index 0000000..26cffc4
Binary files /dev/null and b/tools/key_wheels/wx_key-1.1.0-cp314-cp314-win_amd64.whl differ
diff --git a/uv.lock b/uv.lock
index 04b52ea..3dc6aee 100644
--- a/uv.lock
+++ b/uv.lock
@@ -919,7 +919,7 @@ requires-dist = [
{ name = "requests", specifier = ">=2.32.4" },
{ name = "typing-extensions", specifier = ">=4.8.0" },
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.24.0" },
- { name = "wx-key" },
+ { name = "wx-key", specifier = ">=1.1.0" },
{ name = "zstandard", specifier = ">=0.23.0" },
]
provides-extras = ["build"]
@@ -935,13 +935,13 @@ wheels = [
[[package]]
name = "wx-key"
-version = "1.0.0"
+version = "1.1.0"
source = { registry = "tools/key_wheels" }
wheels = [
- { path = "wx_key-1.0.0-cp311-cp311-win_amd64.whl" },
- { path = "wx_key-1.0.0-cp312-cp312-win_amd64.whl" },
- { path = "wx_key-1.0.0-cp313-cp313-win_amd64.whl" },
- { path = "wx_key-1.0.0-cp314-cp314-win_amd64.whl" },
+ { path = "wx_key-1.1.0-cp311-cp311-win_amd64.whl" },
+ { path = "wx_key-1.1.0-cp312-cp312-win_amd64.whl" },
+ { path = "wx_key-1.1.0-cp313-cp313-win_amd64.whl" },
+ { path = "wx_key-1.1.0-cp314-cp314-win_amd64.whl" },
]
[[package]]