- 回滚/备份:空 bak 改名 .bad 跳过;升级刷新 bak 补上单数 marker 补丁;统一原子写 - 补丁命中:optional 命中不符记软失败;#42 插入型替换加探针防重复插入 - Windows:进程枚举改用 | 分隔 + UTF-8,修复中文路径换包不杀旧进程;换包失败拉起原版 - 安全:asar 解包防越界;红队路径校验 realpath 防空 symlink;更新仅 https;报告回放去换行注入 - 提示词钩子:停用后 rewriteFn 返回原装配文本并清理 assemble guard;缓存签名纳入红队/策略/override - 红队:listEngagements 默认不算统计;listVulns/报告支持 evidenceLimit - 子代理名额占位即时生效并回退;--apply 有失败项退出码 1 - 清理:删除 lib/mnemon-settings.js 及 13 处死代码/未使用 import;移除 test 目录与 test 脚本
81 lines
1.9 KiB
JavaScript
81 lines
1.9 KiB
JavaScript
import fs from "node:fs";
|
|
import net from "node:net";
|
|
import { spawn } from "node:child_process";
|
|
|
|
const encoded = process.env.DSH_PURGE_RESTART;
|
|
if (!encoded) process.exit(1);
|
|
|
|
let info;
|
|
try {
|
|
info = JSON.parse(encoded);
|
|
} catch {
|
|
process.exit(1);
|
|
}
|
|
|
|
const port = Number(info.port) || 3080;
|
|
const host = typeof info.host === "string" && info.host ? info.host : "127.0.0.1";
|
|
const cleanup = Array.isArray(info.cleanup) ? info.cleanup : [];
|
|
|
|
function spawnEnv() {
|
|
const env = { ...process.env };
|
|
delete env.DSH_PERMISSION_MODE;
|
|
delete env.DSH_PURGE_RESTART;
|
|
return env;
|
|
}
|
|
|
|
function portFree() {
|
|
return new Promise((resolve) => {
|
|
const socket = net.createConnection({ host, port }, () => {
|
|
socket.destroy();
|
|
resolve(false);
|
|
});
|
|
socket.on("error", () => resolve(true));
|
|
});
|
|
}
|
|
|
|
async function waitFree() {
|
|
for (let i = 0; i < 80; i++) {
|
|
if (await portFree()) return true;
|
|
await new Promise((r) => setTimeout(r, 120));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function rmTree(dir) {
|
|
if (!dir) return;
|
|
try {
|
|
fs.rmSync(dir, { recursive: true, force: true, maxRetries: 8, retryDelay: 120 });
|
|
} catch {
|
|
// 锁着就留下
|
|
}
|
|
}
|
|
|
|
const ok = await waitFree();
|
|
/* 端口等不到也要清理:以前直接退出,插件的目录和文件就永远留在那里,
|
|
用户以为卸载成功,重启后插件还在。删不掉的会被 rmTree 吞掉,下一步照常。 */
|
|
for (const dir of cleanup) rmTree(dir);
|
|
if (info.helper) {
|
|
try {
|
|
fs.unlinkSync(info.helper);
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
/* 端口没释放就不拉起新进程(会立刻撞端口),但上面的清理已经做完了。 */
|
|
if (!ok) process.exit(1);
|
|
|
|
const child = spawn(info.execPath, info.argv, {
|
|
detached: true,
|
|
stdio: "ignore",
|
|
cwd: info.cwd || process.cwd(),
|
|
env: spawnEnv(),
|
|
windowsHide: true,
|
|
shell: false,
|
|
});
|
|
|
|
child.on("error", () => process.exit(1));
|
|
child.unref();
|
|
await new Promise((r) => setTimeout(r, 400));
|
|
process.exit(0);
|