1515- ** 健康检查** : 内置服务健康监控
1616- ** 大文件支持** : 最大支持 500MB 视频文件
1717
18+ ## 如何获取 decode_key?(常见问题)
19+
20+ > 对应 issue #1 / #9 。** 本仓库只负责解密,不负责抓取微信接口。**
21+
22+ ` decode_key ` 和加密视频 URL 都来自** 微信原始接口的响应 JSON** ,结构如下:
23+
24+ ``` json
25+ {
26+ "data" : {
27+ "object_desc" : {
28+ "media" : [{
29+ "decode_key" : " 2136343393" , // 解密种子(即本服务的 decode_key)
30+ "url" : " https://..." , // 加密视频下载链接
31+ "file_size" : 14088528
32+ }]
33+ }
34+ }
35+ }
36+ ```
37+
38+ 获取途径(任选其一):
39+
40+ 1 . ** 第三方接口** :例如 ` api.tikhub.io ` 的视频号详情接口,响应直接包含
41+ ` decode_key ` 与加密视频 URL。
42+ 2 . ** 自行抓包** :在 PC 端微信安装 SSL 证书抓包,打开视频号并搜索关键字,
43+ 即可在接口响应 JSON 中找到 ` decode_key ` 和对应加密视频 URL。
44+ > 注意:微信部分流量走私有协议 mmtls,普通 HTTPS 抓包不一定能拿到,需视
45+ > 客户端版本与抓包方案而定。
46+
47+ 拿到 ` decode_key ` 和加密视频文件后,再调用本服务 ` POST /api/decrypt ` 解密。
48+
1849## 架构说明
1950
2051```
2758│ Express.js API Server │
2859│ (Node.js + Multer + CORS) │
2960└───────────────────┬─────────────────────────────────┘
30- │ RPC Call via page.evaluate()
61+ │ ① RPC:仅生成 128KB 密钥流
62+ │ page.evaluate(generateKeystream)
3163 ▼
3264┌─────────────────────────────────────────────────────┐
3365│ Playwright Chromium Browser │
3971│ │ └─────────────────────────────────┘ │ │
4072│ │ │ │
4173│ │ RPC Functions: │ │
42- │ │ - generateKeystream(decodeKey) │ │
43- │ │ - decryptVideo(encrypted, keystream) │ │
74+ │ │ - generateKeystream(decodeKey) ← 唯一职责 │ │
4475│ │ - checkWasmStatus() │ │
4576│ └───────────────────────────────────────────┘ │
77+ └───────────────────┬─────────────────────────────────┘
78+ │ ② 返回 128KB 密钥流
79+ ▼
80+ ┌─────────────────────────────────────────────────────┐
81+ │ ③ Node.js 端 XOR 解密(lib/decrypt.js) │
82+ │ 视频整段 Buffer 不进浏览器 → 规避 CDP 100MB 上限 │
4683└─────────────────────────────────────────────────────┘
4784```
4885
86+ > ** v2.1 架构变更(修复大文件解密崩溃)** :旧版把整段视频经 CDP 管道
87+ > 传入浏览器做 XOR,base64 膨胀后超过 Chromium DevTools 协议 100MB 单条
88+ > 消息上限,导致 80MB+ 文件解密时页面崩溃(issue #4 / #6 / #8 )。现在
89+ > 浏览器只负责生成 128KB 密钥流,XOR 解密改在 Node.js 端用 Buffer 完成,
90+ > 文件大小不再受此限制。
91+
4992### 为什么选择 Playwright?
5093
5194WeChat 的 WASM 模块依赖浏览器特定的 API (` fetch ` , ` self ` , ` window ` 等),无法直接在 Node.js 环境中运行。Playwright 方案的优势:
@@ -129,7 +172,7 @@ GET /
129172``` json
130173{
131174 "service" : " WeChat Channels Video Decryption API" ,
132- "version" : " 2.0 .0" ,
175+ "version" : " 2.1 .0" ,
133176 "engine" : " Playwright + Chromium" ,
134177 "author" : " Evil0ctal" ,
135178 "endpoints" : {
@@ -153,7 +196,7 @@ GET /health
153196{
154197 "status" : " ok" ,
155198 "service" : " wechat-decrypt-api" ,
156- "version" : " 2.0 .0" ,
199+ "version" : " 2.1 .0" ,
157200 "engine" : " playwright" ,
158201 "wasm" : {
159202 "loaded" : true ,
@@ -428,19 +471,22 @@ const keystreamBase64 = await page.evaluate(async (key) => {
428471
429472** 关键** : 使用 ` http:// ` 而非 ` file:// ` 协议,避免浏览器 CORS 限制,使本地 WASM 文件加载成功。
430473
431- ### 3. 数据传输
474+ ### 3. 数据传输(v2.1:视频不进浏览器)
432475
433- 使用 Base64 编码在 Node.js 和浏览器之间传输二进制数据:
476+ 浏览器与 Node.js 之间 ** 只传输 128KB 密钥流 ** ,加密视频本身始终留在 Node.js 端:
434477
435478``` javascript
436- // Node.js → Browser
437- const encryptedBase64 = videoFile . buffer . toString ( ' base64 ' );
438-
439- // Browser → Node.js
440- const decryptedBase64 = await page . evaluate ( ... );
441- const decrypted = Buffer .from (decryptedBase64 , ' base64' );
479+ // Browser → Node.js:仅密钥流(base64,约 175KB,远小于 CDP 100MB 上限)
480+ const keystreamBase64 = await page . evaluate (
481+ async ( key ) => await window . generateKeystream (key),
482+ decode_key
483+ );
484+ const keystream = Buffer .from (keystreamBase64 , ' base64' );
442485```
443486
487+ > 旧版会把整段视频 ` toString('base64') ` 传入浏览器,80MB 文件膨胀到约
488+ > 107MB,超过 CDP 管道 100MB 上限而导致页面崩溃。v2.1 不再传输视频数据。
489+
444490### 4. Isaac64 密钥流生成
445491
446492WASM 模块实现了微信魔改的 Isaac64 算法:
@@ -455,16 +501,25 @@ window.wasm_isaac_generate = function(ptr, size) {
455501
456502** 重要** : 密钥流必须反转 (` reverse() ` ) 才能正确解密,这是微信特有的实现细节。
457503
458- ### 5. XOR 解密
504+ ### 5. XOR 解密(v2.1:Node.js 端执行)
459505
460- 前 128KB 数据通过 XOR 操作解密:
506+ 微信仅加密文件** 前 128KB** ,其余为明文。XOR 解密在 Node.js 端用 Buffer 完成
507+ (` lib/decrypt.js ` 的 ` decryptBuffer ` ),无需把视频送进浏览器:
461508
462509``` javascript
463- for (let i = 0 ; i < 131072 && i < encrypted .length ; i++ ) {
464- decrypted[i] = encrypted[i] ^ keystream[i];
510+ function decryptBuffer (encrypted , keystream ) {
511+ const decrypted = Buffer .from (encrypted); // 明文部分原样保留
512+ const decryptLen = Math .min (KEYSTREAM_SIZE , encrypted .length , keystream .length );
513+ for (let i = 0 ; i < decryptLen; i++ ) {
514+ decrypted[i] = encrypted[i] ^ keystream[i];
515+ }
516+ return decrypted;
465517}
466518```
467519
520+ 该逻辑与 Python CLI(` decrypt_wechat_video_cli.py ` )字节级一致,并有单元测试
521+ (` npm test ` )覆盖含 120MB 大文件在内的边界场景。
522+
468523## 故障排除
469524
470525### 问题: WASM 模块加载超时
@@ -506,6 +561,20 @@ docker-compose build --no-cache
5065612 . 检查 API 响应中的错误信息
5075623 . 验证解密文件的前 12 字节应为: ` 00 00 00 XX 66 74 79 70 ` (MP4 签名)
508563
564+ ### 问题: 大文件(80MB+)解密报错 "Target page... has been closed"
565+
566+ ** 症状** (issue #4 / #6 / #8 ):
567+ ```
568+ page.evaluate: Target page, context or browser has been closed
569+ Too large read data is pending: capacity=104857600 ...
570+ ```
571+
572+ ** 原因** : 旧版(≤ v2.0)把整段视频经 CDP 管道传入浏览器做 XOR,base64 膨胀后
573+ 超过 Chromium DevTools 协议 100MB 单条消息上限,导致页面崩溃。
574+
575+ ** 解决方案** : 升级到 ** v2.1+** 。XOR 解密已移至 Node.js 端,浏览器只生成 128KB
576+ 密钥流,文件大小不再受此限制(仅受 multer 500MB 与服务器内存约束)。
577+
509578### 问题: 文件上传失败 (413 错误)
510579
511580** 症状** :
@@ -537,9 +606,11 @@ deploy:
537606 memory : 4G # 增加内存限制
538607` ` `
539608
540- ### 3. 启用请求缓存
609+ ### 3. 密钥流缓存(v2.1 已内置)
541610
542- 对于相同的 decode_key,可以缓存生成的密钥流以提高性能。
611+ 相同 ` decode_key` 的密钥流恒定,服务端已内置 LRU 缓存:命中后跳过浏览器 WASM
612+ 调用(并发接口连页面池都不占用)。缓存上限可通过环境变量 `KEYSTREAM_CACHE_MAX`
613+ 配置(默认 100)。
543614
544615# ## 4. 负载均衡
545616
@@ -569,6 +640,14 @@ Evil0ctal - evil0ctal1985@gmail.com
569640
570641# # 更新日志
571642
643+ # ## v2.1.0 (2026-06-09)
644+ - **修复大文件解密崩溃**(issue # 4 / #6 / #8):XOR 解密从浏览器移至 Node.js 端,
645+ 视频数据不再经 CDP 管道传输,规避 DevTools 协议 100MB 单条消息上限。80MB+ /
646+ 100MB+ / 300MB+ 文件均可正常解密。
647+ - **新增密钥流 LRU 缓存**:相同 `decode_key` 跳过浏览器 WASM 调用,可经
648+ ` KEYSTREAM_CACHE_MAX` 配置上限。
649+ - **解密核心抽离为 `lib/decrypt.js`** 并新增单元测试(`npm test`,含 120MB 边界场景)。
650+
572651# ## v2.0.0 (2025-10-17)
573652- 采用 Playwright + RPC 架构
574653- 100% 兼容微信官方 WASM v1.2.46
0 commit comments