mihomo-cli 3.2.0 → 3.4.0
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 +79 -0
- package/README.md +51 -17
- package/dist/index.js +1522 -1092
- package/package.json +5 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,84 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.4.0] - 2026-08-15
|
|
4
|
+
|
|
5
|
+
### 修复
|
|
6
|
+
|
|
7
|
+
- **配置 `controller_secret` 后测速与热重载失效** - 访问 external-controller 的 HTTP 客户端从不发送 `Authorization`,设置密钥后 `test`/`clean`(走主实例)所有节点返回 401 被判失败,保活的配置热重载也恒 401 回退到 sudo 重启。现测速(主实例)与热重载请求均携带 `Bearer <secret>`;隔离测速实例自身无密钥,不受影响
|
|
8
|
+
- **并行更新订阅时缓存临时文件互相踩踏** - `atomicWriteFileSync` 的临时文件名仅含 pid,同进程 `Promise.all` 并行更新多个订阅时写向同名临时文件,导致内容交错或 `rename` 失败。临时名改为 pid + 进程内自增序号,各写入落到独立临时文件
|
|
9
|
+
|
|
10
|
+
### 安全
|
|
11
|
+
|
|
12
|
+
- **YAML 别名炸弹 DoS 防护(回归修复)** - 解析订阅/覆写/运行时配置的 `yaml.load` 未设别名上限,js-yaml 默认无限制,恶意配置可借指数级别名膨胀耗尽内存/CPU。现统一设 `maxAliases` 上限
|
|
13
|
+
- **序列化对歧义标量加引号** - 配置序列化改用会给 `on`/`off`/`yes`/`no` 等歧义标量加引号的默认 schema。此前裸输出的 `name: on` 虽被 mihomo(go-yaml v3)读作字符串,但流经 PyYAML 等 YAML 1.1 工具会被误解析为布尔,造成静默的配置损坏
|
|
14
|
+
- **内核下载文件名路径穿越防护** - 下载内核时临时路径直接拼接 GitHub API 返回的 asset 名,被篡改的响应/镜像可借 `../` 写出内核目录之外。现用 `basename` 剥离目录成分
|
|
15
|
+
- **`open` 命令 URL 参数注入防护** - 打开订阅页面/日志文件时,服务器可控的 URL(订阅响应头 `web_page_url`)若以 `-` 开头会被 `open` 当作选项。现加 `--` 终止选项解析
|
|
16
|
+
- **测速实例终止前校验进程身份** - 停止隔离测速实例时按 pid 文件裸值 `SIGKILL`,pid 被系统复用后可能误杀无关进程。现杀进程前校验其命令行确属该测速实例
|
|
17
|
+
|
|
18
|
+
### 变更
|
|
19
|
+
|
|
20
|
+
- **覆写 `~proxies` 注入的节点纳入 include-all 排除** - `~key` 就地合并在同名节点不存在时会追加新节点,此前只有 `+proxies`/`proxies+` 注入的节点会从 `include-all` 分组排除,`~proxies` 追加的节点会被重复纳入。现一并排除
|
|
21
|
+
- **依赖升级** - `js-yaml` 5.2.1 → 5.3.0(修复 flow collections 指数解析 DoS)、`esbuild` 经 overrides 提升至 0.28.2(修复 dev server 任意文件读取)、`@types/node` → 26、`@biomejs/biome` → 2.5.8、`lint-staged`/`tsx` 跟随最新;`npm audit` 无告警
|
|
22
|
+
|
|
23
|
+
## [3.3.0] - 2026-08-15
|
|
24
|
+
|
|
25
|
+
### 新增
|
|
26
|
+
|
|
27
|
+
- **覆写按 name 就地 patch 数组元素(`~key` 语法)** - 此前覆写数组只有整体替换(`key!`)、前置(`+key`)、追加(`key+`)三种语义,无法「只改数组里某一个元素的部分字段」。新增 `~key`:以 `name` 为主键匹配数组元素,命中则深度合并该元素、保留其余字段与其余元素,找不到则追加。典型用途:修改订阅下发的某个 `proxy-group` 的字段(如给 `select` 组注入 `default-selected` 改默认选中节点),保留原有全部节点、不动其它分组、订阅更新后依然生效。键名真以 `~` 开头时用 `<~key>` 转义
|
|
28
|
+
- **覆写作用域限定(`match` 块)** - 覆写文件顶部可加 `match:` 块,让该文件只对指定订阅生效(无 `match` 仍全局生效,向后兼容)。支持 `subscription`(按订阅名精确匹配)和 `url-domain`(按订阅 URL hostname 后缀匹配)两个条件,所列条件需全部满足(AND),条件值为数组时其内部为 OR。未知匹配键或无法评估的条件均 fail closed(跳过该文件并告警),避免误配置静默全局生效。`ow list` 与 `status` 会展示各文件的作用域
|
|
29
|
+
|
|
30
|
+
### 修复
|
|
31
|
+
|
|
32
|
+
- **TUN 启动失败误报"密码错误或取消"** - 启动脚本失败时 `exit 1`,与 sudo 鉴权失败的退出码冲突,配置错误、端口占用等真实失败都被误报。脚本失败改用 `exit 2`,调用方据此区分;失败时同时清理 root 属主 pid 文件,避免后续 `start` 因残留死锁(旧提示只让 `pkill`,清不掉 pid 文件)
|
|
33
|
+
- **`reset subs` 半重置状态** - 只删订阅缓存/原始配置文件,settings 里的订阅列表保留,重置后 `start` 报"未找到订阅配置"。现同步清空订阅列表与 `active_subscription`
|
|
34
|
+
- **`sub add` 下载失败留下半成品订阅** - 订阅已写入并可能切为默认后下载才失败,之后 `start` 必然报错。现下载失败自动回滚(移除刚添加的订阅)
|
|
35
|
+
- **覆写文件顶层为数组时被当配置合并** - YAML 顶层数组能通过类型检查,被解构出数字键参与合并。现拒绝并告警
|
|
36
|
+
- **`sub web` 缺页面地址时覆盖已保存配置** - 回退路径重新下载订阅并落盘,副作用超出"打开页面"。现只取响应头,不写盘
|
|
37
|
+
- **`clean` 后订阅文件残留死节点规则** - 只清理了引用已删空分组的规则,直接引用死节点的规则留在文件里(靠构建时兜底)。现保存时一并清理
|
|
38
|
+
- **自动更新超时后全部计为失败** - 超时即丢弃已完成结果。现收齐已完成/已失败的更新再统计,超时只影响未完成的部分
|
|
39
|
+
- **`SUB-RULE` 规则被误删** - 配置校验按「末段为代理/分组名」检查规则目标,但 `SUB-RULE` 末段引用的是 sub-rule 名,被当作无效引用删除。现跳过此类规则的目标校验
|
|
40
|
+
- **空名覆写节点清空 include-all 分组** - 覆写注入 `name` 为空的节点时,exclude-filter 正则出现空分支(`a||b`)匹配所有节点,分组被清空。现过滤空/非字符串节点名
|
|
41
|
+
- **节点重命名未同步规则** - 保存时裁剪节点名只更新了 `proxies`/`proxy-groups`,规则里直接引用旧名会变悬空引用。现一并 remap `rules` 中的目标
|
|
42
|
+
- **`sub add` URL 校验过宽** - 仅判 `startsWith('http')`,`httpfoo://`、`http-evil` 等能通过。现用 `URL` 解析校验协议并 trim 首尾空白
|
|
43
|
+
- **`reset -f` 语义误导** - `-f` 是 `--full`(删全部)的别名,与常见 `-f=force` 直觉冲突,且未知标志(如拼错的 `--ful`)被静默忽略后走默认删除。现移除 `-f` 别名(删全部只认 `--full`,免确认统一 `-y/--yes`),未知标志一律报错退出
|
|
44
|
+
- **HTTP 下载无响应体大小上限** - 订阅/内核下载被劫持或故障返回超大响应时可能 OOM。现按 `Content-Length` 提前拒绝并流式读取,超 50MB 中止
|
|
45
|
+
- **`tar` 解压无路径穿越防护** - 恶意镜像可借含 `../`/绝对路径的归档条目写出目标目录之外。现解压前校验条目路径
|
|
46
|
+
- **内核进程创建失败处理** - 内核二进制不可执行时,`spawn` 的 error 事件无监听会冒泡为未捕获异常、`pid` 缺失会二次抛错。现监听 error 并在 pid 缺失时给出可读提示
|
|
47
|
+
|
|
48
|
+
### 安全
|
|
49
|
+
|
|
50
|
+
- **错误信息遮蔽路径型订阅令牌** - `maskUrl` 原仅遮蔽 query/userinfo,形如 `/subscribe/<TOKEN>` 的路径令牌会原样出现在错误日志。现对疑似令牌的长路径段一并遮蔽
|
|
51
|
+
- **`ui` 命令不再明文回显 `controller_secret`** - 改为提示密钥已配置、见 `settings.json`,避免进入 shell 历史/日志
|
|
52
|
+
|
|
53
|
+
### 变更
|
|
54
|
+
|
|
55
|
+
- **`allow-lan` 不再强制锁定** - 订阅/覆写显式提供时按其值(支持局域网设备连入代理端口的入站场景),未提供时默认 `false`
|
|
56
|
+
- **`sub` 列表改为纯只读** - 不再触发自动更新(更新是写操作),`sub add`/`use`/`update` 末尾的列表也不再顺带更新其他订阅。自动更新只在 `start` 与显式 `sub update` 时发生
|
|
57
|
+
- **启动自动清理加冷却** - 节点数超阈值时的自动测速清理改为同一订阅 12 小时内只跑一次(冷却记录在订阅缓存),新增 `--no-clean` 跳过;避免每次 `start` 都全量测速并可能二次重启
|
|
58
|
+
- **隐式停止不再弹 sudo** - `start`/`clean` 遇到 root 属主残留(TUN 实例等)时,不再由 `stop()` 内部 sudo 提权,改为报错引导手动清理或使用 `sub clean`(`stop` 命令本身的 sudo 提权保留)
|
|
59
|
+
- **可选 `controller_secret` 设置** - `settings.json` 设置后,external-controller 启用 Bearer 认证(系统锁定,订阅/覆写无法伪造),`ui` 命令会提示密钥;面向多用户环境
|
|
60
|
+
- **支持 `--flag=value` 形式** - `--timeout=3000`、`--mirror=url` 等与空格分隔形式等价
|
|
61
|
+
- **非 TTY 下测速不再逐节点刷屏** - 管道/重定向时只输出汇总行
|
|
62
|
+
- **`mihomo log` 的 Ctrl+C 不再打印"正在退出..."** - follow 场景这是常规退出
|
|
63
|
+
- **`status` 未运行时也显示模式** - 有配置文件时展示上次构建的 TUN/Mixed
|
|
64
|
+
- **`update` 权限失败给出 sudo 提示**
|
|
65
|
+
- **`test`/`clean` 与 `sub test`/`sub clean` 帮助区分** - 前者经运行中的主实例,后者用隔离实例、无需主实例运行
|
|
66
|
+
- **`status` TUN 模式端口显示** - 不再显示「未知」,改为「TUN 接管」并标注备用监听端口
|
|
67
|
+
- **`sub use`/`ow on`/`ow off` 触发重启时透传启动选项** - `-s`/`-t`/`-j`/`--no-clean` 等不再被丢弃
|
|
68
|
+
- **订阅「永久」到期显示** - 机场 `expire=0` 不再显示成 `1970-01-01`,改为「永久」
|
|
69
|
+
- **`curl` 未安装时明确提示** - 内核下载不再报「退出码 null」
|
|
70
|
+
|
|
71
|
+
### 内部
|
|
72
|
+
|
|
73
|
+
- 抽出 `src/progress.ts`(进度条与结果格式化),解开 `commands/start` ↔ `commands/subscription` 的循环依赖
|
|
74
|
+
- 订阅缓存损坏时与 settings.json 一致:先备份再回退默认
|
|
75
|
+
- 合并订阅任一来源失败即取消其余下载,不再白等
|
|
76
|
+
- `applyOverwrite` 恒返回浅拷贝,避免构建时的锁定键删除污染订阅原始对象(debug stage1 失真)
|
|
77
|
+
- `isGithubUrl` 对多 URL 合并订阅要求全部来源为 GitHub 才按 GitHub 策略
|
|
78
|
+
- `--mirror` 默认镜像收敛为 `DEFAULT_MIRROR` 常量(与可用镜像列表首项一致)
|
|
79
|
+
- `buildConfig(subRawContent, mode, scope?)` 新增可选订阅作用域参数(`{ subName, subUrl }`),由 `prepareConfigForStart` 组装传入;作用域过滤在 `buildConfig` 顶部统一执行一次,确保被排除的覆写文件不会污染 `exclude-filter` 与 debug 输出
|
|
80
|
+
- `match` 元数据键在 `loadOverwriteFile` 阶段即抽成结构化字段并从 config 剥离,保证它永不进入最终 mihomo 配置
|
|
81
|
+
|
|
3
82
|
## [3.2.0] - 2026-07-19
|
|
4
83
|
|
|
5
84
|
### 修复
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- 🔄 **自动更新** - 启动时自动检查并更新过期订阅
|
|
9
9
|
- 🔍 **模糊匹配** - `sub use` / `sub web` 支持订阅名称模糊匹配
|
|
10
10
|
- 🧹 **节点测速清理** - `test` 快速测试、`clean` 清理并重启;`sub test/clean` 独立进程测试任意订阅
|
|
11
|
-
- 📝 **覆写配置** -
|
|
11
|
+
- 📝 **覆写配置** - 在订阅基础上进行自定义覆写,支持强制覆盖、数组合并、按 name 就地 patch、按订阅限定作用域
|
|
12
12
|
- 🔄 **智能重启** - `sub use` 切换订阅、`ow on/off` 切换覆写后自动重启
|
|
13
13
|
- 🚀 **进程管理** - 启动/停止/切换模式,自动清理残留进程
|
|
14
14
|
- 🛡️ **进程保活** - 基于 launchd(root),崩溃/开机自动拉起,代理后台常驻(`daemon on`)
|
|
@@ -84,7 +84,7 @@ mihomo ui yacd # YACD
|
|
|
84
84
|
|
|
85
85
|
| 命令 | 说明 |
|
|
86
86
|
| --------------------------- | ---------------------------------------------------------------------------- |
|
|
87
|
-
| `mihomo start [tun\|mixed]` | 启动/重启/切换代理模式(`-s` 跳过更新,`-u` 更新超时,`-r` 清理轮次,`-t` 超时,`-j`
|
|
87
|
+
| `mihomo start [tun\|mixed]` | 启动/重启/切换代理模式(`-s` 跳过更新,`-u` 更新超时,`-r` 清理轮次,`-t` 超时,`-j` 并发,`--no-clean` 跳过启动自动清理) |
|
|
88
88
|
| `mihomo stop` | 停止代理 |
|
|
89
89
|
| `mihomo status` | 查看运行状态 |
|
|
90
90
|
| `mihomo log` | 实时查看日志 (`-o` 用系统编辑器打开) |
|
|
@@ -102,10 +102,10 @@ mihomo ui yacd # YACD
|
|
|
102
102
|
| `mihomo sub update <name>` | 更新指定订阅(支持模糊匹配) |
|
|
103
103
|
| `mihomo sub remove <name>` | 删除订阅(支持模糊匹配) |
|
|
104
104
|
| `mihomo sub web [name]` | 打开订阅页面(无参打开默认) |
|
|
105
|
-
| `mihomo sub test [name]` |
|
|
106
|
-
| `mihomo sub clean [name]` |
|
|
107
|
-
| `mihomo test` |
|
|
108
|
-
| `mihomo clean` |
|
|
105
|
+
| `mihomo sub test [name]` | 测试节点连通性(独立隔离实例,无需运行主实例,`-t` 超时,`-j` 并发) |
|
|
106
|
+
| `mihomo sub clean [name]` | 测速并清理失败节点(独立实例,不动主实例,`-r` 轮数,默认2)|
|
|
107
|
+
| `mihomo test` | 测试当前节点(经运行中的主实例,`-t` 超时,`-j` 并发) |
|
|
108
|
+
| `mihomo clean` | 清理失败节点并重启(经主实例,`-t` 超时,`-j` 并发,`-r` 轮数) |
|
|
109
109
|
|
|
110
110
|
### 覆写配置
|
|
111
111
|
|
|
@@ -125,7 +125,7 @@ mihomo ui yacd # YACD
|
|
|
125
125
|
| `mihomo ui [zash\|dash\|yacd]` | 打开 Web UI |
|
|
126
126
|
| `mihomo dir` | 显示数据目录位置 |
|
|
127
127
|
| `mihomo dir open [target]` | 打开指定目录(`root`, `subs`, `logs`, `kernel` 等) |
|
|
128
|
-
| `mihomo reset [目标...] [--full]` | 重置用户数据(可用目标:`subs`, `logs`, `kernel`, `overwrites`
|
|
128
|
+
| `mihomo reset [目标...] [--full] [-y]` | 重置用户数据(可用目标:`subs`, `logs`, `kernel`, `overwrites` 等;`--full` 删全部,`-y` 跳过确认) |
|
|
129
129
|
| `mihomo version` | 显示版本信息 |
|
|
130
130
|
| `mihomo help` | 显示帮助信息 |
|
|
131
131
|
|
|
@@ -223,10 +223,17 @@ mihomo kernel --mirror-all hk.gh-proxy.org
|
|
|
223
223
|
## 订阅自动更新
|
|
224
224
|
|
|
225
225
|
- 默认更新间隔:GitHub 订阅 6 小时,其他订阅 12 小时(订阅服务端可通过 `profile-update-interval` 覆盖)
|
|
226
|
-
- 触发时机:`start`
|
|
226
|
+
- 触发时机:`start` 命令(`sub` 列表为纯只读,不再触发更新)
|
|
227
227
|
- 更新失败时继续使用本地缓存,不影响使用
|
|
228
228
|
- 自动更新默认超时 10 秒,可通过 `-u <ms>` 调整;使用 `-s` 可完全跳过自动更新
|
|
229
229
|
|
|
230
|
+
## 启动自动清理
|
|
231
|
+
|
|
232
|
+
节点数超过阈值(GitHub 订阅 50、其他 100)时,`start` 会自动测速清理死节点:
|
|
233
|
+
|
|
234
|
+
- 同一订阅 12 小时内只自动清理一次(冷却记录在订阅缓存),避免每次启动都全量测速
|
|
235
|
+
- `--no-clean` 可跳过;随时可用 `mihomo clean` / `mihomo sub clean` 手动清理
|
|
236
|
+
|
|
230
237
|
## 数据目录
|
|
231
238
|
|
|
232
239
|
用户数据存储位置(与安装位置分离,更新不丢失):
|
|
@@ -268,12 +275,24 @@ mihomo kernel --mirror-all hk.gh-proxy.org
|
|
|
268
275
|
|
|
269
276
|
覆写配置支持以下特殊操作符:
|
|
270
277
|
|
|
271
|
-
| 语法 | 作用
|
|
272
|
-
| -------- |
|
|
273
|
-
| `key!` | 强制覆盖整个对象(不深度合并)
|
|
274
|
-
| `+key` | 数组前置插入
|
|
275
|
-
| `key+` | 数组追加
|
|
276
|
-
|
|
|
278
|
+
| 语法 | 作用 | 示例 |
|
|
279
|
+
| -------- | ----------------------------------------- | -------------------- |
|
|
280
|
+
| `key!` | 强制覆盖整个对象(不深度合并) | `dns!`: { ... } |
|
|
281
|
+
| `+key` | 数组前置插入 | `+proxies`: [...] |
|
|
282
|
+
| `key+` | 数组追加 | `rules+`: [...] |
|
|
283
|
+
| `~key` | 按 `name` 就地合并数组中的单个元素 | `~proxy-groups`: [...] |
|
|
284
|
+
| `<+key>` | 键名以 `+`/`~` 等符号开头时转义 | `<+.google.cn>`: ... |
|
|
285
|
+
|
|
286
|
+
`~key` 用于**只修改数组里某一个元素的部分字段**,而不动其余元素、也不必复制整个元素。以 `name` 为主键匹配:命中同名元素则深度合并该元素,找不到则追加。典型用途:修改订阅下发的某个 `proxy-group` 的字段(如默认选中的节点),订阅更新后依然生效。
|
|
287
|
+
|
|
288
|
+
### 作用域限定(match)
|
|
289
|
+
|
|
290
|
+
在覆写文件顶部加 `match:` 块,可让该文件**只对指定订阅生效**(无 `match` 则全局生效)。所列条件需全部满足(AND),条件值为数组时其内部为 OR:
|
|
291
|
+
|
|
292
|
+
| 匹配键 | 作用 |
|
|
293
|
+
| ------------- | ----------------------------- |
|
|
294
|
+
| `subscription` | 按订阅名精确匹配 |
|
|
295
|
+
| `url-domain` | 按订阅 URL 的 hostname 后缀匹配 |
|
|
277
296
|
|
|
278
297
|
### 示例
|
|
279
298
|
|
|
@@ -292,6 +311,19 @@ rules+:
|
|
|
292
311
|
- 'DOMAIN-SUFFIX,example.com,DIRECT'
|
|
293
312
|
```
|
|
294
313
|
|
|
314
|
+
```yaml
|
|
315
|
+
# ~/.mihomo-cli/overwrite.edu1.yaml
|
|
316
|
+
# 只对 edu1 订阅生效:把订阅下发的 Developer 分组默认选中改为 TW Fixed IP
|
|
317
|
+
match:
|
|
318
|
+
subscription: edu1 # 或 url-domain: glados-config.com
|
|
319
|
+
|
|
320
|
+
~proxy-groups:
|
|
321
|
+
- name: Developer
|
|
322
|
+
default-selected: TW Fixed IP
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
> 注:`default-selected` 由 mihomo 内核决定默认选中项,优先级低于 `store-selected` 缓存的历史选择。若之前手动选过、且开启了 `store-selected`,需 `mihomo reset data` 清缓存后才能看到默认值接管。
|
|
326
|
+
|
|
295
327
|
## Web UI
|
|
296
328
|
|
|
297
329
|
内置三个常用 Web UI:
|
|
@@ -331,13 +363,15 @@ sudo pkill -9 mihomo
|
|
|
331
363
|
|
|
332
364
|
## 安全特性
|
|
333
365
|
|
|
334
|
-
- **URL 脱敏**:订阅 URL 中的 token、key、password
|
|
366
|
+
- **URL 脱敏**:订阅 URL 中的 token、key、password 等敏感参数(含 query、userinfo 及路径型令牌)自动替换为 `***`
|
|
335
367
|
- **文件权限**:配置文件使用 `0o600` 权限(仅所有者可读可写),目录使用 `0o700` 权限
|
|
336
|
-
-
|
|
368
|
+
- **入站默认关闭**:订阅/覆写未指定时 `allow-lan` 默认 `false`;如需局域网设备连入代理端口,可在订阅或覆写中显式开启
|
|
337
369
|
- **信号处理**:优雅处理 SIGINT/SIGTERM 信号
|
|
338
370
|
- **异常捕获**:全局 uncaughtException 和 unhandledRejection 处理
|
|
339
371
|
|
|
340
|
-
> **注意**:外部控制器(`127.0.0.1:9090
|
|
372
|
+
> **注意**:外部控制器(`127.0.0.1:9090`)默认无鉴权,与 Clash 系工具惯例一致。它仅监听本机回环、局域网不可达;但本机其他进程(含浏览器中的网页)可访问它,请勿在不可信的多用户环境使用。
|
|
373
|
+
>
|
|
374
|
+
> 多用户环境可在 `settings.json` 中设置 `controller_secret`(写入配置后随启动生效,`ui` 命令会提示密钥),为控制器 API 加上 Bearer 认证;密钥由系统锁定,订阅/覆写无法伪造。
|
|
341
375
|
|
|
342
376
|
## 许可证
|
|
343
377
|
|