From 4c053b8bdbeb1cb44b7861ea60623cb04e70a503 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 29 Sep 2026 22:47:57 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=88=20Sync=202026-09-29=2022:47:56?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luci-app-homeproxy-pro/Makefile | 2 +- .../homeproxy-pro/scripts/generator/route.uc | 4 +- luci-app-homeproxy/Makefile | 2 +- luci-app-homeproxy/README.md | 2 +- .../etc/homeproxy/scripts/generate_client.uc | 4 +- luci-app-substore/CHANGELOG.md | 59 +++++++ luci-app-substore/Makefile | 4 +- luci-app-substore/README.en.md | 6 +- luci-app-substore/README.md | 6 +- luci-app-substore/docs/INSTALL.md | 6 +- .../root/usr/bin/substore-cron.sh | 24 ++- .../lua/luci/controller/admin/substore.lua | 122 ++++++++------ .../usr/lib/lua/luci/view/substore/combo.htm | 6 +- .../usr/lib/lua/luci/view/substore/form.htm | 12 +- .../lib/lua/luci/view/substore/local_form.htm | 14 +- .../lib/lua/luci/view/substore/node_edit.htm | 8 +- .../usr/lib/lua/luci/view/substore/nodes.htm | 41 ++--- .../usr/lib/lua/luci/view/substore/output.htm | 6 +- .../lua/luci/view/substore/subscriptions.htm | 21 ++- .../root/usr/share/substore/core.lua | 33 ++-- .../root/usr/share/substore/http.lua | 75 ++++++++- .../root/usr/share/substore/node.lua | 13 +- .../share/substore/output_wireguard_conf.lua | 57 +++++-- .../tests/controller_local_test.lua | 159 ++++++++++++++++++ luci-app-substore/tests/cron_result_test.sh | 82 +++++++++ luci-app-substore/tests/http_proxy_test.lua | 105 ++++++++++++ .../tests/node_extended_test.lua | 55 ++++++ .../tests/template_escape_test.lua | 157 +++++++++++++++++ .../tests/wireguard_conf_test.lua | 87 ++++++++++ 29 files changed, 1015 insertions(+), 157 deletions(-) create mode 100644 luci-app-substore/tests/controller_local_test.lua create mode 100755 luci-app-substore/tests/cron_result_test.sh create mode 100644 luci-app-substore/tests/template_escape_test.lua diff --git a/luci-app-homeproxy-pro/Makefile b/luci-app-homeproxy-pro/Makefile index 54de3d01f..049d7a807 100644 --- a/luci-app-homeproxy-pro/Makefile +++ b/luci-app-homeproxy-pro/Makefile @@ -23,7 +23,7 @@ LUCI_DEPENDS:= \ PKG_NAME:=luci-app-homeproxy-pro PKG_VERSION:=28.9.1.14 -PKG_RELEASE:=4 +PKG_RELEASE:=5 # Only files the package actually ships belong here. The previous list named # four paths that exist nowhere in the tree - certs/ and ruleset/ are created at diff --git a/luci-app-homeproxy-pro/root/etc/homeproxy-pro/scripts/generator/route.uc b/luci-app-homeproxy-pro/root/etc/homeproxy-pro/scripts/generator/route.uc index bb6ff415a..1b3b790ac 100644 --- a/luci-app-homeproxy-pro/root/etc/homeproxy-pro/scripts/generator/route.uc +++ b/luci-app-homeproxy-pro/root/etc/homeproxy-pro/scripts/generator/route.uc @@ -193,7 +193,7 @@ function build_route_proxy(config, dm, ctx, direct_overrides) { type: 'remote', tag: 'geoip-cn', format: 'binary', - url: 'https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs', + url: 'https://gh-proxy.com/raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs', update_interval: '24h', download_detour: 'main-out' }); @@ -201,7 +201,7 @@ function build_route_proxy(config, dm, ctx, direct_overrides) { type: 'remote', tag: 'geosite-cn', format: 'binary', - url: 'https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs', + url: 'https://gh-proxy.com/raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs', update_interval: '24h', download_detour: 'main-out' }); diff --git a/luci-app-homeproxy/Makefile b/luci-app-homeproxy/Makefile index 2c4c555d7..a710a90f3 100644 --- a/luci-app-homeproxy/Makefile +++ b/luci-app-homeproxy/Makefile @@ -23,7 +23,7 @@ LUCI_DEPENDS:= \ PKG_NAME:=luci-app-homeproxy PKG_VERSION:=27.919.1.14 -PKG_RELEASE:=19 +PKG_RELEASE:=20 define Package/luci-app-homeproxy/conffiles /etc/config/homeproxy diff --git a/luci-app-homeproxy/README.md b/luci-app-homeproxy/README.md index a15979b2a..8c2eec1ab 100644 --- a/luci-app-homeproxy/README.md +++ b/luci-app-homeproxy/README.md @@ -7,7 +7,7 @@ **The modern ImmortalWrt proxy platform for ARM64 / AMD64** -基于 sing-box 1.14 内核的现代代理平台 — 简洁、高效、开箱即用。 +本项目发版到R13后将不再频繁维护,除非存在重大修复。日常只推进“luci-app-homeproxy-pro”版本 --- diff --git a/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc b/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc index 61ee004f6..0f7a800f0 100755 --- a/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc +++ b/luci-app-homeproxy/root/etc/homeproxy/scripts/generate_client.uc @@ -1070,12 +1070,12 @@ if (!isEmpty(main_node)) { { tag: 'geoip-cn', path: HP_DIR + '/resources/geoip_cn.srs', - url: 'https://raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs' + url: 'https://gh-proxy.com/raw.githubusercontent.com/SagerNet/sing-geoip/rule-set/geoip-cn.srs' }, { tag: 'geosite-cn', path: HP_DIR + '/resources/geosite_cn.srs', - url: 'https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs' + url: 'https://gh-proxy.com/raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-geolocation-cn.srs' } ]; diff --git a/luci-app-substore/CHANGELOG.md b/luci-app-substore/CHANGELOG.md index daeb85924..042a33ae7 100644 --- a/luci-app-substore/CHANGELOG.md +++ b/luci-app-substore/CHANGELOG.md @@ -2,6 +2,65 @@ All notable changes to this project will be documented in this file. +## [2.5.0-r1] - 订阅可靠性、错误反馈与 WireGuard 去重修复 + +- **修复严重缺陷(订阅更新可能「看起来成功其实失败」)**:`core.sync` 失败时是 + 「返回 `nil, err`」而**不是**抛异常,而调用方只判断了 `pcall` 的第一层返回值。 + `pcall` 返回 `true` 只说明没有抛错,第二个返回值才是 `sync` 自身的结果—— + 于是「同步返回 `nil, err`」被统计成**成功**。 + - `root/usr/bin/substore-cron.sh`:改为 `local ok, res, err = pcall(core.sync, id)`, + 并要求 `ok and res` 才算成功;失败时打印真实原因。同时把脚本输出同时写 stdout 与 + syslog(原先只进 syslog,cron 邮件里看不到) + - `root/usr/lib/lua/luci/controller/admin/substore.lua`:`action_update` 同样处理两层结果 +- **修复严重缺陷(代理静默失效,属 silent fallback)**: + - `core.sync` 原先在「代理已启用但代理地址无效」时只记一条日志就**直连下载**, + 用户会以为流量走了代理、实际暴露真实 IP。现改为**明确失败**并把原因写入订阅状态 + - wget 后端原先在遇到它不支持的代理协议(`socks*`)时**丢掉代理继续直连**。 + 现改为明确报错并提示安装 curl 或改用 http 代理(busybox wget 只能通过 + `http_proxy` / `https_proxy` 环境变量使用 http(s) 代理) +- **修复严重缺陷(wget 后端重定向绕过 SSRF 预检)**:curl 路径逐跳校验重定向目标, + wget 路径**完全不校验**,可被重定向到 `127.0.0.1` / 内网而绕过 `check_public`。 + 现 wget 改用 `-S` 输出响应头日志,由新增的 `http.validate_redirect_chain` + 按出现顺序解析整条重定向链并逐跳复检,任一跳不安全即整体失败并**丢弃响应体**。 + 另修复协议相对地址(`//host/path`)被误当成同主机路径而漏检的问题 +- **修复严重缺陷(界面失败无反馈)**:订阅的新建 / 保存 / 本地订阅新建 / 保存 + 失败时,控制器只静默跳回列表页,用户看到的是「什么都没发生」,与成功无法区分。 + 现失败原因经 `?err=` 回传到列表页并渲染为可见的错误提示 +- **修复严重缺陷(WireGuard 节点被错误去重合并)**:去重键为 `proto+server+port`, + 而同一 endpoint 上的**不同 peer 公钥是不同节点**,会被错误合并而丢节点。 + 现 WireGuard / `wg` 节点的去重键并入 peer 公钥(兼容 `public-key` / `public_key` / + `peer-public-key` / `peer_public_key` 四种写法);其余协议去重行为**完全不变** +- **修复严重缺陷(多个 WireGuard 节点被拼进一个 `.conf`)**:一个 `.conf` 文件只能包含 + 一个 `[Interface]`,拼接会产生客户端无法导入(或只取首段)的畸形配置。 + 现多于一个 WireGuard 节点时**明确报错**(错误信息含节点数与「一条隧道」提示), + 而不是静默拼接 +- **修复 AmneziaWG `.conf` 导出键名靠猜测**:原先用「首字母大写」由内部键名推导 `.conf` + 键名,多词键会被写错(`header-protection-key` → `Header-protection-key`, + 正确为 `HeaderProtectionKey`),未知键可能让客户端拒绝整份配置。 + 现改为显式映射表,只输出能**确定**键名的键(`Jc/Jmin/Jmax/S1–S4/H1–H4/I1–I5/J1–J3/Itime`), + 映射不到的键一律不输出;已支持键集合零变化 +- **修复模板注入(HTML / JS)**:7 个模板把用户可控数据(订阅名、URL、代理、节点字段、 + 解析错误信息)直接以 `<%= %>` 原样输出。现按上下文分别转义: + HTML 用 `luci.util.pcdata`,注入 JS 的字符串用 `json_encode`(并转义 ` 2.1.3),PKG_RELEASE 重置为 1。 -PKG_VERSION:=2.4.0 -PKG_RELEASE:=8 +PKG_VERSION:=2.5.0 +PKG_RELEASE:=9 LUCI_DEPENDS:=+luci-lua-runtime +luci-compat diff --git a/luci-app-substore/README.en.md b/luci-app-substore/README.en.md index 29662f107..a4ea8ce72 100644 --- a/luci-app-substore/README.en.md +++ b/luci-app-substore/README.en.md @@ -93,18 +93,18 @@ group them, then re-emit them in a format your client can consume. ## Installation > The version in the package name must match `PKG_VERSION` / `PKG_RELEASE` in the -> [Makefile](Makefile) (currently `2.4.0-r2`). +> [Makefile](Makefile) (currently `2.5.0-r1`). opkg (OpenWrt / ImmortalWrt 24.10 and earlier): ```bash -opkg install luci-app-substore-2.4.0-r2.ipk +opkg install luci-app-substore-2.5.0-r1.ipk ``` apk (OpenWrt / ImmortalWrt 25.12+): ```bash -apk add --allow-untrusted luci-app-substore-2.4.0-r2.apk +apk add --allow-untrusted luci-app-substore-2.5.0-r1.apk ``` Then open LuCI: **Services → Subscriptions**. diff --git a/luci-app-substore/README.md b/luci-app-substore/README.md index 9283ada9d..a63b8f494 100644 --- a/luci-app-substore/README.md +++ b/luci-app-substore/README.md @@ -80,18 +80,18 @@ ## 安装 > 包名中的版本号必须与 [Makefile](Makefile) 的 `PKG_VERSION` / `PKG_RELEASE` 保持一致 -> (当前 `2.4.0-r2`)。 +> (当前 `2.5.0-r1`)。 opkg(OpenWrt / ImmortalWrt 24.10 及更早): ```bash -opkg install luci-app-substore-2.4.0-r2.ipk +opkg install luci-app-substore-2.5.0-r1.ipk ``` apk(OpenWrt / ImmortalWrt 25.12+): ```bash -apk add --allow-untrusted luci-app-substore-2.4.0-r2.apk +apk add --allow-untrusted luci-app-substore-2.5.0-r1.apk ``` 然后在 LuCI 菜单打开:**服务 → 订阅**。 diff --git a/luci-app-substore/docs/INSTALL.md b/luci-app-substore/docs/INSTALL.md index 2d0c179d7..39f22dfde 100644 --- a/luci-app-substore/docs/INSTALL.md +++ b/luci-app-substore/docs/INSTALL.md @@ -3,18 +3,18 @@ > NOTE: stage-0 skeleton has not yet been installed/verified on a target device. > This document will be updated once installation is validated. > -> 包名中的版本号需与 Makefile 的 `PKG_VERSION` / `PKG_RELEASE` 保持同步(当前 2.4.0-r2)。 +> 包名中的版本号需与 Makefile 的 `PKG_VERSION` / `PKG_RELEASE` 保持同步(当前 2.5.0-r1)。 ## Install (opkg — OpenWrt / ImmortalWrt 24.10 及更早) ```bash -opkg install luci-app-substore-2.4.0-r2.ipk +opkg install luci-app-substore-2.5.0-r1.ipk ``` ## Install (apk — OpenWrt / ImmortalWrt 25.12+) ```bash -apk add --allow-untrusted luci-app-substore-2.4.0-r2.apk +apk add --allow-untrusted luci-app-substore-2.5.0-r1.apk ``` Refresh LuCI: diff --git a/luci-app-substore/root/usr/bin/substore-cron.sh b/luci-app-substore/root/usr/bin/substore-cron.sh index 51ef9be0e..5e6c85ae5 100755 --- a/luci-app-substore/root/usr/bin/substore-cron.sh +++ b/luci-app-substore/root/usr/bin/substore-cron.sh @@ -3,7 +3,8 @@ # 用法:substore-cron.sh [订阅ID](不传则更新全部已启用订阅) # 注意:显式设置 package.path,确保独立 cron 进程能找到 /usr/lib/lua 下的模块 -DATA_DIR="/etc/substore" +# 数据目录可被环境变量覆盖,仅用于测试;生产环境仍为 /etc/substore +DATA_DIR="${SUBSTORE_DATA_DIR:-/etc/substore}" LIST_FILE="$DATA_DIR/subscriptions.json" SUB_ID="${1:-}" LUA_BIN="" @@ -23,19 +24,24 @@ fi [ -f "$LIST_FILE" ] || exit 0 export SUB_ID +OUT=$( LUA_PATH="/usr/lib/lua/?.lua;/usr/share/lua/?.lua;${LUA_PATH:-}" \ "$LUA_BIN" -e ' local core = require("substore.core") local sub_id = os.getenv("SUB_ID") local ok_count, fail_count = 0, 0 +-- core.sync 失败时是「返回 nil, err」而非抛异常,因此 pcall 必须处理两层结果: +-- pcall 返回 true 只说明没有抛错,第二个返回值才是 sync 自身的结果。 +-- 只判断第一层会把「sync 返回 nil, err」统计成成功。 local function sync_one(id) - local ok, err = pcall(function() return core.sync(id) end) - if ok then + local ok, res, err = pcall(core.sync, id) + if ok and res then ok_count = ok_count + 1 else fail_count = fail_count + 1 - io.stderr:write("Failed sync " .. tostring(id) .. ": " .. tostring(err) .. "\n") + local reason = ok and err or res + io.stderr:write("Failed sync " .. tostring(id) .. ": " .. tostring(reason) .. "\n") end end @@ -47,4 +53,12 @@ else end end io.stdout:write(string.format("substore cron done: %d ok, %d failed\n", ok_count, fail_count)) -' 2>&1 | logger -t luci-app-substore +' 2>&1 +) + +# 输出到 stdout(cron 会按需邮件/记录),同时写 syslog +printf '%s\n' "$OUT" +if command -v logger >/dev/null 2>&1; then + printf '%s\n' "$OUT" | logger -t luci-app-substore +fi +exit 0 diff --git a/luci-app-substore/root/usr/lib/lua/luci/controller/admin/substore.lua b/luci-app-substore/root/usr/lib/lua/luci/controller/admin/substore.lua index f1cbd9d84..00a889c9d 100644 --- a/luci-app-substore/root/usr/lib/lua/luci/controller/admin/substore.lua +++ b/luci-app-substore/root/usr/lib/lua/luci/controller/admin/substore.lua @@ -2,9 +2,15 @@ module("luci.controller.admin.substore", package.seeall) -local function back_to_list() +-- 返回列表页。err 非空时把错误带到列表页显示(§18:失败必须让用户看见, +-- 不能「失败了却看起来像成功」)。沿用 LuCI 既有的 query + 模板渲染,不引入新 framework。 +local function back_to_list(err) local http = require("luci.http") - http.redirect(luci.dispatcher.build_url("admin", "services", "substore", "list")) + local url = luci.dispatcher.build_url("admin", "services", "substore", "list") + if err ~= nil and tostring(err) ~= "" then + url = url .. "?err=" .. luci.util.urlencode(tostring(err)) + end + http.redirect(url) end function index() @@ -84,18 +90,20 @@ function action_create() local proxy_enable = http.formvalue("proxy_enable") or "0" if proxy_enable ~= "1" then proxy_enable = "0" end local proxy = (http.formvalue("proxy") or ""):gsub("^%s+", ""):gsub("%s+$", "") - if name ~= "" and url ~= "" then - local cron_enable, cron_time = read_cron_fields() - local rules = read_rules_fields() - core.add(name, url, { - proxy_enable = proxy_enable, proxy = proxy, - cron_enable = cron_enable, cron_time = cron_time, - rules_enable = rules.rules_enable, proto_filter = rules.proto_filter, - keyword_include = rules.keyword_include, keyword_exclude = rules.keyword_exclude, - dedup = rules.dedup, rename_map = rules.rename_map, - }) - core.write_cron() + if name == "" or url == "" then + return back_to_list("名称和 URL 不能为空") end + local cron_enable, cron_time = read_cron_fields() + local rules = read_rules_fields() + local id, err = core.add(name, url, { + proxy_enable = proxy_enable, proxy = proxy, + cron_enable = cron_enable, cron_time = cron_time, + rules_enable = rules.rules_enable, proto_filter = rules.proto_filter, + keyword_include = rules.keyword_include, keyword_exclude = rules.keyword_exclude, + dedup = rules.dedup, rename_map = rules.rename_map, + }) + if not id then return back_to_list(err or "创建订阅失败") end + core.write_cron() end back_to_list() end @@ -110,18 +118,21 @@ function action_save() local proxy_enable = http.formvalue("proxy_enable") or "0" if proxy_enable ~= "1" then proxy_enable = "0" end local proxy = (http.formvalue("proxy") or ""):gsub("^%s+", ""):gsub("%s+$", "") - if name ~= "" and url ~= "" then - local cron_enable, cron_time = read_cron_fields() - local rules = read_rules_fields() - core.save_meta(id, { - name = name, url = url, proxy_enable = proxy_enable, proxy = proxy, - cron_enable = cron_enable, cron_time = cron_time, - rules_enable = rules.rules_enable, proto_filter = rules.proto_filter, - keyword_include = rules.keyword_include, keyword_exclude = rules.keyword_exclude, - dedup = rules.dedup, rename_map = rules.rename_map, - }) - core.write_cron() + if id == "" then return back_to_list("缺少订阅 ID") end + if name == "" or url == "" then + return back_to_list("名称和 URL 不能为空") end + local cron_enable, cron_time = read_cron_fields() + local rules = read_rules_fields() + local ok, err = core.save_meta(id, { + name = name, url = url, proxy_enable = proxy_enable, proxy = proxy, + cron_enable = cron_enable, cron_time = cron_time, + rules_enable = rules.rules_enable, proto_filter = rules.proto_filter, + keyword_include = rules.keyword_include, keyword_exclude = rules.keyword_exclude, + dedup = rules.dedup, rename_map = rules.rename_map, + }) + if not ok then return back_to_list(err or "保存失败") end + core.write_cron() end back_to_list() end @@ -134,15 +145,17 @@ function action_local_create() local content = http.formvalue("content") or "" local local_mode = http.formvalue("local_mode") or "text" local rules = read_rules_fields() - if name ~= "" and content ~= "" then - core.add_local(name, content, local_mode, { - rules_enable = rules.rules_enable, - proto_filter = rules.proto_filter, - keyword_include = rules.keyword_include, - keyword_exclude = rules.keyword_exclude, - dedup = rules.dedup, - }) - end + -- §19:空名称 / 空内容必须明确报错,不能无声创建无效订阅 + if name == "" then return back_to_list("名称不能为空") end + if content == "" then return back_to_list("订阅内容不能为空") end + local id, err = core.add_local(name, content, local_mode, { + rules_enable = rules.rules_enable, + proto_filter = rules.proto_filter, + keyword_include = rules.keyword_include, + keyword_exclude = rules.keyword_exclude, + dedup = rules.dedup, + }) + if not id then return back_to_list(err or "创建本地订阅失败") end end back_to_list() end @@ -156,19 +169,23 @@ function action_local_save() local content = http.formvalue("content") or "" local local_mode = http.formvalue("local_mode") or "text" local rules = read_rules_fields() - if id ~= "" and name ~= "" and content ~= "" then - core.save_meta(id, { - name = name, - raw_content = content, - local_mode = local_mode, - rules_enable = rules.rules_enable, - proto_filter = rules.proto_filter, - keyword_include = rules.keyword_include, - keyword_exclude = rules.keyword_exclude, - dedup = rules.dedup, - }) - core.sync(id) - end + if id == "" then return back_to_list("缺少订阅 ID") end + if name == "" then return back_to_list("名称不能为空") end + if content == "" then return back_to_list("订阅内容不能为空") end + local ok, err = core.save_meta(id, { + name = name, + raw_content = content, + local_mode = local_mode, + rules_enable = rules.rules_enable, + proto_filter = rules.proto_filter, + keyword_include = rules.keyword_include, + keyword_exclude = rules.keyword_exclude, + dedup = rules.dedup, + }) + if not ok then return back_to_list(err or "保存失败") end + -- 解析失败会写进 meta.error(列表页 Status 列可见),此处再明确提示一次 + local sok, serr = core.sync(id) + if not sok then return back_to_list(serr or "解析订阅内容失败") end end back_to_list() end @@ -315,12 +332,15 @@ function action_update() -- local subscription does not support auto update return end - -- pcall fallback: parse or write error will not 500 the page, error saved to list status - local ok, err = pcall(function() - return core.sync(id) - end) + -- pcall 只保证「不抛异常」;core.sync 的失败是「返回 nil, err」而非抛错, + -- 因此必须同时检查两层结果,否则失败永远不会写回列表状态。 + local ok, res, err = pcall(core.sync, id) if not ok then - core.save_meta(id, { error = tostring(err), last_update = os.time() }) + -- 抛异常:第二个返回值是错误信息 + core.save_meta(id, { error = tostring(res), last_update = os.time() }) + elseif not res then + -- 正常返回但失败:第三个返回值是错误信息 + core.save_meta(id, { error = tostring(err or "更新失败"), last_update = os.time() }) end end back_to_list() diff --git a/luci-app-substore/root/usr/lib/lua/luci/view/substore/combo.htm b/luci-app-substore/root/usr/lib/lua/luci/view/substore/combo.htm index eee34b3e6..d89612a0c 100644 --- a/luci-app-substore/root/usr/lib/lua/luci/view/substore/combo.htm +++ b/luci-app-substore/root/usr/lib/lua/luci/view/substore/combo.htm @@ -27,7 +27,7 @@
- + "/>
@@ -52,11 +52,11 @@
">
- +
- +
diff --git a/luci-app-substore/root/usr/lib/lua/luci/view/substore/form.htm b/luci-app-substore/root/usr/lib/lua/luci/view/substore/form.htm index 8ab34b174..274d11237 100644 --- a/luci-app-substore/root/usr/lib/lua/luci/view/substore/form.htm +++ b/luci-app-substore/root/usr/lib/lua/luci/view/substore/form.htm @@ -38,11 +38,11 @@
- + "/>
- + " style="width:60%"/>
@@ -51,7 +51,7 @@
"> - + " style="width:60%"/>
通过代理下载订阅(留空则不使用),支持 http:// 或 socks5:// 地址,如 socks5://192.168.5.1:1080
@@ -78,11 +78,11 @@
">
- +
- +
@@ -99,7 +99,7 @@ <% if traffic_str then %> | <%:Remaining traffic:%> <%=traffic_str%><% end %> <% if time_str then %> | <%:Remaining time:%> <%=time_str%><% end %> | <%:Last updated:%> <%=os.date("%Y-%m-%d %H:%M", it.last_update)%> - <% if it.error and it.error ~= "" then %> | <%=it.error%><% end %> + <% if it.error and it.error ~= "" then %> | <%=luci.util.pcdata(it.error)%><% end %>
<% end %> diff --git a/luci-app-substore/root/usr/lib/lua/luci/view/substore/local_form.htm b/luci-app-substore/root/usr/lib/lua/luci/view/substore/local_form.htm index f86da27e5..ae3d801b3 100644 --- a/luci-app-substore/root/usr/lib/lua/luci/view/substore/local_form.htm +++ b/luci-app-substore/root/usr/lib/lua/luci/view/substore/local_form.htm @@ -14,6 +14,10 @@ -- 注入 JS 的初始内容:JSON 字符串字面量,转义 "

<%=is_edit and luci.i18n.translate("Edit local subscription") or luci.i18n.translate("Add local subscription")%>

@@ -25,7 +29,7 @@
- + "/>
@@ -59,11 +63,11 @@
">
- +
- +
@@ -75,7 +79,7 @@ <%:Nodes:%> <%=it.node_count or 0%> | <%:Last updated:%> <%=os.date("%Y-%m-%d %H:%M", it.last_update)%> - <% if it.error and it.error ~= "" then %> | <%=it.error%><% end %> + <% if it.error and it.error ~= "" then %> | <%=luci.util.pcdata(it.error)%><% end %>
<% end %> @@ -89,7 +93,7 @@