This commit is contained in:
dela
2026-03-11 14:21:26 +08:00
parent f923257af6
commit 502307cbcd
14 changed files with 37495 additions and 125 deletions

1503
asset/challenge.js Normal file

File diff suppressed because it is too large Load Diff

469
asset/deobfuscate.js Normal file
View File

@@ -0,0 +1,469 @@
/**
* hsw.js AST 解混淆脚本 v4
*
* 双解码器支持:
* - PW/QQ: base=311, 596条, rotation=275
* - Qg: base=438, 133条, 无旋转
*
* AST 遍历 passes:
* 1. 别名收集 (两个解码器各自的别名链)
* 2. 常量传播 + 解码替换
* 3. 属性访问简化: obj["prop"] → obj.prop
* 4. 字符串拼接折叠: "a".concat("b") → "ab"
* 5. 死代码清理
*/
const fs = require("fs");
const path = require("path");
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generate = require("@babel/generator").default;
const t = require("@babel/types");
const SRC = path.join(__dirname, "hsw.js");
const OUT = path.join(__dirname, "hsw.deobfuscated.js");
const src = fs.readFileSync(SRC, "utf-8");
// ═══════════════════════════════════════════
// Phase 1: 提取两个字符串数组 + 解码
// ═══════════════════════════════════════════
console.log("[*] Phase 1: 提取字符串数组...");
function decode(encoded) {
const chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=";
let raw = "";
let bc = 0;
let bs = 0;
let ch;
let idx = 0;
while ((ch = encoded.charAt(idx++))) {
ch = chars.indexOf(ch);
if (~ch) {
bs = bc % 4 ? 64 * bs + ch : ch;
if (bc++ % 4)
raw += String.fromCharCode(255 & (bs >> ((-2 * bc) & 6)));
}
}
let uri = "";
for (let i = 0; i < raw.length; i++)
uri += "%" + ("00" + raw.charCodeAt(i).toString(16)).slice(-2);
return decodeURIComponent(uri);
}
// ── 解码器 1: tH / QQ / PW (base=311, 有旋转) ──
const arr1Match = src.match(
/tH\s*=\s*function\s*\(\)\s*\{\s*var\s+Ig\s*=\s*\[([\s\S]*?)\];\s*return\s*\(\s*tH/
);
if (!arr1Match) { console.error("[-] 无法提取 tH 数组"); process.exit(1); }
const raw1 = eval(`[${arr1Match[1]}]`);
const decoded1 = raw1.map((s) => { try { return decode(s); } catch { return null; } });
console.log(`[+] 解码器1 (PW/QQ): ${raw1.length} 条, base=311`);
// 暴力搜索旋转
const BASE1 = 311;
const LEN1 = decoded1.length;
const lookup1 = (rot, idx) => decoded1[((((idx - BASE1 + rot) % LEN1) + LEN1) % LEN1)];
const constraints1 = [
[814, "length"], [507, "concat"], [606, "createElement"],
[675, "canvas"], [440, "prototype"], [719, "toString"],
[874, "call"], [532, "create"], [716, "test"],
[897, "width"], [811, "height"], [873, "toDataURL"],
];
let rot1 = -1;
for (let r = 0; r < LEN1; r++) {
if (constraints1.every(([i, e]) => lookup1(r, i) === e)) { rot1 = r; break; }
}
if (rot1 === -1) { console.error("[-] PW/QQ 旋转搜索失败"); process.exit(1); }
console.log(`[+] PW/QQ 旋转偏移: ${rot1}`);
const map1 = new Map();
for (let i = BASE1; i < BASE1 + LEN1; i++) {
const v = lookup1(rot1, i);
if (v != null) map1.set(i, v);
}
// ── 解码器 2: xf / Qg (base=438, 无旋转) ──
const arr2Match = src.match(
/xf\s*=\s*function\s*\(\)\s*\{\s*var\s+Ig\s*=\s*\[([\s\S]*?)\];\s*return\s*\(\s*xf/
);
if (!arr2Match) { console.error("[-] 无法提取 xf 数组"); process.exit(1); }
const raw2 = eval(`[${arr2Match[1]}]`);
const decoded2 = raw2.map((s) => { try { return decode(s); } catch { return null; } });
console.log(`[+] 解码器2 (Qg): ${raw2.length} 条, base=438`);
const BASE2 = 438;
const map2 = new Map();
for (let i = 0; i < decoded2.length; i++) {
if (decoded2[i] != null) map2.set(i + BASE2, decoded2[i]);
}
// 验证 Qg 的一些已知值
const constraints2 = [
[441, "length"], // Qg(441) 在 wasm 段出现大量
[439, "buffer"], // Qg(439)
[453, "name"], // Qg(453)
[456, "isArray"], // Array[Qg(456)]
[457, "exec"], // regex.exec
[447, "string"], // typeof === Qg(447)
[449, "constructor"],// Ig[Qg(449)]
[462, "message"], // Ig[Qg(462)]
[463, "stack"], // Ig[Qg(463)]
[476, "set"], // cP().set()
[467, "subarray"], // Ig[Qg(467)]
];
let c2pass = 0;
for (const [idx, exp] of constraints2) {
const act = map2.get(idx);
if (act === exp) c2pass++;
else console.log(` [!] Qg(${idx}): 期望 "${exp}", 实际 "${act}"`);
}
if (c2pass < constraints2.length) {
// 需要旋转
console.log(`[!] Qg 直接映射验证 ${c2pass}/${constraints2.length}, 尝试旋转搜索...`);
const LEN2 = decoded2.length;
let rot2 = -1;
for (let r = 0; r < LEN2; r++) {
const lk = (idx) => decoded2[((((idx - BASE2 + r) % LEN2) + LEN2) % LEN2)];
if (constraints2.every(([i, e]) => lk(i) === e)) { rot2 = r; break; }
}
if (rot2 !== -1 && rot2 !== 0) {
console.log(`[+] Qg 旋转偏移: ${rot2}`);
map2.clear();
for (let i = BASE2; i < BASE2 + LEN2; i++) {
const v = decoded2[((((i - BASE2 + rot2) % LEN2) + LEN2) % LEN2)];
if (v != null) map2.set(i, v);
}
}
}
console.log(`[+] 映射表: PW/QQ=${map1.size}条, Qg=${map2.size}条, 合计=${map1.size + map2.size}`);
// ── 合并映射: 根据解码器名来分派 ──
// decoderGroup1: PW, QQ, 以及它们的别名 → 查 map1
// decoderGroup2: Qg, 以及它的别名 → 查 map2
const group1Names = new Set(["PW", "QQ"]);
const group2Names = new Set(["Qg"]);
function getMapForDecoder(name) {
if (group1Names.has(name)) return map1;
if (group2Names.has(name)) return map2;
return null;
}
// ═══════════════════════════════════════════
// Phase 2: 解析 AST
// ═══════════════════════════════════════════
console.log("[*] Phase 2: 解析 AST...");
const ast = parser.parse(src, {
sourceType: "script",
plugins: [],
errorRecovery: true,
});
console.log("[+] AST 解析完成");
// ═══════════════════════════════════════════
// Phase 3: Pass 1 — 别名收集 (两个解码器)
// ═══════════════════════════════════════════
console.log("[*] Phase 3: 收集解码器别名...");
// 追踪: var X = PW → X 属于 group1
// var Y = Qg → Y 属于 group2
// var Z = X → Z 属于 X 的 group
const allDecoders = new Set([...group1Names, ...group2Names]);
traverse(ast, {
VariableDeclarator(path) {
if (
t.isIdentifier(path.node.id) &&
t.isIdentifier(path.node.init) &&
allDecoders.has(path.node.init.name)
) {
const src = path.node.init.name;
const dst = path.node.id.name;
if (group1Names.has(src)) group1Names.add(dst);
else if (group2Names.has(src)) group2Names.add(dst);
allDecoders.add(dst);
}
},
AssignmentExpression(path) {
if (
t.isIdentifier(path.node.left) &&
t.isIdentifier(path.node.right) &&
allDecoders.has(path.node.right.name)
) {
const src = path.node.right.name;
const dst = path.node.left.name;
if (group1Names.has(src)) group1Names.add(dst);
else if (group2Names.has(src)) group2Names.add(dst);
allDecoders.add(dst);
}
},
});
// 多轮别名链传播
let prevSize;
do {
prevSize = allDecoders.size;
traverse(ast, {
noScope: true,
VariableDeclarator(path) {
if (
t.isIdentifier(path.node.id) &&
t.isIdentifier(path.node.init) &&
allDecoders.has(path.node.init.name) &&
!allDecoders.has(path.node.id.name)
) {
const s = path.node.init.name;
const d = path.node.id.name;
if (group1Names.has(s)) group1Names.add(d);
else if (group2Names.has(s)) group2Names.add(d);
allDecoders.add(d);
}
},
AssignmentExpression(path) {
if (
t.isIdentifier(path.node.left) &&
t.isIdentifier(path.node.right) &&
allDecoders.has(path.node.right.name) &&
!allDecoders.has(path.node.left.name)
) {
const s = path.node.right.name;
const d = path.node.left.name;
if (group1Names.has(s)) group1Names.add(d);
else if (group2Names.has(s)) group2Names.add(d);
allDecoders.add(d);
}
},
});
} while (allDecoders.size > prevSize);
console.log(`[+] 解码器1别名 (${group1Names.size}): ${[...group1Names].join(", ")}`);
console.log(`[+] 解码器2别名 (${group2Names.size}): ${[...group2Names].join(", ")}`);
// ═══════════════════════════════════════════
// Phase 4: Pass 2 — 常量传播 + 解码替换
// ═══════════════════════════════════════════
console.log("[*] Phase 4: 常量传播 + 字符串解码...");
let resolvedCount = 0;
let constPropCount = 0;
function resolveNumericValue(node, scopePath) {
if (t.isNumericLiteral(node)) return node.value;
if (t.isUnaryExpression(node) && node.operator === "-" && t.isNumericLiteral(node.argument)) {
return -node.argument.value;
}
if (t.isIdentifier(node)) {
const binding = scopePath.scope.getBinding(node.name);
if (binding && binding.constant && binding.path.isVariableDeclarator()) {
const init = binding.path.node.init;
if (t.isNumericLiteral(init)) return init.value;
}
// 非 constant binding 但 init 是数字且只赋值一次
if (binding && binding.path.isVariableDeclarator()) {
const init = binding.path.node.init;
if (t.isNumericLiteral(init) && !binding.constantViolations.length) {
return init.value;
}
}
}
return null;
}
traverse(ast, {
CallExpression(path) {
const callee = path.node.callee;
if (
t.isIdentifier(callee) &&
allDecoders.has(callee.name) &&
path.node.arguments.length >= 1
) {
const arg = path.node.arguments[0];
const numVal = resolveNumericValue(arg, path);
if (numVal === null) return;
const map = getMapForDecoder(callee.name);
if (!map) return;
if (map.has(numVal)) {
path.replaceWith(t.stringLiteral(map.get(numVal)));
resolvedCount++;
if (!t.isNumericLiteral(arg)) constPropCount++;
}
}
},
});
console.log(`[+] 解码替换: ${resolvedCount} (常量传播: ${constPropCount})`);
// ═══════════════════════════════════════════
// Phase 5: Pass 3 — 属性简化
// ═══════════════════════════════════════════
console.log("[*] Phase 5: 属性访问简化...");
let memberCount = 0;
const RESERVED = new Set([
"break","case","catch","continue","debugger","default","delete","do",
"else","finally","for","function","if","in","instanceof","new","return",
"switch","this","throw","try","typeof","var","void","while","with",
"class","const","enum","export","extends","import","super","implements",
"interface","let","package","private","protected","public","static","yield",
]);
traverse(ast, {
MemberExpression(path) {
if (
path.node.computed &&
t.isStringLiteral(path.node.property) &&
/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(path.node.property.value) &&
!RESERVED.has(path.node.property.value)
) {
path.node.computed = false;
path.node.property = t.identifier(path.node.property.value);
memberCount++;
}
},
});
console.log(`[+] 属性简化: ${memberCount}`);
// ═══════════════════════════════════════════
// Phase 6: Pass 4 — 字符串拼接折叠
// ═══════════════════════════════════════════
console.log("[*] Phase 6: 字符串拼接折叠...");
let concatCount = 0;
let round;
do {
round = 0;
traverse(ast, {
CallExpression(path) {
if (
t.isMemberExpression(path.node.callee) &&
!path.node.callee.computed &&
t.isIdentifier(path.node.callee.property, { name: "concat" }) &&
t.isStringLiteral(path.node.callee.object) &&
path.node.arguments.length === 1 &&
t.isStringLiteral(path.node.arguments[0])
) {
path.replaceWith(
t.stringLiteral(
path.node.callee.object.value + path.node.arguments[0].value
)
);
round++;
}
},
});
concatCount += round;
} while (round > 0);
console.log(`[+] 拼接折叠: ${concatCount}`);
// ═══════════════════════════════════════════
// Phase 7: Pass 5 — 常量折叠 (typeof, 简单比较)
// ═══════════════════════════════════════════
console.log("[*] Phase 7: 常量表达式折叠...");
let constFoldCount = 0;
traverse(ast, {
// "string" == typeof x → 保留 (运行时), 但 typeof "xxx" → "string"
UnaryExpression(path) {
if (path.node.operator === "typeof" && t.isStringLiteral(path.node.argument)) {
path.replaceWith(t.stringLiteral("string"));
constFoldCount++;
}
},
// void 0 → undefined (可选, 增加可读性)
// 暂时不做, 可能影响语义
});
console.log(`[+] 常量折叠: ${constFoldCount}`);
// ═══════════════════════════════════════════
// Phase 8: Pass 6 — 清理无用别名声明
// ═══════════════════════════════════════════
console.log("[*] Phase 8: 清理无用别名...");
let deadCount = 0;
traverse(ast, {
VariableDeclarator(path) {
if (
t.isIdentifier(path.node.id) &&
t.isIdentifier(path.node.init) &&
allDecoders.has(path.node.init.name) &&
allDecoders.has(path.node.id.name)
) {
const binding = path.scope.getBinding(path.node.id.name);
if (binding && binding.references === 0) {
path.remove();
deadCount++;
}
}
},
});
console.log(`[+] 清理: ${deadCount}`);
// ═══════════════════════════════════════════
// Phase 9: 生成输出
// ═══════════════════════════════════════════
console.log("[*] Phase 9: 生成代码...");
const output = generate(ast, {
comments: true,
compact: false,
retainLines: false,
concise: false,
}).code;
fs.writeFileSync(OUT, output, "utf-8");
const origKB = (fs.statSync(SRC).size / 1024).toFixed(1);
const newKB = (Buffer.byteLength(output) / 1024).toFixed(1);
console.log(`\n${"═".repeat(50)}`);
console.log(`[=] 解混淆完成`);
console.log(` 原始: ${origKB} KB`);
console.log(` 输出: ${newKB} KB`);
console.log(` 解码替换: ${resolvedCount} (常量传播 ${constPropCount})`);
console.log(` 属性简化: ${memberCount}`);
console.log(` 拼接折叠: ${concatCount}`);
console.log(` 常量折叠: ${constFoldCount}`);
console.log(` 死代码清理: ${deadCount}`);
console.log(` PW/QQ 别名: ${group1Names.size} | Qg 别名: ${group2Names.size}`);
console.log(` 输出: ${OUT}`);
console.log(`${"═".repeat(50)}`);
// 导出映射表
const mapOut = path.join(__dirname, "hsw.string-map.json");
const mapObj = { "decoder1_PW_QQ": {}, "decoder2_Qg": {} };
for (const [k, v] of map1) mapObj.decoder1_PW_QQ[k] = v;
for (const [k, v] of map2) mapObj.decoder2_Qg[k] = v;
fs.writeFileSync(mapOut, JSON.stringify(mapObj, null, 2), "utf-8");
console.log(` 映射: ${mapOut}`);

19969
asset/hcaptcha.html Normal file

File diff suppressed because one or more lines are too long

4711
asset/hsw.deobfuscated.js Normal file

File diff suppressed because one or more lines are too long

9102
asset/hsw.js Normal file

File diff suppressed because one or more lines are too long

734
asset/hsw.string-map.json Normal file

File diff suppressed because one or more lines are too long

218
asset/package-lock.json generated Normal file
View File

@@ -0,0 +1,218 @@
{
"name": "asset",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "asset",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@babel/generator": "^7.29.1",
"@babel/parser": "^7.29.0",
"@babel/traverse": "^7.29.0",
"@babel/types": "^7.29.0"
}
},
"node_modules/@babel/code-frame": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/generator": {
"version": "7.29.1",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
"license": "MIT",
"dependencies": {
"@babel/parser": "^7.29.0",
"@babel/types": "^7.29.0",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-globals": {
"version": "7.28.0",
"resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
"integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
"integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
"integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
"integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
"license": "MIT",
"dependencies": {
"@babel/types": "^7.29.0"
},
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/template": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.28.6",
"@babel/parser": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/types": "^7.29.0",
"debug": "^4.3.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/types": {
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.0",
"@jridgewell/trace-mapping": "^0.3.24"
}
},
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.31",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/debug": {
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"license": "MIT"
},
"node_modules/jsesc": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
"integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
"license": "MIT",
"bin": {
"jsesc": "bin/jsesc"
},
"engines": {
"node": ">=6"
}
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"license": "ISC"
}
}
}

19
asset/package.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "asset",
"version": "1.0.0",
"description": "",
"main": "challenge.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"@babel/generator": "^7.29.1",
"@babel/parser": "^7.29.0",
"@babel/traverse": "^7.29.0",
"@babel/types": "^7.29.0"
}
}

86
asset/wasm.js Normal file

File diff suppressed because one or more lines are too long