mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-16 15:17:14 +00:00
feat(sub): add legacy Clash subscription endpoint (#6338)
* feat(sub): add legacy Clash subscription endpoint * fix(deps): update js-yaml to patched release Raise the Swagger UI js-yaml override to 4.3.2 and refresh the lockfile to resolve GHSA-2883-xcg3-v3hh without changing Swagger UI. * fix(sub): preserve client detection and normalize legacy cipher Keep the original Clash/Mihomo auto-detection default so existing subscription URLs continue returning YAML. Normalize the panel-supported chacha20-poly1305 alias when generating legacy Clash profiles, and cover both regressions through HTTP endpoint tests. * refactor(sub): drop an unreachable guard and make the alias test assert Review of the legacy Clash subscription endpoint left three LOW findings, all introduced by the change: - The comment above the routing merge ran to three lines, over CLAUDE.md's two-line cap. - validateClashRouteGraph on the legacy path could never fail: the legacy branch skips the routing merge, so it validated the literal config built a few lines above against itself. Dead code that reads as a guard. - TestClashAliasesSkipConfiguredPathConflicts asserted nothing — it could only fail on an escaping gin panic, so a regression that registered the alias handler on the configured path went unnoticed. It now drives each collision through the router and asserts which format answers each path. --------- Co-authored-by: Sanaei <ho3ein.sanaei@gmail.com>
This commit is contained in:
@@ -42,17 +42,38 @@ URLs and preview both bodies here:
|
||||
|
||||
The **format is chosen by path**, each with its own enable toggle:
|
||||
|
||||
| Format | Path | Enabled by | Output |
|
||||
| --------------------- | --------- | ---------------- | --------------------------------------------------- |
|
||||
| **Raw links** | `subPath` | always (if on) | A list of `vless://`, `vmess://`, … links (base64-encoded when `subEncrypt` is on). |
|
||||
| **JSON** | `subJsonPath` | `subJsonEnable` | Full Xray client config(s). |
|
||||
| **Clash / Mihomo** | `subClashPath` | `subClashEnable` | YAML profile. |
|
||||
| Format | Path | Enabled by | Output |
|
||||
| ------------------------------ | ---------------- | ---------------- | --------------------------------------------------- |
|
||||
| **Raw links** | `subPath` | always (if on) | A list of `vless://`, `vmess://`, … links (base64-encoded when `subEncrypt` is on). |
|
||||
| **JSON** | `subJsonPath` | `subJsonEnable` | Full Xray client config(s). |
|
||||
| **Clash / Mihomo** | `subClashPath` | `subClashEnable` | Full Mihomo-compatible YAML profile. |
|
||||
| **Mihomo (explicit)** | `/mihomo/` | `subClashEnable` | Alias for the full `subClashPath` profile. |
|
||||
| **Clash for Windows (legacy)** | `/clash-legacy/` | `subClashEnable` | YAML limited to proxy types, transports, and ciphers supported by the legacy Clash core. |
|
||||
|
||||
Only enabled inbounds using **VLESS, VMess, Trojan, Shadowsocks, or Hysteria2**
|
||||
appear in a subscription, ordered by their sub-sort index. Requesting `subPath`
|
||||
with an `Accept: text/html` header (or `?html=1`) returns a human-readable info
|
||||
page instead of the raw body.
|
||||
|
||||
Use `/mihomo/<sub-id>` for Clash Verge Rev, Mihomo, and other maintained
|
||||
Mihomo-based clients. Use `/clash-legacy/<sub-id>` only for the discontinued
|
||||
Clash for Windows client. The legacy endpoint keeps compatible VMess, Trojan,
|
||||
and Shadowsocks nodes and excludes VLESS, Hysteria2, Reality, XHTTP,
|
||||
HTTPUpgrade, and Shadowsocks 2022. If no compatible node exists, it returns an
|
||||
explicit `422` response instead of a YAML profile the client cannot import.
|
||||
To avoid Mihomo-only syntax entering the legacy profile, this endpoint always
|
||||
uses its minimal `PROXY` group and `MATCH,PROXY` rule and ignores custom Clash
|
||||
routing settings.
|
||||
|
||||
If an administrator has already assigned `/mihomo/` or `/clash-legacy/` to a
|
||||
different configurable subscription path, that existing path is preserved and
|
||||
the conflicting alias is skipped with a warning at startup.
|
||||
|
||||
Automatic Clash format detection keeps the existing `(?i)(clash|mihomo)`
|
||||
default matcher so existing subscription URLs continue returning YAML.
|
||||
It does not distinguish legacy clients from Mihomo-based clients; Clash for
|
||||
Windows users must use `/clash-legacy/<sub-id>` for a compatible profile.
|
||||
|
||||
### Base64 vs JSON
|
||||
|
||||
The **Base64** body is just the newline-joined share links, standard-base64
|
||||
|
||||
@@ -36,14 +36,31 @@ https://<sub-host>:<sub-port>/<sub-path>/<sub-id>
|
||||
|
||||
**格式由路径决定**,每种格式都有各自的启用开关:
|
||||
|
||||
| 格式 | 路径 | 启用方式 | 输出 |
|
||||
| --------------------- | --------- | ---------------- | --------------------------------------------------- |
|
||||
| **原始链接** | `subPath` | 始终(若已开启) | 一组 `vless://`、`vmess://` 等链接的列表(当 `subEncrypt` 开启时进行 base64 编码)。 |
|
||||
| **JSON** | `subJsonPath` | `subJsonEnable` | 完整的 Xray 客户端配置。 |
|
||||
| **Clash / Mihomo** | `subClashPath` | `subClashEnable` | YAML 配置文件。 |
|
||||
| 格式 | 路径 | 启用方式 | 输出 |
|
||||
| ----------------------------- | ---------------- | ---------------- | --------------------------------------------------- |
|
||||
| **原始链接** | `subPath` | 始终(若已开启) | 一组 `vless://`、`vmess://` 等链接的列表(当 `subEncrypt` 开启时进行 base64 编码)。 |
|
||||
| **JSON** | `subJsonPath` | `subJsonEnable` | 完整的 Xray 客户端配置。 |
|
||||
| **Clash / Mihomo** | `subClashPath` | `subClashEnable` | 完整的 Mihomo 兼容 YAML 配置。 |
|
||||
| **Mihomo(明确端点)** | `/mihomo/` | `subClashEnable` | 完整 `subClashPath` 配置的别名。 |
|
||||
| **Clash for Windows(旧版)** | `/clash-legacy/` | `subClashEnable` | 仅包含旧 Clash 内核支持的代理类型、传输方式和加密算法。 |
|
||||
|
||||
只有使用 **VLESS、VMess、Trojan、Shadowsocks 或 Hysteria2** 的已启用入站才会出现在订阅中,并按其订阅排序索引排列。使用 `Accept: text/html` 头(或 `?html=1`)请求 `subPath` 会返回一个人类可读的信息页面,而非原始内容。
|
||||
|
||||
Clash Verge Rev、Mihomo 及其他仍在维护的 Mihomo 客户端应使用
|
||||
`/mihomo/<sub-id>`。已经停止维护的 Clash for Windows 应使用
|
||||
`/clash-legacy/<sub-id>`;旧版端点只保留兼容的 VMess、Trojan 和
|
||||
Shadowsocks 节点,并排除 VLESS、Hysteria2、Reality、XHTTP、HTTPUpgrade
|
||||
和 Shadowsocks 2022。如果没有任何兼容节点,端点会明确返回 `422`,而不是返回一份无法导入的 YAML。
|
||||
为避免 Mihomo 专用语法进入旧版配置,此端点始终使用最小的 `PROXY` 策略组与
|
||||
`MATCH,PROXY` 规则,并忽略自定义 Clash 路由设置。
|
||||
|
||||
如果管理员已经把 `/mihomo/` 或 `/clash-legacy/` 分配给其他可配置订阅路径,
|
||||
系统会保留原有路径,并在启动时记录警告、跳过发生冲突的别名。
|
||||
|
||||
Clash 格式自动识别保留原有的 `(?i)(clash|mihomo)` 默认匹配器,确保已有订阅 URL
|
||||
继续返回 YAML。它不区分旧版客户端与 Mihomo 系客户端;Clash for Windows 用户
|
||||
必须使用 `/clash-legacy/<sub-id>` 获取兼容配置。
|
||||
|
||||
### Base64 与 JSON
|
||||
|
||||
**Base64** 内容只是用换行符连接的分享链接,经标准 base64 编码(通过 `subEncrypt` 开关控制)。**JSON** 内容则将每个客户端包装为一份完整的 Xray 客户端配置 —— 一套固定的骨架(绑定到 127.0.0.1 的本地 SOCKS/HTTP 入站、DNS、路由、策略)加上一个指向该入站的 `proxy` 出站。3x-ui **对单个客户端输出单个配置对象,对多个客户端输出数组**,使用扁平的出站 `settings` 形式(`address`/`port`/`id`,`level: 8`),并从 `streamSettings` 中剥离 `sockopt`。
|
||||
|
||||
Reference in New Issue
Block a user