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,165 @@
#!/usr/bin/env node
'use strict';
const { spawnSync } = require('child_process');
function parseArgs(argv) {
const args = { python: '', json: false, markdown: false };
for (let i = 2; i < argv.length; i++) {
const a = argv[i];
if (a === '--python') args.python = argv[++i] || '';
else if (a === '--json') args.json = true;
else if (a === '--markdown') args.markdown = true;
else if (a === '--help' || a === '-h') args.help = true;
else throw new Error(`未知参数:${a}`);
}
if (!args.json && !args.markdown) args.markdown = true;
return args;
}
function usage() {
return `用法:
node scripts/check_tls_clients.js --markdown
node scripts/check_tls_clients.js --python python --json
说明:检测最终请求阶段可选的 TLS 指纹兼容客户端:Node.js CycleTLS / impers / curl-cffi-node、Python curl_cffi / cffi_curl / cyCronet;真实请求交付时必须再封装为 Session 模式。`;
}
function run(cmd, args, timeout = 12000) {
const ret = spawnSync(cmd, args, { encoding: 'utf8', timeout, windowsHide: true });
return {
ok: ret.status === 0,
status: ret.status,
stdout: (ret.stdout || '').trim(),
stderr: (ret.stderr || '').trim(),
error: ret.error ? ret.error.message : '',
command: [cmd].concat(args).join(' '),
};
}
function nodeRequire(name) {
const code = `
(async()=>{
const name=${JSON.stringify(name)};
try {
const m=require(name);
console.log(JSON.stringify({ok:true, loader:"require", keys:Object.keys(m).slice(0,20)}));
} catch (e1) {
try {
const m=await import(name);
console.log(JSON.stringify({ok:true, loader:"import", keys:Object.keys(m).slice(0,20)}));
} catch (e2) {
console.log(JSON.stringify({ok:false,error:e1.message + " / " + e2.message}));
process.exit(2);
}
}
})();`;
const ret = run(process.execPath, ['-e', code]);
try {
const parsed = JSON.parse(ret.stdout.replace(/^\uFEFF/, ''));
return { name, installed: !!parsed.ok, loader: parsed.loader || '', keys: parsed.keys || [], error: parsed.error || '' };
} catch {
return { name, installed: false, loader: '', keys: [], error: ret.stderr || ret.error || '检测失败' };
}
}
function pythonCandidates(explicit) {
const out = [];
if (explicit) out.push({ cmd: explicit, prefix: [] });
out.push({ cmd: 'python', prefix: [] });
out.push({ cmd: 'python3', prefix: [] });
out.push({ cmd: 'py', prefix: ['-3'] });
const seen = new Set();
return out.filter(x => {
const k = x.cmd + ' ' + x.prefix.join(' ');
if (seen.has(k)) return false;
seen.add(k);
return true;
});
}
function detectPythonModules(explicitPython) {
const modules = ['curl_cffi', 'cffi_curl', 'cycronet', 'cyCronet'];
const code = [
'import importlib, json',
`mods=${JSON.stringify(modules)}`,
'out={}',
'for name in mods:',
' try:',
' m=importlib.import_module(name)',
' out[name]={"installed": True, "version": getattr(m, "__version__", "")}',
' except Exception as e:',
' out[name]={"installed": False, "error": str(e)}',
'print(json.dumps(out, ensure_ascii=False))',
].join('\n');
for (const c of pythonCandidates(explicitPython)) {
const ret = run(c.cmd, c.prefix.concat(['-c', code]));
if (!ret.ok && !ret.stdout) continue;
try {
const parsed = JSON.parse(ret.stdout.replace(/^\uFEFF/, ''));
return { python: c.cmd, pythonArgsPrefix: c.prefix, modules: parsed };
} catch {}
}
return {
python: '',
pythonArgsPrefix: [],
modules: Object.fromEntries(modules.map(m => [m, { installed: false, error: '未找到可用 Python 或检测失败' }])),
};
}
function detect(args) {
const nodePackages = ['cycletls', '@luminati-io/cycletls', 'cycle-tls', 'cycleTls', 'impers', 'curl-cffi', 'curl-cffi-node'].map(nodeRequire);
const python = detectPythonModules(args.python);
const cycleTlsAvailable = nodePackages.some(p => p.installed && /cycle/i.test(p.name));
const impersAvailable = nodePackages.some(p => p.installed && p.name === 'impers');
const curlCffiNodeAvailable = nodePackages.some(p => p.installed && p.name === 'curl-cffi');
return {
node: {
executable: process.execPath,
packages: nodePackages,
cycleTlsAvailable,
impersAvailable,
curlCffiNodeAvailable,
nodeTlsAvailable: cycleTlsAvailable || impersAvailable || curlCffiNodeAvailable,
},
python,
pythonTlsAvailable: Object.values(python.modules).some(v => v && v.installed),
note: '这些客户端只用于授权范围内的最终低频请求验证;如果本 case 需要最终发送真实请求,应在前置阶段先选择 Node.js CycleTLS/impers/curl-cffi-node 或 Python curl_cffi/cyCronet,并在最终项目中封装为 Session 模式,不要等普通客户端失败后才考虑。',
};
}
function renderMarkdown(result) {
const lines = ['# TLS 指纹兼容客户端检测结果', '', `说明:${result.note}`, '', '## Node.js / CycleTLS / impers'];
lines.push(`- Node.js:${result.node.executable}`);
lines.push(`- 是否检测到 CycleTLS:${result.node.cycleTlsAvailable ? '是' : '否'}`);
lines.push(`- 是否检测到 impers:${result.node.impersAvailable ? '是' : '否'}`);
lines.push(`- 是否检测到 Node.js TLS 指纹兼容客户端:${result.node.nodeTlsAvailable ? '是' : '否'}`);
for (const p of result.node.packages) {
lines.push(`- ${p.name}:${p.installed ? '已安装' : '未安装'}${p.loader ? `(${p.loader})` : ''}${p.error ? `(${p.error})` : ''}`);
}
lines.push('', '## Python / curl_cffi / cffi_curl / cyCronet');
lines.push(`- Python:${result.python.python ? `${result.python.python} ${result.python.pythonArgsPrefix.join(' ')}`.trim() : '未检测到'}`);
lines.push(`- 是否检测到 Python TLS 客户端:${result.pythonTlsAvailable ? '是' : '否'}`);
for (const [name, info] of Object.entries(result.python.modules)) {
lines.push(`- ${name}:${info.installed ? '已安装' : '未安装'}${info.version ? `(版本 ${info.version})` : ''}${info.error && !info.installed ? `(${info.error})` : ''}`);
}
lines.push('', '## 下一步');
if (!result.node.nodeTlsAvailable && !result.pythonTlsAvailable) {
lines.push('- 未检测到可用 TLS 指纹兼容客户端;如果本 case 需要最终发送真实请求,需在前置阶段询问用户安装 CycleTLS / impers / curl_cffi / cyCronet,或改为只输出本地 sign 结果。');
} else {
lines.push('- 在任务确认阶段选择一个最终请求客户端,并限制为少量授权验证请求;最终项目中只保留所选客户端的 Session 请求逻辑。');
}
return lines.join('\n') + '\n';
}
try {
const args = parseArgs(process.argv);
if (args.help) { console.log(usage()); process.exit(0); }
const result = detect(args);
if (args.json) console.log(JSON.stringify(result, null, 2));
if (args.markdown) process.stdout.write(renderMarkdown(result));
} catch (err) {
console.error(err.message || String(err));
console.error(usage());
process.exit(1);
}