mihomo-cli 2.2.1 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/index.js +18 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.2.2] - 2026-05-01
|
|
4
|
+
|
|
5
|
+
### 修复
|
|
6
|
+
|
|
7
|
+
- **文件描述符泄漏**:修复 `startMixedMode` 中 spawn 后未关闭 fd 的问题
|
|
8
|
+
- **forceSudo 参数失效**:修复 `cleanupAll` 忽略调用方传入的强制 sudo 参数
|
|
9
|
+
- **formatBytes 溢出**:修复超大字节值(>1PB)导致显示 `undefined` 单位
|
|
10
|
+
- **YAML 解析类型检查**:`parseYamlOrJson` 现在拒绝非对象类型的 YAML 内容
|
|
11
|
+
- **spawn 错误处理**:`openUrl` 添加 error 事件处理,防止未捕获异常
|
|
12
|
+
- **UserInfo 类型转换**:移除 `parseUserInfo` 中多余的 `as unknown` 双重转换
|
|
13
|
+
|
|
14
|
+
### 安全
|
|
15
|
+
|
|
16
|
+
- **订阅名称校验**:新增文件名安全校验,防止路径穿越等不安全名称
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
3
20
|
## [2.2.1] - 2026-05-01
|
|
4
21
|
|
|
5
22
|
### 修复
|
package/dist/index.js
CHANGED
|
@@ -2808,7 +2808,14 @@ function getSubscriptionsWithCache() {
|
|
|
2808
2808
|
...cache[s.name] || {}
|
|
2809
2809
|
}));
|
|
2810
2810
|
}
|
|
2811
|
+
var SAFE_NAME_RE = /^[\w\-\p{Unified_Ideograph}]{1,64}$/u;
|
|
2812
|
+
function validateSubscriptionName(name) {
|
|
2813
|
+
if (!name || !SAFE_NAME_RE.test(name)) {
|
|
2814
|
+
throw new Error(`\u8BA2\u9605\u540D\u79F0\u65E0\u6548: "${name}"\uFF0C\u53EA\u5141\u8BB8\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u3001\u77ED\u6A2A\u7EBF\u548C\u4E2D\u6587\uFF08\u6700\u957F 64 \u5B57\u7B26\uFF09`);
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2811
2817
|
function addSubscription(url, name = "default") {
|
|
2818
|
+
validateSubscriptionName(name);
|
|
2812
2819
|
const settings = readSettings();
|
|
2813
2820
|
const subs = settings.subscriptions || [];
|
|
2814
2821
|
const existingIndex = subs.findIndex((s) => s.name === name);
|
|
@@ -3006,7 +3013,7 @@ function parseYamlOrJson(content, errorMsg) {
|
|
|
3006
3013
|
}
|
|
3007
3014
|
try {
|
|
3008
3015
|
const result = jsYaml.load(content);
|
|
3009
|
-
if (result
|
|
3016
|
+
if (result != null && typeof result === "object" && !Array.isArray(result)) return result;
|
|
3010
3017
|
} catch {
|
|
3011
3018
|
}
|
|
3012
3019
|
try {
|
|
@@ -3160,7 +3167,7 @@ function formatBytes(bytes) {
|
|
|
3160
3167
|
if (num === 0) return "0 B";
|
|
3161
3168
|
const k = 1024;
|
|
3162
3169
|
const sizes = ["B", "KB", "MB", "GB", "TB"];
|
|
3163
|
-
const i = Math.floor(Math.log(num) / Math.log(k));
|
|
3170
|
+
const i = Math.min(Math.floor(Math.log(num) / Math.log(k)), sizes.length - 1);
|
|
3164
3171
|
return `${parseFloat((num / k ** i).toFixed(2))} ${sizes[i]}`;
|
|
3165
3172
|
}
|
|
3166
3173
|
function formatTimestamp(ts) {
|
|
@@ -3405,14 +3412,14 @@ function killAllMihomo(forceSudo = false) {
|
|
|
3405
3412
|
}
|
|
3406
3413
|
}
|
|
3407
3414
|
}
|
|
3408
|
-
function cleanupAll(
|
|
3415
|
+
function cleanupAll(forceSudo = false) {
|
|
3409
3416
|
const pids = getAllMihomoPids();
|
|
3410
3417
|
if (pids.length === 0) {
|
|
3411
3418
|
clearPid();
|
|
3412
3419
|
return { killed: 0, failed: 0, remaining: [] };
|
|
3413
3420
|
}
|
|
3414
3421
|
const hasRootProcess = pids.some((p) => isProcessRoot(p));
|
|
3415
|
-
const needsSudo = hasRootProcess;
|
|
3422
|
+
const needsSudo = forceSudo || hasRootProcess;
|
|
3416
3423
|
let killedCount = 0;
|
|
3417
3424
|
const failedPids = [];
|
|
3418
3425
|
if (needsSudo) {
|
|
@@ -3560,12 +3567,12 @@ async function startMixedMode(staleState) {
|
|
|
3560
3567
|
const configFile = PATHS.configFile;
|
|
3561
3568
|
const logFile = PATHS.logFile;
|
|
3562
3569
|
const args = ["-d", DIRS.data, "-f", configFile];
|
|
3563
|
-
const
|
|
3564
|
-
const err = fs5.openSync(logFile, "a");
|
|
3570
|
+
const logFd = fs5.openSync(logFile, "a");
|
|
3565
3571
|
const child = spawn(PATHS.mihomoBinary, args, {
|
|
3566
3572
|
detached: true,
|
|
3567
|
-
stdio: ["ignore",
|
|
3573
|
+
stdio: ["ignore", logFd, logFd]
|
|
3568
3574
|
});
|
|
3575
|
+
fs5.closeSync(logFd);
|
|
3569
3576
|
child.unref();
|
|
3570
3577
|
const pid = child.pid;
|
|
3571
3578
|
savePid(pid);
|
|
@@ -3735,7 +3742,10 @@ function getLogPathByName(name) {
|
|
|
3735
3742
|
}
|
|
3736
3743
|
function openUrl(url) {
|
|
3737
3744
|
try {
|
|
3738
|
-
spawn("open", [url], { stdio: "ignore", detached: true });
|
|
3745
|
+
const child = spawn("open", [url], { stdio: "ignore", detached: true });
|
|
3746
|
+
child.unref();
|
|
3747
|
+
child.on("error", () => {
|
|
3748
|
+
});
|
|
3739
3749
|
return true;
|
|
3740
3750
|
} catch {
|
|
3741
3751
|
return false;
|