bookworm-smart-assistant/scripts/patches/patch-sanitize-v6-fix-replace.js

106 lines
4.0 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* patch-sanitize-v6-fix-replace.js
*
* 修复 sanitize v6.0 kv/json/cli/token 处理中
* 错误把 String.replace N 个非字符串参数 (offset:number, namedGroups:object)
* 当作 token 导致 token.slice is not a function bug
*
* 修复方法: 过滤 args 仅保留 typeof === 'string' 且非空
*
* 协议: patches/ + sentinel + 原子写
*/
'use strict';
const fs = require('fs');
const path = require('path');
const TARGET = path.join(__dirname, '..', 'sanitize.js');
const SENTINEL_OLD = 'SANITIZE-V6-17PATTERNS';
const SENTINEL_NEW = 'SANITIZE-V6-FIX-REPLACE';
function main() {
if (!fs.existsSync(TARGET)) {
process.stderr.write('[ERROR] target not found: ' + TARGET + '\n');
process.exit(1);
}
let src = fs.readFileSync(TARGET, 'utf8');
if (!src.includes(SENTINEL_OLD)) {
process.stderr.write('[ERROR] base v6.0 patch not applied yet. Run patch-sanitize-v6-17patterns.js first.\n');
process.exit(1);
}
if (src.includes(SENTINEL_NEW)) {
process.stdout.write('[SKIP] already patched (fix sentinel found)\n');
process.exit(0);
}
// 替换块: kv/json/cli + jwt/token/bearer/telegram
const OLD_BLOCK =
" } else if (type === 'kv' || type === 'json' || type === 'cli') {\n" +
" // 抓最后一个非空捕获组作为 token\n" +
" result = result.replace(re, function() {\n" +
" const args = Array.from(arguments);\n" +
" const m = args[0];\n" +
" const groups = args.slice(1, -2).filter(Boolean);\n" +
" const token = groups[groups.length - 1] || m;\n" +
" return m.replace(token, maskToken(token));\n" +
" });\n" +
" } else if (type === 'jwt' || type === 'token' || type === 'bearer' || type === 'telegram') {\n" +
" result = result.replace(re, function(m, g1) {\n" +
" const token = g1 || m;\n" +
" return m.replace(token, maskToken(token));\n" +
" });\n" +
" }";
const NEW_BLOCK =
" } else if (type === 'kv' || type === 'json' || type === 'cli') {\n" +
" // " + SENTINEL_NEW + ": 过滤非字符串参数 (offset:number / namedGroups:object)\n" +
" result = result.replace(re, function() {\n" +
" const args = Array.from(arguments);\n" +
" const m = args[0];\n" +
" const strs = args.slice(1).filter(function(a){ return typeof a === 'string' && a.length > 0; });\n" +
" const token = strs[strs.length - 1];\n" +
" if (!token || typeof token !== 'string') return m;\n" +
" return m.split(token).join(maskToken(token));\n" +
" });\n" +
" } else if (type === 'jwt' || type === 'token' || type === 'bearer' || type === 'telegram') {\n" +
" result = result.replace(re, function(m, g1) {\n" +
" var token = (typeof g1 === 'string' && g1.length > 0) ? g1 : m;\n" +
" if (typeof token !== 'string') return m;\n" +
" return m.split(token).join(maskToken(token));\n" +
" });\n" +
" }";
if (!src.includes(OLD_BLOCK)) {
process.stderr.write('[ERROR] expected block not found. v6.0 file structure changed?\n');
process.exit(1);
}
// 备份
const ts = new Date().toISOString().replace(/[:.]/g, '-');
const bakPath = TARGET + '.bak.' + ts;
fs.copyFileSync(TARGET, bakPath);
process.stdout.write('[BACKUP] ' + bakPath + '\n');
const updated = src.replace(OLD_BLOCK, NEW_BLOCK);
// 语法验证: 试 require 临时文件
const tmpPath = TARGET + '.tmp.' + process.pid;
fs.writeFileSync(tmpPath, updated);
try {
delete require.cache[require.resolve(tmpPath)];
require(tmpPath); // 加载验证
fs.renameSync(tmpPath, TARGET);
process.stdout.write('[OK] sanitize.js fix applied (replace bug fixed)\n');
} catch (e) {
fs.unlinkSync(tmpPath);
process.stderr.write('[ERROR] syntax check failed: ' + e.message + '\n');
process.exit(1);
}
}
if (require.main === module) main();