mirror of
https://github.com/LifeArchiveProject/WeChatDataAnalysis.git
synced 2026-02-19 14:20:51 +08:00
- 新增 /api/sns/users:按发圈数统计联系人(支持 keyword/limit) - 新增 /api/sns/realtime/sync_latest:WCDB 实时增量同步到解密库(append-only),并持久化 sync state - 朋友圈媒体优先走“远程下载+解密”:图片支持 wcdb_decrypt_sns_image,视频/实况支持 ISAAC64(WeFlow 逻辑) - 增加 WeFlow WASM keystream(Node) 优先 + Python ISAAC64 fallback,提升兼容性 - wcdb_api.dll 支持多路径自动发现/环境变量覆盖,并在状态信息中回传实际使用路径
123 lines
3.0 KiB
JavaScript
123 lines
3.0 KiB
JavaScript
// Generate WeChat/WeFlow WxIsaac64 keystream via WeFlow's WASM module.
|
|
//
|
|
// Usage:
|
|
// node tools/weflow_wasm_keystream.js <key> <size>
|
|
//
|
|
// Prints a base64-encoded keystream to stdout (no extra logs).
|
|
|
|
const fs = require('fs')
|
|
const path = require('path')
|
|
const vm = require('vm')
|
|
|
|
function usageAndExit() {
|
|
process.stderr.write('Usage: node tools/weflow_wasm_keystream.js <key> <size>\\n')
|
|
process.exit(2)
|
|
}
|
|
|
|
const key = String(process.argv[2] || '').trim()
|
|
const size = Number(process.argv[3] || 0)
|
|
|
|
if (!key || !Number.isFinite(size) || size <= 0) usageAndExit()
|
|
|
|
const basePath = path.join(__dirname, '..', 'WeFlow', 'electron', 'assets', 'wasm')
|
|
const wasmPath = path.join(basePath, 'wasm_video_decode.wasm')
|
|
const jsPath = path.join(basePath, 'wasm_video_decode.js')
|
|
|
|
if (!fs.existsSync(wasmPath) || !fs.existsSync(jsPath)) {
|
|
process.stderr.write(`WeFlow WASM assets not found: ${basePath}\\n`)
|
|
process.exit(1)
|
|
}
|
|
|
|
const wasmBinary = fs.readFileSync(wasmPath)
|
|
const jsContent = fs.readFileSync(jsPath, 'utf8')
|
|
|
|
let capturedKeystream = null
|
|
let resolveInit
|
|
let rejectInit
|
|
const initPromise = new Promise((res, rej) => {
|
|
resolveInit = res
|
|
rejectInit = rej
|
|
})
|
|
|
|
const mockGlobal = {
|
|
console: { log: () => {}, error: () => {} }, // keep stdout clean
|
|
Buffer,
|
|
Uint8Array,
|
|
Int8Array,
|
|
Uint16Array,
|
|
Int16Array,
|
|
Uint32Array,
|
|
Int32Array,
|
|
Float32Array,
|
|
Float64Array,
|
|
BigInt64Array,
|
|
BigUint64Array,
|
|
Array,
|
|
Object,
|
|
Function,
|
|
String,
|
|
Number,
|
|
Boolean,
|
|
Error,
|
|
Promise,
|
|
require,
|
|
process,
|
|
setTimeout,
|
|
clearTimeout,
|
|
setInterval,
|
|
clearInterval,
|
|
}
|
|
|
|
mockGlobal.Module = {
|
|
onRuntimeInitialized: () => resolveInit(),
|
|
wasmBinary,
|
|
print: () => {},
|
|
printErr: () => {},
|
|
}
|
|
|
|
mockGlobal.self = mockGlobal
|
|
mockGlobal.self.location = { href: jsPath }
|
|
mockGlobal.WorkerGlobalScope = function () {}
|
|
mockGlobal.VTS_WASM_URL = `file://${wasmPath}`
|
|
|
|
mockGlobal.wasm_isaac_generate = (ptr, n) => {
|
|
const buf = new Uint8Array(mockGlobal.Module.HEAPU8.buffer, ptr, n)
|
|
capturedKeystream = new Uint8Array(buf) // copy view
|
|
}
|
|
|
|
try {
|
|
const context = vm.createContext(mockGlobal)
|
|
new vm.Script(jsContent, { filename: jsPath }).runInContext(context)
|
|
} catch (e) {
|
|
rejectInit(e)
|
|
}
|
|
|
|
;(async () => {
|
|
try {
|
|
await initPromise
|
|
|
|
if (!mockGlobal.Module.WxIsaac64 && mockGlobal.Module.asm && mockGlobal.Module.asm.WxIsaac64) {
|
|
mockGlobal.Module.WxIsaac64 = mockGlobal.Module.asm.WxIsaac64
|
|
}
|
|
if (!mockGlobal.Module.WxIsaac64) {
|
|
throw new Error('WxIsaac64 not found in WASM module')
|
|
}
|
|
|
|
capturedKeystream = null
|
|
const isaac = new mockGlobal.Module.WxIsaac64(key)
|
|
isaac.generate(size)
|
|
if (isaac.delete) isaac.delete()
|
|
|
|
if (!capturedKeystream) throw new Error('Failed to capture keystream')
|
|
|
|
const out = Buffer.from(capturedKeystream)
|
|
// Match WeFlow worker logic: reverse the captured Uint8Array.
|
|
out.reverse()
|
|
process.stdout.write(out.toString('base64'))
|
|
} catch (e) {
|
|
process.stderr.write(String(e && e.stack ? e.stack : e) + '\\n')
|
|
process.exit(1)
|
|
}
|
|
})()
|
|
|