reverse-skills-max: initial public release (restored, redacted, hardened)

This commit is contained in:
baradok609hecl1pq6qi
2026-10-20 02:17:15 +03:00
commit da24c2bd20
2227 changed files with 443931 additions and 0 deletions

View File

@@ -0,0 +1,362 @@
#!/usr/bin/env node
'use strict';
const fs = require('fs');
const path = require('path');
function parseArgs(argv) {
const args = { caseDir: '', target: '', entry: '', param: '', api: '', force: false, json: false };
for (let i = 2; i < argv.length; i++) {
const a = argv[i];
if (a === '--case-dir' || a === '--dir' || a === '-d') args.caseDir = argv[++i] || '';
else if (a === '--target') args.target = argv[++i] || '';
else if (a === '--entry') args.entry = argv[++i] || '';
else if (a === '--param') args.param = argv[++i] || '';
else if (a === '--api') args.api = argv[++i] || '';
else if (a === '--force') args.force = true;
else if (a === '--json') args.json = true;
else if (a === '--help' || a === '-h') args.help = true;
else throw new Error(`未知参数:${a}`);
}
return args;
}
function usage() {
return `用法:
node scripts/init_env_case.js --case-dir case --target app.js --entry window.makeSign --param sign --api https://example.com/api/search
说明:已有文件默认不覆盖;如需覆盖模板文件,请显式添加 --force。`;
}
function isDangerousDir(p) {
const resolved = path.resolve(p);
const root = path.parse(resolved).root;
return resolved === root || resolved.length <= root.length + 2;
}
function ensureDir(p, actions) {
if (!fs.existsSync(p)) {
fs.mkdirSync(p, { recursive: true });
actions.push({ action: 'create-dir', path: p });
} else {
actions.push({ action: 'keep-dir', path: p });
}
}
function writeFileIfNeeded(p, content, force, actions) {
if (fs.existsSync(p) && !force) {
actions.push({ action: 'keep-file', path: p });
return;
}
fs.mkdirSync(path.dirname(p), { recursive: true });
const existed = fs.existsSync(p);
fs.writeFileSync(p, content, 'utf8');
actions.push({ action: existed ? 'write-file' : 'create-file', path: p });
}
function initCase(args) {
if (!args.caseDir) throw new Error('必须提供 --case-dir');
const caseDir = path.resolve(args.caseDir);
if (isDangerousDir(caseDir)) throw new Error(`拒绝在危险目录中初始化:${caseDir}`);
const actions = [];
const dirs = ['js/original', 'js/pretty', 'js/extracted', 'requests', 'fixtures', 'notes', 'hooks', 'env', 'ruyi-trace/logs', 'browser/ruyipage', 'result', 'tmp'];
ensureDir(caseDir, actions);
for (const d of dirs) ensureDir(path.join(caseDir, d), actions);
const fixture = {
name: 'sample-001',
pageUrl: '',
apiUrl: args.api || '',
method: '',
param: args.param || '',
paramLocation: '',
browser: {
userAgent: '',
language: 'zh-CN',
timezone: 'Asia/Shanghai',
screen: { width: 1920, height: 1080 },
},
request: { query: {}, headers: {}, body: {}, cookies: {}, localStorage: {}, sessionStorage: {} },
runtime: { now: null, performanceNow: null, randomBytes: [] },
fingerprint: {
source: { mode: '', pageUrl: '', userAgent: '', timezone: '', locale: '', capturedAt: '' },
canvas: { toDataURL: [], toBlob: [], measureText: [], getImageData: [] },
webgl: { getParameter: [], getSupportedExtensions: null, getExtension: [], getShaderPrecisionFormat: [], readPixels: [] },
webgpu: { requestAdapter: [] },
audio: { startRendering: [], getChannelData: [] },
domGeometry: { getBoundingClientRect: [], getClientRects: [], offset: [] },
},
entry: args.entry || '',
args: [],
expected: args.param ? { [args.param]: '' } : {},
};
writeFileIfNeeded(path.join(caseDir, 'fixtures', 'sample.fixture.json'), JSON.stringify(fixture, null, 2) + '\n', args.force, actions);
const fingerprintFixture = {
version: 1,
source: { mode: '', pageUrl: '', userAgent: '', timezone: '', locale: '', capturedAt: '' },
canvas: { toDataURL: [], toBlob: [], measureText: [], getImageData: [] },
webgl: { getParameter: [], getSupportedExtensions: null, getExtension: [], getShaderPrecisionFormat: [], readPixels: [] },
webgpu: { requestAdapter: [] },
audio: { startRendering: [], getChannelData: [] },
domGeometry: { getBoundingClientRect: [], getClientRects: [], offset: [] },
};
writeFileIfNeeded(path.join(caseDir, 'fixtures', 'fingerprint.fixture.json'), JSON.stringify(fingerprintFixture, null, 2) + '\n', args.force, actions);
const notes = `# Node.js 补环境任务笔记
## 基本信息
- 目标 API:${args.api || ''}
- 目标 JS:${args.target || ''}
- 入口函数:${args.entry || ''}
- 目标参数:${args.param || ''}
## 前置材料检查
- [ ] 请求样本已确认
- [ ] 已列出请求样本中的全部可疑加密参数
- [ ] 用户已确认本次要分析哪些加密参数
- [ ] 加密参数已在请求中确认
- [ ] 已输出 source / entry / builder / writer 四层链路
- [ ] 目标 JS 文件已保存
- [ ] 加密入口已定位
- [ ] 浏览器取证模式已由用户选择:ruyiPage + RuyiTrace / ruyiPage / CloakBrowser / 手动取证 / AI 自行决定
- [ ] 如选择 RuyiTrace,NDJSON 日志已导入或确认不需要
- [ ] Node 泄露阻断已检查
- [ ] 补环境初始化阶段已加载 / 检测 addon,并记录可用性、导出 API 或降级原因
- [ ] 默认启用 addon-first;如用户明确要求不使用 addon,已记录豁免原因
- [ ] 默认启用 toString / 属性描述符 / 原型链 / 访问器 / 实例对象保护;如用户明确要求关闭,已记录原因
- [ ] 已读取 code-style.md,并先规划 result 目录、文件职责和调用关系
- [ ] 补环境代码默认要求简洁、模块化、具名函数清晰,并写入中文注释
- [ ] 中文注释使用 UTF-8 正常显示,没有问号、连续问号或乱码
- [ ] 已创建 / 读取 notes/代码变更记忆.md;修改关键源码前已搜索历史记录,修改后已记录失败尝试、禁止回退、验证范围和遗留风险
- [ ] 六项纯计算预检已执行或明确不需要
- [ ] 如目标访问 Canvas / WebGL / WebGPU / Audio / 字体 / DOM 几何指纹,已采集真实浏览器终端 API 返回值并写入 fixtures/fingerprint.fixture.json
- [ ] 用户已确认进入补环境阶段
## 缺失环境追踪
- trace 文件:tmp/env-trace.jsonl
- 缺失环境摘要:tmp/missing-env.json
- trace 分析:notes/missing-env-priority.md
## 可疑加密参数确认
| 参数名 | 位置 | 样本值摘要 | 疑似原因 | 用户是否确认分析 |
|---|---|---|---|---|
> cURL / HAR 中已有的加密参数值只能作为 fixture expected,最终产物必须通过补环境重新生成,不能直接复用。
## 补齐记录
| 轮次 | 缺失环境 | 处理方式 | 验证结果 |
|---|---|---|---|
## 通用代码变更记忆
- 记录文件:notes/代码变更记忆.md
- [ ] 修改关键源码前已读取该文件
- [ ] 修改关键源码后已追加本轮变更记录
- [ ] 已记录修改前逻辑、问题证据、本次修改、修改理由、已失败尝试、禁止回退、验证命令、验证结果、当前验证范围、遗留风险和当前状态
- [ ] 已运行 scripts/check_change_memory.js --case-dir case --markdown
## 代码质量
- [ ] 已运行 scripts/check_code_quality.js --case-dir case --markdown
- [ ] 已修复超长行、超长函数、压缩堆叠代码和过深嵌套
- [ ] 已确认每个手写源码文件顶部都有中文职责注释
- [ ] 已确认关键 WebAPI、getter / setter、addon-first、fallback、指纹回放和加密入口有中文说明
- [ ] 已确认中文注释没有问号、连续问号或乱码
## 指纹值回放
- [ ] 已确认哪些指纹终端 API 被目标 JS 访问
- [ ] 已使用真实浏览器采样值回放,而不是在 Node.js 中真实模拟渲染
- [ ] 未把浏览器自动化代码放入最终 result 目录
- [ ] 缺失指纹样本时已阻塞并提示补采样,没有静默伪造默认值
## 最终请求验证
- [ ] fixtures 已通过
- [ ] 用户已确认是否发起真实请求
- [ ] 如普通客户端疑似 TLS 指纹不一致,已确认是否使用 CycleTLS / curl_cffi / cffi_curl / cyCronet
- [ ] 请求次数、状态码、响应关键字段已记录
- [ ] 临时响应和敏感请求副本已清理
## 最终总结
- [ ] 已从前置阶段开始生成 case/阶段报告/01-需求信息确认.md 等中文命名阶段报告
- [ ] 项目完成后已默认生成 result/最终项目总结.md
- [ ] 最终总结使用 UTF-8 写入,中文正常显示
- [ ] 总结包含 native addon / NativeProtect 使用情况、加密参数生成与样本复用检查、最终交付结构、测试结果和清理结果
- [ ] 如用户明确要求不生成最终总结,已记录原因
## 清理检查
- [ ] 已删除临时 trace / 日志
- [ ] 已删除失败 runner
- [ ] 已保留必要 fixtures 和 notes
`;
writeFileIfNeeded(path.join(caseDir, 'notes', 'env-task.md'), notes, args.force, actions);
const codeChangeMemory = `# 代码变更记忆
本文件由通用代码变更记忆机制维护,用于记录复杂 case 中关键源码修改的事实、原因、失败尝试、禁止回退、验证范围和遗留风险。不要把“当前报错消失”直接写成永久结论。
## 使用规则
- 修改关键源码前先读取本文件,并搜索文件名、函数名、错误关键词和参数名。
- 修改关键源码后立即追加一条“变更”记录。
- 不删除失败记录;如历史记录被新证据替代,新增记录说明替代原因。
- 状态只能使用:临时修复 / 当前验证通过 / 已失败 / 被替代 / 稳定基线。
## 变更 001 - 待填写
- 时间:YYYY-MM-DD HH:mm
- 涉及文件:
- 涉及函数 / 模块:
- 当前状态:临时修复
### 修改前逻辑
待填写。
### 问题证据
待填写。
### 本次修改
待填写。
### 修改理由
待填写。
### 已失败尝试
待填写。
### 禁止回退
待填写。
### 验证命令
\`\`\`bash
# 待填写
\`\`\`
### 验证结果
待填写。
### 当前验证范围
待填写。
### 遗留风险
待填写。
`;
writeFileIfNeeded(path.join(caseDir, 'notes', '代码变更记忆.md'), codeChangeMemory, args.force, actions);
const entryChain = `# 加密入口链路记录
## writer 最终写入
- 类型:fetch / XHR / URLSearchParams / Header / Cookie / Body
- 文件与行列号:
- 调用栈:
- 写入前对象快照:
- 写入后对象快照:
## builder 请求构造
- 函数 / 方法:
- 所在模块:
- 输入:
- 输出:
- 是否经过拦截器:
## entry 加密入口
- 函数名 / 表达式:${args.entry || ''}
- 文件 / chunk / module id:${args.target || ''}
- 行列号:
- 入参:
- 返回:
- 是否需要初始化:
## source 数据源
- URL / Query:
- Body:
- Cookie:
- localStorage / sessionStorage:
- 时间 / 随机数:
- navigator / screen / document / canvas / WebGL:
- Canvas / WebGL / WebGPU / Audio / 字体 / DOM 几何指纹 fixture:
- 其他:
## 可信度
- 证据来源:
- 是否可进入补环境:否
- 阻塞点:
`;
writeFileIfNeeded(path.join(caseDir, 'notes', 'entry-chain.md'), entryChain, args.force, actions);
const silentChecklist = `# 静默失败排查清单
当目标 JS 不报错但 ${args.param || '目标参数'} 不一致时逐项检查。
- [ ] 请求 URL、Query、Body、Header 与浏览器样本一致
- [ ] SDK 初始化参数、版本、appId、页面配置一致
- [ ] Cookie、localStorage、sessionStorage 已按 fixture 注入
- [ ] Date.now / new Date / performance.now 可复现
- [ ] Math.random / crypto.getRandomValues 可复现
- [ ] Canvas / WebGL / WebGPU / Audio / 字体 / DOM 几何等指纹终端 API 返回值来自真实浏览器采样并可回放
- [ ] navigator / screen / timezone / language 与浏览器样本一致
- [ ] JS 加载顺序、runtime chunk、动态 chunk 完整
- [ ] Function.prototype.toString / Object.prototype.toString 已处理
- [ ] 属性描述符与原型链已记录
- [ ] document.all 等特殊对象已处理或确认未触发
- [ ] Worker / WASM / postMessage 已排查
`;
writeFileIfNeeded(path.join(caseDir, 'notes', 'silent-failure-checklist.md'), silentChecklist, args.force, actions);
const trustMatrix = `# 证据可信度矩阵
| 项目 | 当前值 / 结论 | 来源 | 等级 A/B/C/D | 待验证 |
|---|---|---|---|---|
| 目标 API | ${args.api || ''} | 用户输入 | B | |
| 目标参数 | ${args.param || ''} | 用户输入 | B | |
| 加密入口 | ${args.entry || ''} | 用户输入 / 待验证 | C | |
| JS 文件 | ${args.target || ''} | 用户输入 / 待验证 | C | |
| Cookie / token | 仅记录键名和脱敏摘要 | fixture | A/B | |
`;
writeFileIfNeeded(path.join(caseDir, 'notes', 'trust-matrix.md'), trustMatrix, args.force, actions);
return { caseDir, actions };
}
function render(result) {
const label = { 'create-dir': '创建目录', 'keep-dir': '保留目录', 'create-file': '创建文件', 'write-file': '写入文件', 'keep-file': '保留已有文件' };
const lines = ['# 补环境 case 初始化结果', '', `- case 目录:${result.caseDir}`];
for (const a of result.actions) lines.push(`- ${label[a.action] || a.action}:${a.path}`);
return lines.join('\n') + '\n';
}
try {
const args = parseArgs(process.argv);
if (args.help) { console.log(usage()); process.exit(0); }
const result = initCase(args);
if (args.json) console.log(JSON.stringify(result, null, 2));
else process.stdout.write(render(result));
} catch (err) {
console.error(err.message || String(err));
console.error(usage());
process.exit(1);
}