ksjsb/tools/jose_encrypt.js
2026-07-30 20:25:56 +08:00

86 lines
3.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 纯算加密服务:调用快手 captcha 的 Jose VM 生成 verifyParam。
//
// 加密管线(从 iframe bundle d702 模块还原):
// verifyParam = base64( Jose.$encrypt( utf8(JSON.stringify(payload)), KEY ) )
// KEY = "c7b645db-65e8-401f-b38c-4c07c5fff247" (硬编码, iframe bundle d702)
// Jose = encrypt.js 的字节码 VM; $encrypt 内含随机 IV.
//
// 用法 (CLI):
// node tools/jose_encrypt.js '{"captchaSn":"...","relativeX":123,...}'
// -> stdout: verifyParam(base64)
//
// 关键: 沙箱必须是【单 realm】——不能注入外层 String/Object/Uint8Array 等,
// 否则 VM 对宿主基本类型字符串的 .charCodeAt 方法派发失败 (跨 realm 原型链查不到)。
const fs = require("fs"), vm = require("vm"), path = require("path");
const ENC_PATH = path.join(__dirname, "..", "out", "captcha_net",
"js_07_rm_static_captcha_js_encrypt_ee7d2a41_js.js");
const KEY = "c7b645db-65e8-401f-b38c-4c07c5fff247";
function makeBox() {
const sandbox = {
console: { log: () => {}, error: () => {}, warn: () => {} },
setTimeout, clearTimeout, setImmediate, queueMicrotask,
Buffer,
btoa: (s) => Buffer.from(s, "binary").toString("base64"),
atob: (s) => Buffer.from(s, "base64").toString("binary"),
};
vm.createContext(sandbox); // 让 context 自带 intrinsic
sandbox.window = sandbox; sandbox.self = sandbox; sandbox.global = sandbox;
const src = fs.readFileSync(ENC_PATH, "utf-8");
vm.runInContext(src, sandbox, { filename: "encrypt.js", timeout: 30000 });
const factory = sandbox.webpackJsonp[0][1]["088e"];
const rq = (id) => id === "b639" ? { Buffer } : id === "dd40" ? (x) => x : {};
const mod = { exports: {} };
factory(mod, mod.exports, rq);
if (!sandbox.Jose) throw new Error("Jose 未加载");
return sandbox;
}
// 预置 in-sandbox 辅助 + 加密入口(全单 realm
function primeBox(sandbox) {
vm.runInContext(`
globalThis.__enc = function(payloadStr){
var u8 = new Uint8Array(Array.prototype.map.call(payloadStr, function(c){return c.charCodeAt(0);}));
globalThis.__out=null; globalThis.__done=null;
Jose.call("$encrypt", [u8, ${JSON.stringify(KEY)}, {
suc: function(v){ var s=""; for(var i=0;i<v.length;i++) s+=String.fromCharCode(v[i]); globalThis.__out=btoa(s); globalThis.__done='ok'; },
err: function(e){ globalThis.__out='ERR:'+(e&&e.message||e); globalThis.__done='err'; }
}]);
};
`, sandbox);
}
function encrypt(sandbox, payloadObj) {
const json = JSON.stringify(payloadObj);
sandbox.__done = null; sandbox.__out = null;
vm.runInContext(`__enc(${JSON.stringify(json)});`, sandbox);
// VM 回调经 setTimeout 异步, 外部轮询沙箱全局标志
return new Promise((resolve) => {
const t0 = Date.now();
const iv = setInterval(() => {
if (sandbox.__done !== null || Date.now() - t0 > 5000) {
clearInterval(iv);
resolve(sandbox.__done === "ok" ? sandbox.__out : (sandbox.__out || "ERR:timeout"));
}
}, 5);
});
}
module.exports = { makeBox, primeBox, encrypt, KEY };
// ---- CLI ----
if (require.main === module) {
const arg = process.argv[2];
if (!arg) { console.error("usage: node jose_encrypt.js '<json-payload>'"); process.exit(2); }
const box = makeBox(); primeBox(box);
let payload;
try { payload = JSON.parse(arg); }
catch (e) { console.error("payload JSON parse 失败:", e.message); process.exit(2); }
encrypt(box, payload).then((out) => {
if (out && out.indexOf("ERR:") === 0) { console.error(out); process.exit(1); }
process.stdout.write(out || "");
});
}