diff --git a/luci-app-easymesh/Makefile b/luci-app-easymesh/Makefile index 08d7cec46..3d4c49722 100755 --- a/luci-app-easymesh/Makefile +++ b/luci-app-easymesh/Makefile @@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-easymesh PKG_VERSION:=2.4.1 -PKG_RELEASE:=3 +PKG_RELEASE:=4 PKG_LICENSE:=GPL-2.0 PKG_MAINTAINER:=Arafat Rahman Zami Mondol diff --git a/luci-app-substore/CHANGELOG.md b/luci-app-substore/CHANGELOG.md index 9198c14f4..1092db5b4 100644 --- a/luci-app-substore/CHANGELOG.md +++ b/luci-app-substore/CHANGELOG.md @@ -2,6 +2,52 @@ All notable changes to this project will be documented in this file. +## [2.7.2-r9] - Loon 引号包裹的位置参数放行逗号(LEGACY_ISSUES 7.9 e 修订) + +第五轮把 7.9(e) 判为「含英文逗号就整条丢弃」,理由里有一句是错的。本轮复核后 +只推翻其中的**位置参数**那一半。 + +### 修复 — 7.9(e) 修订:Loon 引号包裹的位置参数放行逗号 + +第五轮 `surge_line` 的注释写着「Loon 的那对引号只是标记,值里的逗号照样是分隔符」。 +Loon 官方文档(`nsloon.app/docs/Node/`)的原文是「**参数值中含有英文逗号时,请使用 +双引号包裹**」—— 这句话只在客户端解析是**引号感知**的前提下才成立,也就是说那对 +双引号**确实**能保住值里的逗号。原注释把引号当成了纯装饰,据此推出的「引号救不了 +逗号」不成立,整条丢弃的代价(极少见的「密码里带逗号」的节点在 Loon 上被丢弃) +也就失去了依据。 + +判据改成「这个值是不是引号完整包裹的」(`v:match('^".*"$')`),**不是** `is_loon`: + +* Loon 位置参数(`loon_positional` 无条件加引号)→ **放行**含逗号的值; +* Loon 的裸位置参数(无引号,如加密方式)→ 仍丢弃(无引号语义); +* 具名参数(Surge 家族,以及 Loon 的 `sni=` / `ws-path=` 等)→ 仍丢弃:Surge 家族的 + 引号语义未获文档证据,且解析端不对具名值 unquote,加引号会直接断掉回环; +* Surfboard 的裸位置参数(anytls)→ 仍丢弃。 + +判据选「是否引号包裹」而非「是否 Loon」,让上述四种情形自动分开,不必再分叉一次。 + +**安全性**来自 `loon_positional` 的两条既有保证:它无条件把 Loon 的位置凭据包成 +`"…"`(引号是 Loon 语法的一部分),且值里含 `"` 时直接返回 `nil`(整条丢弃,走不到 +这一行)—— 于是引号包裹的值内部不可能出现落单引号, +`parser_surge.split_fields` 的「奇数引号回退」分支不会被本行的输出触发。 + +具名参数检查原样不动。 + +### 测试 + +* `tests/output_formats_test.lua`:第五轮那条 `loon comma password drops node` 翻转成 + `loon comma password kept (quoted positional)`,并补 `loon rt comma password` / + `loon rt comma method` 两条回环断言(放行的前提就是能原样回环);`surge comma + password drops node` 保留为反向护栏。 +* `tests/anytls_reality_test.lua`:新增 `surge_line comma in quoted positional + password kept`、`loon comma password round-trips`、`surge_line comma in loon vless + uuid kept`;保留具名密码、裸位置密码两条护栏。 +* 断言先取 `local line = fmts.surge_line(...)` 再判 `type(line) == "string"`:直接在 + `nil` 上调 `:find` 会抛错、吞掉同文件后续断言,反向验证就只剩「崩了」。 +* 反向验证:把谓词改回无条件丢弃 → **6 条 FAIL** 全部指向本轮改动,4 条护栏断言 + 始终绿;还原后全绿。 +* 全套 **59 个测试文件、0 失败**。 + ## [2.7.2-r8] - Surge / SurgeMac 一并丢弃 Hysteria v1(LEGACY_ISSUES 7.9 j) 第六轮把 Loon 的 Hysteria v1 丢弃了,本轮把同一条证据链延伸到 Surge 家族。 diff --git a/luci-app-substore/Makefile b/luci-app-substore/Makefile index fb08ad78a..b90d3cc2c 100644 --- a/luci-app-substore/Makefile +++ b/luci-app-substore/Makefile @@ -10,7 +10,7 @@ PKG_NAME:=luci-app-substore # 版本约定:每次提交 PKG_RELEASE +1(2.1.2-r1 ~ r9); # 达到 r10 时 PKG_VERSION 末位 +1(2.1.2 -> 2.1.3),PKG_RELEASE 重置为 1。 PKG_VERSION:=2.7.2 -PKG_RELEASE:=22 +PKG_RELEASE:=23 LUCI_DEPENDS:=+luci-lua-runtime +luci-compat diff --git a/luci-app-substore/docs/LEGACY_ISSUES.md b/luci-app-substore/docs/LEGACY_ISSUES.md index 9e4c66bb7..c013bb1bf 100644 --- a/luci-app-substore/docs/LEGACY_ISSUES.md +++ b/luci-app-substore/docs/LEGACY_ISSUES.md @@ -658,13 +658,13 @@ crontab 里,`substore-cron.sh` 会拿着已不存在的 id 反复执行,每 | 7.6 | 修复 | **已修复**(第一轮,见下) | | 7.7 | A:后端错误串 msgid 化 | **已实施**(第四轮,见下) | | 7.8 | A:删除 `age.lua` / `age_test.lua` | **已删除**(第一轮) | -| 7.9 | (a)(b)(c)(d) 全部实施;(e) 保持保守;(g)(h) 实施;(i) 保持现状;(j) 实施(Surge/SurgeMac) | **已实施**(第五、六、七轮,见下) | +| 7.9 | (a)(b)(c)(d) 全部实施;(e) 具名保持保守、Loon 位置参数放行(第八轮修订);(g)(h) 实施;(i) 保持现状;(j) 实施(Surge/SurgeMac) | **已实施**(第五~八轮,见下) | 7.5 / 7.6 的修复见本节末尾「7.5 / 7.6 修复记录」, 7.1 / 7.3 / 7.4 的实施见「第二轮修复记录」, 7.2 的实施见「第三轮修复记录」, 7.7 的实施见「第四轮修复记录」, -7.9 的 (a)–(e) 见「第五轮修复记录」,(g)(h) 见「第六轮修复记录」,(j) 见「第七轮修复记录」。 +7.9 的 (a)–(e) 见「第五轮修复记录」,(g)(h) 见「第六轮修复记录」,(j) 见「第七轮修复记录」,(e) 的修订见「第八轮修复记录」。 | # | 问题 | 位置 | 依据 | 影响 | |---|---|---|---|---| @@ -676,7 +676,7 @@ crontab 里,`substore-cron.sh` 会拿着已不存在的 id 反复执行,每 | 7.6 | ~~Loon 的 `transport=ws` 未映射到 `net`~~ **已修复** | `parser_surge.parse_surge_line` 的 `transport=` 分支 | 只认 `ws=true`(Surge 旧写法)与 `obfs=ws`(QX);`nsloon.app/docs/Node/` 用 `transport=ws` + `path=` + `host=` | Loon 的 ws 节点导入后 `net=tcp`,`path` / `host` 全丢 → 导出到任何格式都按 tcp 连,握手失败**且不报错** | | 7.7 | ~~后端模块仍有 **113 处**硬编码中文字符串字面量(注释外)~~ **已实施** | `core.lua` 47 / `http.lua` 47 / `parser.lua` 9 / `util.lua` 5 / `output_wireguard_conf.lua` 3 / `node.lua` 2 | 扫描脚本(去注释后提取含 CJK / 全角的字符串字面量),见下 | 控制器文案已接入 i18n,但这些来自后端的失败原因经 `?err=` **原样**显示,英文界面下仍是中文。**已按 A 实施**:全部改为语言中立的英文 msgid,组合消息用 `msg.lua` 的分隔符机制,翻译只在显示边界发生(详见「第四轮修复记录」) | | 7.8 | ~~`root/usr/share/substore/age.lua` 与 `tests/age_test.lua` 未被 git 跟踪,且 `age.lua` 未被任何模块 `require`~~ **已删除** | 仓库根 | `grep -rn require` 无引用 | 未随包发布;留在工作区会被后续审计反复重新评估 | -| 7.9 | ~~Loon 的节点行仍有**多处**与官方文档不一致~~ **已实施** | `output_formats.surge_line` / `parser_surge.parse_surge_line` | `nsloon.app/docs/Node/`;`manual.nssurge.com`;`getsurfboard.com` | 逐条见下「7.9 的明细」。**已按 (a)(b)(c)(d) 全部实施、(e) 保持保守**:Loon 的 TLS 开关改 `over-tls`(Trojan 除外)、UDP 改 `udp`、Surge 家族补 `encrypt-method`、Loon 的 ss/ssr/hysteria2 改位置参数;解析端同步跟进以保住回环(详见「第五轮修复记录」)。实施中新发现三条待决策项,见下「第五轮新发现」;其中 (g)(h) 已于第六轮实施、(i) 决定保持现状,另发现 (j) Surge 家族同样没有 Hysteria v1,**已于第七轮实施**(Surge / SurgeMac 丢弃,Surfboard 因无证据保留) | +| 7.9 | ~~Loon 的节点行仍有**多处**与官方文档不一致~~ **已实施** | `output_formats.surge_line` / `parser_surge.parse_surge_line` | `nsloon.app/docs/Node/`;`manual.nssurge.com`;`getsurfboard.com` | 逐条见下「7.9 的明细」。**已按 (a)(b)(c)(d) 全部实施、(e) 具名保持保守而 Loon 位置参数于第八轮改为放行**:Loon 的 TLS 开关改 `over-tls`(Trojan 除外)、UDP 改 `udp`、Surge 家族补 `encrypt-method`、Loon 的 ss/ssr/hysteria2 改位置参数;解析端同步跟进以保住回环(详见「第五轮修复记录」)。实施中新发现三条待决策项,见下「第五轮新发现」;其中 (g)(h) 已于第六轮实施、(i) 决定保持现状,另发现 (j) Surge 家族同样没有 Hysteria v1,**已于第七轮实施**(Surge / SurgeMac 丢弃,Surfboard 因无证据保留) | ### 7.7 的统计口径与例外(修复前必读) @@ -715,7 +715,8 @@ crontab 里,`substore-cron.sh` 会拿着已不存在的 id 反复执行,每 Loon 与 Surge 家族的不一致远不止「凭据位置」。以下每条都对照官方文档原文, **没有推测项**;本轮按用户的轮次安排只做决策里点名的 7.4-A,其余记录在此待决策。 **第五轮(2.7.2-r6)已按 (a)(b)(c)(d) 全部实施、(e) 保持保守**,各条下方的 -「→ 实施」注明落点。 +「→ 实施」注明落点;**(e) 已于第八轮(2.7.2-r9)部分修订**(具名参数保持保守、 +Loon 的引号包裹位置参数改为放行),见「第八轮修复记录」。 **(a) Loon 的 TLS 开关写作 `over-tls`,本生成器写 `tls`** —— 影响最大的一条。 Loon 文档的通用参数表与 Reality 示例都用 `over-tls=true`: @@ -779,6 +780,13 @@ Loon 不再要这个开关,所以 Loon 的 Trojan 行整个不写 TLS 参数 (保守:本行的具名参数一律不带引号,两种约定混用会让行为依赖客户端实现), 代价是极少见的「密码里带逗号」的节点在 Loon 上被丢弃。 +**→ 部分修订(第八轮,2.7.2-r9)**:既然引号**确实**能保住逗号,上述保守决策的 +依据(「引号救不了逗号」)就不成立。第八轮只推翻**位置参数那一半** —— Loon 的 +引号包裹位置参数放行含逗号的值;**具名参数仍按「含逗号就丢弃」**(Surge 家族的 +引号语义未获文档证据,且解析端不对具名值 unquote)。判据是「值是否被引号完整 +包裹」而非「是否 Loon」,Surfboard 的裸位置参数因此自动落在丢弃一侧。详见 +「第八轮修复记录」。 + **(f) 更正:Surfboard 的 trojan / vmess / vless 凭据是具名写法,不是位置参数** —— 本节 7.4 行原先把 Surfboard 与 Loon 并列,是**误判**。复核 `getsurfboard.com` 的 vmess 页:其 Format 模板写 `{username}` 位置,但**实际示例与参数表都是 `key=value`** @@ -790,6 +798,11 @@ trojan 页同样写 `username=` / `password=`。所以 Surge / Surfboard / Surge 就整条丢弃」处理,并在 `tests/output_formats_test.lua` 钉了一条断言防止日后被 无意改成半截输出。 +**(e) 修订说明(第八轮)**:位置参数那一半被**部分推翻**。第五轮那条断言 +(`loon comma password drops node`)已按新行为翻转成 `loon comma password kept +(quoted positional)`,并补了「导出 → 导入拿到同一个密码」的回环断言 —— 放行的 +前提就是能原样回环。具名参数那一半保持不变,护栏断言仍在。 + ### 第五轮新发现((g)(h) 第六轮已实施,(i) 保持现状,(j) 第七轮已实施) 第五轮实施 (a)–(d) 时对照 `nsloon.app/docs/Node/` 全文复核,另发现三处不一致。 @@ -1276,7 +1289,8 @@ message"` 后跑 `tests/backend_i18n_test.lua`,得到 **1 条 FAIL**(`no po ## 第五轮修复记录(7.9) -**7.9 (a)(b)(c)(d) 按官方文档对齐 Loon / Surge 家族的写法**,(e) 保持保守。 +**7.9 (a)(b)(c)(d) 按官方文档对齐 Loon / Surge 家族的写法**,(e) 保持保守 +(**该保守决策已于第八轮部分修订**,见「第八轮修复记录」)。 全部改动集中在 `root/usr/share/substore/output_formats.lua` 的 `M.surge_line` (生成端)与 `root/usr/share/substore/parser_surge.lua` 的 `parse_surge_line` (解析端)—— 两端必须成对,否则导出的配置再导入回来会静默丢字段。 @@ -1343,7 +1357,7 @@ trojan / vmess / vless 一律用具名参数」—— 7.4-A 之后就不成立 * `tests/ssr_test.lua`:`loon encrypt-method` 一条改为断言位置参数写法,并新增 **9 条 Loon 输出 → 导入回环**断言。 * `tests/output_formats_test.lua`:新增 **7.9 专节 24 条**((a) 6 / (b) 3 / (c) 4 / - (d) 4 / (e) 1 / 回环 6)。 + (d) 4 / (e) 1 / 回环 6)。**(e) 那 1 条已于第八轮随修订改写**,见「第八轮修复记录」。 * **反向验证**(逐条把代码改回旧行为,确认测试变红):`tls_flag` 写死 `tls=true` → 3 条 FAIL;UDP 写死 `udp-relay` → 2 条 FAIL;去掉 `encrypt-method` → 2 条 FAIL; Loon 的 ss / hysteria2 改回具名 → 2 条 FAIL;解析端 ssr 分支停用 → 5 条 FAIL; @@ -1462,6 +1476,80 @@ if n["skip-cert-verify"] then e[#e + 1] = "skip-cert-verify=true" end 无。这是 7.9 决策链的最后一条;实施完 (j) 后 7.9 的 (a)–(e)、(g)–(j) 全部结清 ((f) 复核确认本来就对,(i) 决定保持现状)。 +**(e) 的例外**:(e) 当时按「保持保守」结清,但第八轮复核发现该保守决策建立在一个 +**错误的注释**上(详见「第八轮修复记录」),于是对**位置参数那一半**做了修订 —— +具名参数仍保持保守。这是 7.9 唯一一处「结清后又修订」的条目。 + +--- + +## 第八轮修复记录(7.9 (e) 的修订) + +**7.9 (e) 的保守决策被部分推翻:Loon 引号包裹的位置参数放行含英文逗号的值。** + +### 起因 + +第五轮把 (e) 判为「保持保守:位置参数或具名值里含英文逗号就整条丢弃」, +并在 `surge_line` 里写下一段理由,其中一句是错的: + +> Loon 的那对引号只是标记,值里的逗号照样是分隔符。 + +Loon 官方文档(`nsloon.app/docs/Node/`)原文是「**参数值中含有英文逗号时,请使用 +双引号包裹**」—— 这句话只有在**客户端解析是引号感知**的前提下才成立,也就是说那对 +双引号**确实**能保住值里的逗号。原注释把「引号」当成了纯粹的装饰,据此推出的 +「引号救不了逗号」不成立,整条丢弃的代价(极少见的「密码里带逗号」的节点在 Loon +上被丢弃)也就失去了依据。 + +### 精确范围(用户确认) + +只改 **Loon 的引号包裹位置参数**这一种情形,其余一律不动: + +| 情形 | 第五轮 | 第八轮 | +|---|---|---| +| Loon 位置参数,值被 `"…"` 完整包裹 | 丢弃 | **放行** | +| Loon 位置参数,裸值(无引号,如加密方式) | 丢弃 | 丢弃(无引号语义) | +| 具名参数(Surge 家族 + Loon 的 `sni=` / `ws-path=` 等) | 丢弃 | 丢弃(Surge 引号语义未获文档证据,且解析端不对具名值 unquote,加引号会断回环) | +| Surfboard 的裸位置参数(anytls) | 丢弃 | 丢弃(无引号语义) | + +判据**不是** `is_loon` 而是「这个值是不是引号包裹的」(`v:match('^".*"$')`): +`loon_positional` 只在 Loon 分支被调用,Surfboard 的 anytls 走裸位置参数, +两者由这个判据自动分开,不必再分叉一次。 + +### 安全性依据 + +放行不会让生成端产出解析端读不动的行,因为 `loon_positional` 有两条保证: + +1. 它**无条件**把 Loon 的位置凭据包成 `"…"`,所以引号是 Loon 语法的一部分; +2. 值里含 `"` 时它直接返回 `nil`(整条丢弃,走不到这一行)—— 于是引号包裹的值 + 内部不可能出现落单引号,`parser_surge.split_fields` 的「奇数引号回退」分支 + 不会被本行的输出触发。 + +### 改动 + +* `root/usr/share/substore/output_formats.lua`:`surge_line` 的位置参数检查 + `if v:find(",", 1, true) then return nil end` 改为 + `if v:find(",", 1, true) and not v:match('^".*"$') then return nil end`; + 上方注释整段重写(说明引号语义、判据选择与安全性依据)。 +* 具名参数检查(上一段 `for _, kv in ipairs(e)`)**原样不动**。 + +### 测试 + +* `tests/output_formats_test.lua`:第五轮那条 `loon comma password drops node` + 改为 `loon comma password kept (quoted positional)`,并新增回环断言 + `loon rt comma password` / `loon rt comma method`;同时保留 + `surge comma password drops node` 作为反向护栏。 +* `tests/anytls_reality_test.lua`:新增 `surge_line comma in quoted positional + password kept`、`loon comma password round-trips`、`surge_line comma in loon + vless uuid kept`;保留 `surge_line comma in named password -> nil` 与 + `surge_line comma in bare positional password -> nil` 两条护栏。 +* 断言一律先 `local line = fmts.surge_line(...)` 再判 `type(line) == "string"`: + 直接在 `nil` 上调 `:find` 会抛错、把同文件后续断言全吞掉,反向验证就只能看到 + 「崩了」而看不到是哪条行为变了。 +* **反向验证**:把谓词改回 `if v:find(",", 1, true) then`(撤掉放行)→ **6 条 FAIL** + 全部指向本轮改动(output_formats 3 条 + anytls 3 条),4 条护栏断言 + (`surge comma password drops node`、具名密码、裸位置密码、具名 uuid)**始终绿** + → 说明断言确实指向改动,且没有误伤范围外的行为。还原后全绿。 +* 全套 **59 个测试文件、0 失败**。 + --- # 附:P2 修复范围(不含本文件所列项) diff --git a/luci-app-substore/root/usr/share/substore/output_formats.lua b/luci-app-substore/root/usr/share/substore/output_formats.lua index ada75e72f..378445c2e 100644 --- a/luci-app-substore/root/usr/share/substore/output_formats.lua +++ b/luci-app-substore/root/usr/share/substore/output_formats.lua @@ -376,15 +376,23 @@ function M.surge_line(n, flavor) local v = kv:match("^[^=]*=(.*)$") if v and v:find(",", 1, true) then return nil end end - -- 位置参数(Loon 的凭据写法)按官方文档是带双引号包裹的,而 Loon 文档明说 - -- 「参数值中含有英文逗号时,请使用双引号包裹」(nsloon.app/docs/Node/)—— - -- 也就是说那对引号**确实**能保住逗号。这里仍然按「值里含逗号就整条丢弃」 - -- 处理,是刻意的保守选择:本行的具名参数(sni= / ws-path= / ws-headers=Host:) - -- 一律不带引号,同一行里两种约定混用会让「哪个值被包裹」变成依赖客户端实现 - -- 的行为;统一丢弃最容易验证,代价只是极少见的「密码里带逗号」的节点。 - -- (值里本身带双引号的情况已由 loon_positional 在构造时挡掉。) + -- 位置参数(Loon 的凭据写法)与上面的具名参数不同:它**带双引号**,而 Loon + -- 文档明说「参数值中含有英文逗号时,请使用双引号包裹」(nsloon.app/docs/Node/) + -- —— 也就是说那对引号**确实**能保住逗号。所以这里放行「被引号完整包裹」的值: + -- `Trojan, h, 443, "pa,ss", sni=x.com` 的密码就是 pa,ss。 + -- + -- 判据不是「is_loon」而是「这个值是不是引号包裹的」:loon_positional 只在 + -- Loon 分支里被调用,Surfboard 的 anytls 走的是**裸**位置参数,两者由这个 + -- 判据自动分开,不必在这里再分叉一次。裸值(含加密方式这类不带引号的位置 + -- 参数)仍按「值里含逗号就整条丢弃」处理 —— 它们没有引号语义。 + -- + -- 安全性来自 loon_positional 的两条保证:值里含 `"` 时它直接返回 nil(节点 + -- 已被丢弃,走不到这里),所以引号包裹的值内部不可能出现落单引号 —— + -- parser_surge.split_fields 的「奇数引号回退」分支不会被本行的输出触发。 + -- (本行的具名参数仍然一律不带引号,含逗号的照样丢:Surge 家族的引号语义 + -- 未获文档证据,且解析端不对具名值做 unquote,加了引号回环就断。) for _, v in ipairs(positional) do - if v:find(",", 1, true) then return nil end + if v:find(",", 1, true) and not v:match('^".*"$') then return nil end end for _, v in ipairs(positional) do head_parts[#head_parts + 1] = v end diff --git a/luci-app-substore/tests/anytls_reality_test.lua b/luci-app-substore/tests/anytls_reality_test.lua index 5865699f5..5ef26d0c2 100644 --- a/luci-app-substore/tests/anytls_reality_test.lua +++ b/luci-app-substore/tests/anytls_reality_test.lua @@ -28,6 +28,7 @@ local node = require("substore.node") local parser = require("substore.parser") local output = require("substore.output") local fmts = require("substore.output_formats") +local psurge = require("substore.parser_surge") local passed, failed = 0, 0 @@ -412,23 +413,31 @@ check("anytls form merge keeps reality creds", check("surge_line unknown proto -> nil", fmts.surge_line({ proto = "snell", name = "S", server = "1.2.3.4", port = 443 }) == nil) --- 参数值里的逗号无法用这些格式表达,会把凭据静默截断,整条丢弃。 --- 位置参数同理:Loon 文档确实说「参数值中含有英文逗号时请使用双引号包裹」, --- 也就是说那对引号**能**保住逗号 —— 但本行的具名参数一律不带引号,同一行里 --- 两种约定混用会让行为依赖客户端实现,所以统一按「含逗号就丢弃」处理(保守)。 +-- 参数值里的逗号:**具名**写法无法表达,会把凭据静默截断,整条丢弃。 +-- 位置参数不同 —— Loon 文档明说「参数值中含有英文逗号时请使用双引号包裹」 +-- (nsloon.app/docs/Node/),那对引号**能**保住逗号,而 loon_positional 已经 +-- 无条件把凭据包成了 `"..."`。所以引号包裹的位置参数里的逗号原样保留。 +-- 裸位置参数(Surfboard 的 anytls)没有引号语义,仍按「含逗号就丢弃」处理。 local bad_pw = node.normalize({ proto = "anytls", name = "Bad", server = "1.2.3.4", port = 443, password = "a,b" }) check("surge_line comma in named password -> nil", fmts.surge_line(bad_pw, "surge") == nil) -check("surge_line comma in quoted positional password -> nil", fmts.surge_line(bad_pw, "loon") == nil) +check("surge_line comma in quoted positional password kept", fmts.surge_line(bad_pw, "loon") ~= nil) check("surge_line comma in bare positional password -> nil", fmts.surge_line(bad_pw, "surfboard") == nil) +-- 放行的前提是「能原样回环」:导出的行重新导入必须拿到同一个密码 +-- (先取出字符串再拼接:surge_line 退回 nil 时 `.. nil` 会抛错、吞掉后续断言) +local loon_comma_line = fmts.surge_line(bad_pw, "loon") +local rt_pw = type(loon_comma_line) == "string" + and psurge.parse("[Proxy]\n" .. loon_comma_line .. "\n") or {} +check("loon comma password round-trips", rt_pw[1] and rt_pw[1].password == "a,b") -- 值里含双引号时带引号的位置参数也表达不了(`"pa"ss"` 无法确定切法),同样丢弃 local quote_pw = node.normalize({ proto = "anytls", name = "Q", server = "1.2.3.4", port = 443, password = 'pa"ss' }) check("surge_line double-quote in loon positional password -> nil", fmts.surge_line(quote_pw, "loon") == nil) -- 同样的值在具名写法(Surge)下没有引号语义,仍按原样输出 check("surge_line double-quote in named password kept", fmts.surge_line(quote_pw, "surge") ~= nil) --- Loon 的 vmess / vless 位置参数同样受这条约束 +-- Loon 的 vmess / vless 位置参数同样带引号,含逗号一样能保住 +-- (这里测的是**位置参数这条机制**,不是 uuid 的取值是否合理 —— uuid 实际不会含逗号) local bad_uuid = node.normalize({ proto = "vless", name = "BU", server = "1.2.3.4", port = 443, uuid = "a,b" }) -check("surge_line comma in loon vless uuid -> nil", fmts.surge_line(bad_uuid, "loon") == nil) +check("surge_line comma in loon vless uuid kept", fmts.surge_line(bad_uuid, "loon") ~= nil) -- 具名写法(Surge 家族)没有引号语义,含逗号的 uuid 一样按「值里含逗号」丢弃 check("surge_line comma in named vless uuid -> nil", fmts.surge_line(bad_uuid, "surfboard") == nil) -- 双引号则相反:具名写法原样保留,Loon 的带引号位置参数表达不了 diff --git a/luci-app-substore/tests/output_formats_test.lua b/luci-app-substore/tests/output_formats_test.lua index a590f0b61..e3c8b5af6 100644 --- a/luci-app-substore/tests/output_formats_test.lua +++ b/luci-app-substore/tests/output_formats_test.lua @@ -225,12 +225,18 @@ check("surge hysteria2 named", fmts.surge_line(hy_node, "surge"):find("password= check("loon hysteria2 positional", fmts.surge_line(hy_node, "loon"):find('hysteria2, 1.1.1.1, 443, "pw"', 1, true) ~= nil) --- (e) 值里含英文逗号:Loon 的引号按文档确实能保住逗号,本实现仍按「整条丢弃」 --- 处理(具名参数不带引号,同一行混用两种约定会让「哪个值被包裹」变成依赖客户端 --- 实现的行为)。这里钉住这个保守选择,避免日后被无意改成半截输出。 +-- (e) 值里含英文逗号:Loon 的位置参数带双引号,而文档明说「参数值中含有英文逗号时 +-- 请使用双引号包裹」(nsloon.app/docs/Node/)—— 那对引号**能**保住逗号,所以 +-- 引号包裹的位置参数放行。具名参数(Surge 家族)没有引号语义,仍整条丢弃; +-- Surfboard 的 anytls 是**裸**位置参数,同样丢弃(见 anytls_reality_test.lua)。 local ss_comma = { proto = "shadowsocks", name = "S", server = "1.1.1.1", port = 8388, method = "aes-256-gcm", password = "pa,ss" } -check("loon comma password drops node", fmts.surge_line(ss_comma, "loon") == nil) +local ss_comma_line = fmts.surge_line(ss_comma, "loon") +-- 用 type() 兜一下再 :find:surge_line 退回 nil 时直接 :find 会抛错、把整个 +-- 文件后面的断言全吞掉 —— 那样反向验证只能看到「崩了」,看不到是哪条行为变了。 +check("loon comma password kept (quoted positional)", + type(ss_comma_line) == "string" and ss_comma_line:find('aes-256-gcm, "pa,ss"', 1, true) ~= nil) +check("surge comma password drops node", fmts.surge_line(ss_comma, "surge") == nil) -- ---------- Loon 输出 → 导入回环 ---------- -- 生成端与解析端必须成对改动:只改生成端的话,导出的 Loon 配置再导入回来会静默 @@ -245,6 +251,11 @@ local rt_ss = loon_roundtrip(ss_node) check("loon rt ss method", rt_ss and rt_ss.method == "aes-256-gcm") check("loon rt ss password", rt_ss and rt_ss.password == "pw") +-- 含逗号的密码同样要能原样回环 —— 这是「放行」的前提(见上面的 (e)) +local rt_comma = loon_roundtrip(ss_comma) +check("loon rt comma password", rt_comma and rt_comma.password == "pa,ss") +check("loon rt comma method", rt_comma and rt_comma.method == "aes-256-gcm") + local rt_hy = loon_roundtrip(hy_node) check("loon rt hysteria2 password", rt_hy and rt_hy.password == "pw") check("loon rt hysteria2 security", rt_hy and rt_hy.security == "tls") diff --git a/luci-app-easymesh/meta-packages/mbedtls/Makefile b/mbedtls/Makefile similarity index 100% rename from luci-app-easymesh/meta-packages/mbedtls/Makefile rename to mbedtls/Makefile diff --git a/luci-app-easymesh/meta-packages/openssl/Makefile b/openssl/Makefile similarity index 100% rename from luci-app-easymesh/meta-packages/openssl/Makefile rename to openssl/Makefile diff --git a/luci-app-easymesh/meta-packages/wolfssl/Makefile b/wolfssl/Makefile similarity index 100% rename from luci-app-easymesh/meta-packages/wolfssl/Makefile rename to wolfssl/Makefile