From 4bf1fb0640b836302c07bd80039b44a7879a7cdf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 16 Aug 2026 23:43:42 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8D=95=20Sync=202026-08-16=2023:43:42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- luci-app-passwall/Makefile | 2 +- .../luasrc/controller/passwall.lua | 41 +- .../cbi/passwall/client/socks_config.lua | 1 + .../model/cbi/passwall/server/type/ray.lua | 35 +- .../cbi/passwall/server/type/sing-box.lua | 30 + .../model/cbi/passwall/server/user_config.lua | 14 + luci-app-passwall/luasrc/passwall/api.lua | 89 +- .../luasrc/passwall/server_app.lua | 8 +- .../luasrc/passwall/util_sing-box.lua | 30 +- .../luasrc/passwall/util_xray.lua | 14 + .../view/passwall/server/server_wireguard.htm | 28 + luci-app-passwall/po/zh-cn/passwall.po | 9 + .../root/usr/share/passwall/app.sh | 2 +- .../usr/share/passwall/socks_auto_switch.sh | 4 +- .../root/usr/share/passwall/test.sh | 4 +- luci-app-passwall2/Makefile | 2 +- .../cbi/passwall2/server/user_config.lua | 2 +- .../references/aurora-budgets.md | 20 +- .../references/measuring.md | 32 + .../scripts/bench-router.mjs | 567 +++++++++++ luci-theme-aurora/.dev/docs/DEVELOPMENT.md | 2 + luci-theme-aurora/.dev/docs/router.md | 522 +++++++++++ luci-theme-aurora/.dev/src/media/_layout.css | 32 + .../.dev/src/resource/menu-aurora.js | 124 ++- .../src/resource/patches/admin-status-logs.js | 72 +- .../.dev/src/resource/router-aurora.js | 879 ++++++++++++++++++ .../.dev/tests/build-performance.test.js | 20 +- .../.dev/tests/navigation-rendering.test.js | 8 + luci-theme-aurora/.dev/tests/router.test.js | 381 ++++++++ luci-theme-aurora/.dev/vite.config.ts | 1 + luci-theme-aurora/CLAUDE.md | 2 +- luci-theme-aurora/Makefile | 4 +- luci-theme-aurora/README.md | 3 + luci-theme-aurora/README_zh.md | 3 + .../htdocs/luci-static/aurora/main.css | 2 +- .../aurora/patches/admin-status-logs.js | 2 +- .../luci-static/resources/menu-aurora.js | 2 +- .../luci-static/resources/router-aurora.js | 1 + .../ucode/template/themes/aurora/footer.ut | 2 +- .../ucode/template/themes/aurora/header.ut | 37 +- 40 files changed, 2889 insertions(+), 144 deletions(-) create mode 100644 luci-app-passwall/luasrc/view/passwall/server/server_wireguard.htm create mode 100644 luci-theme-aurora/.claude/skills/aurora-performance/scripts/bench-router.mjs create mode 100644 luci-theme-aurora/.dev/docs/router.md create mode 100644 luci-theme-aurora/.dev/src/resource/router-aurora.js create mode 100644 luci-theme-aurora/.dev/tests/router.test.js create mode 100644 luci-theme-aurora/htdocs/luci-static/resources/router-aurora.js diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index b24551153..bf062c809 100644 --- a/luci-app-passwall/Makefile +++ b/luci-app-passwall/Makefile @@ -8,7 +8,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall PKG_VERSION:=26.8.12 -PKG_RELEASE:=223 +PKG_RELEASE:=224 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua index 6cff27e72..582660150 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -124,6 +124,7 @@ function index() entry({"admin", "services", appname, "geo_view"}, call("geo_view")).leaf = true entry({"admin", "services", appname, "fetch_certsha256"}, call("fetch_certsha256")).leaf = true + entry({"admin", "services", appname, "gen_wireguard_key"}, call("gen_wireguard_key")).leaf = true end local function http_write_json(content) @@ -247,7 +248,7 @@ function gen_client_config() end function get_now_use_node() - local path = "/tmp/etc/passwall/acl/default" + local path = api.TMP_PATH .. "/acl/default" local e = {} local tcp_node = api.get_cache_var("ACL_GLOBAL_TCP_node") if tcp_node then @@ -263,7 +264,7 @@ end function get_redir_log() local name = http.formvalue("name") local proto = http.formvalue("proto"):upper() - local path = "/tmp/etc/passwall/acl/" .. name + local path = api.TMP_PATH .. "/acl/" .. name local function alert(msg) http.write(string.format("", i18n.translate(msg))) @@ -280,14 +281,14 @@ function get_redir_log() local acl_udp = uci_get(name, "udp_node") or "nil" local global_enabled = uci_get("@global[0]", "enabled") == "1" if proto == "TCP" and acl_tcp == global_tcp and global_enabled then - path = "/tmp/etc/passwall/acl/default" + path = api.TMP_PATH .. "/acl/default" if uci_get("@global[0]", "log_tcp") ~= "1" then alert("The access control node is the same as the global node. Please enable global logging.") return end end if proto == "UDP" and acl_udp == global_udp and global_enabled then - path = "/tmp/etc/passwall/acl/default" + path = api.TMP_PATH .. "/acl/default" if uci_get("@global[0]", "log_udp") ~= "1" then alert("The access control node is the same as the global node. Please enable global logging.") return @@ -309,7 +310,7 @@ end function get_socks_log() local name = http.formvalue("name") - local path = "/tmp/etc/passwall/" .. name .. ".log" + local path = api.TMP_PATH .. "/" .. name .. ".log" if fs.access(path) then local content = luci.sys.exec("cat ".. path) content = content:gsub("\n", "
") @@ -321,12 +322,12 @@ end function get_chinadns_log() local flag = http.formvalue("flag") - local path = "/tmp/etc/passwall/acl/" .. flag .. "/chinadns_ng.log" + local path = api.TMP_PATH .. "/acl/" .. flag .. "/chinadns_ng.log" if flag ~= "default" then local global_tcp = uci_get("@global[0]", "tcp_node") or "nil" local acl_tcp = uci_get(flag, "tcp_node") or "nil" if acl_tcp == global_tcp and uci_get("@global[0]", "enabled") == "1" then - path = "/tmp/etc/passwall/acl/default/chinadns_ng.log" + path = api.TMP_PATH .. "/acl/default/chinadns_ng.log" if uci_get("@global[0]", "log_chinadns_ng") ~= "1" then http.write(string.format("", i18n.translate("The access control node is the same as the global node. Please enable global logging."))) return @@ -432,31 +433,31 @@ function index_status() local dns_shunt = uci_get("@global[0]", "dns_shunt") or "dnsmasq" if dns_shunt == "smartdns" then local port = api.get_cache_var("SMARTDNS_LOCAL_PORT") or 0 - e.dns_mode_status = (port ~= 0) and luci.sys.call(string.format("netstat -apn | grep ':%s ' >/dev/null", port)) == 0 or false + e.dns_mode_status = (port ~= 0) and luci.sys.call("netstat -apn | grep ':%s ' >/dev/null" % port) == 0 or false elseif dns_shunt == "chinadns-ng" then - e.dns_mode_status = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '/tmp/etc/passwall/bin/' | grep 'default' | grep 'chinadns_ng' >/dev/null") == 0 + e.dns_mode_status = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/bin/' | grep 'default' | grep 'chinadns_ng' >/dev/null" % api.TMP_PATH) == 0 else e.dns_mode_status = luci.sys.call("netstat -apn | grep ':15353 ' >/dev/null") == 0 end e.haproxy_status = "-1" if api.is_finded("haproxy") then - e.haproxy_status = (luci.sys.call(string.format("/bin/busybox top -bn1 | grep -v grep | grep '%s/bin/' | grep haproxy >/dev/null", appname)) == 0) and "0" or "1" + e.haproxy_status = (luci.sys.call("/bin/busybox top -bn1 | grep -v grep | grep '%s/bin/' | grep haproxy >/dev/null" % appname) == 0) and "0" or "1" end - e["tcp_node_status"] = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '/tmp/etc/passwall/bin/' | grep 'default' | grep 'TCP' >/dev/null") == 0 + e["tcp_node_status"] = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/bin/' | grep 'default' | grep 'TCP' >/dev/null" % api.TMP_PATH) == 0 if (uci_get("@global[0]", "udp_node") or "nil") == "tcp" then e["udp_node_status"] = e["tcp_node_status"] else - e["udp_node_status"] = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '/tmp/etc/passwall/bin/' | grep 'default' | grep 'UDP' >/dev/null") == 0 + e["udp_node_status"] = luci.sys.call("/bin/busybox top -bn1 | grep -v 'grep' | grep '%s/bin/' | grep 'default' | grep 'UDP' >/dev/null" % api.TMP_PATH) == 0 end http_write_json(e) end function haproxy_status() local e = {} - e["status"] = luci.sys.call(string.format("/bin/busybox top -bn1 | grep -v grep | grep '%s/bin/' | grep haproxy >/dev/null", appname)) == 0 + e["status"] = luci.sys.call("/bin/busybox top -bn1 | grep -v grep | grep '%s/bin/' | grep haproxy >/dev/null" % appname) == 0 http_write_json(e) end @@ -869,8 +870,9 @@ end function server_log() local id = http.formvalue("id") - if fs.access("/tmp/etc/passwall_server/" .. id .. ".log") then - local content = luci.sys.exec("cat /tmp/etc/passwall_server/" .. id .. ".log") + local f_file = api.S_TMP_PATH .. "/" .. id .. ".log" + if nixio.fs.access(f_file) then + local content = luci.sys.exec("cat " .. f_file) content = content:gsub("\n", "
") http.write(content) else @@ -1268,3 +1270,12 @@ function delete_select_shunt_rules() uci_save(true, true) end end + +function gen_wireguard_key() + local key = api.gen_wireguard_key() + if key then + http_write_json_ok(key) + else + http_write_json_error() + end +end diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua index 0bd7ee749..6f0aabb68 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua @@ -2,6 +2,7 @@ local api = require "luci.passwall.api" api.set_default_cbi() m = Map() +m.redirect = api.url() if not arg[1] or not m:get(arg[1]) then luci.http.redirect(m.redirect) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua index 1cf56d5d3..124a048f6 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua @@ -40,7 +40,8 @@ o:value("vmess", "Vmess") o:value("vless", "VLESS") o:value("shadowsocks", "Shadowsocks") o:value("trojan", "Trojan") -o:value("hysteria2", translate("Hysteria2")) +o:value("hysteria2", "Hysteria2") +o:value("wireguard", "WireGuard") o:value("dokodemo-door", "dokodemo-door") o:depends({ [_n("custom")] = false }) @@ -60,6 +61,7 @@ o:depends({ [_n("protocol")] = "vmess" }) o:depends({ [_n("protocol")] = "vless" }) o:depends({ [_n("protocol")] = "trojan" }) o:depends({ [_n("protocol")] = "hysteria2" }) +o:depends({ [_n("protocol")] = "wireguard" }) o = s:option(ListValue, _n("d_protocol"), translate("Destination protocol")) o:value("tcp", "TCP") @@ -363,7 +365,6 @@ o:depends({ [_n("custom")] = false, [_n("protocol")] = "vmess" }) o:depends({ [_n("custom")] = false, [_n("protocol")] = "vless" }) o:depends({ [_n("custom")] = false, [_n("protocol")] = "trojan" }) o:depends({ [_n("custom")] = false, [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("custom")] = false, [_n("protocol")] = "wireguard" }) o:depends({ [_n("custom")] = false, [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) o = s:option(TextValue, _n("finalmask"), "FinalMask JSON") @@ -417,6 +418,36 @@ o:depends({ [_n("fallback")] = true }) o = s:option(DynamicList, _n("fallback_list"), "Fallback", translate("format: dest,path,xver")) o:depends({ [_n("fallback")] = true }) +-- Not supported at present +--[[ +o = s:option(Flag, _n("wireguard_system_interface"), translate("System interface")) +o.default = 0 +o:depends({ [_n("protocol")] = "wireguard" }) +]]-- + +o = s:option(Value, _n("wireguard_mtu"), "MTU") +o.default = "1420" +o:depends({ [_n("protocol")] = "wireguard" }) + +-- Not supported at present +--[[ +o = s:option(DynamicList, _n("wireguard_local_address"), translate("Local Address")) +o:depends({ [_n("protocol")] = "wireguard" }) +]]-- + +o = s:option(Value, _n("wireguard_private_key"), translate("Private Key")) +o.datatype = "base64" +o:depends({ [_n("protocol")] = "wireguard" }) + +o = s:option(Value, _n("wireguard_public_key"), translate("Public Key")) +o.datatype = "base64" +o:depends({ [_n("protocol")] = "wireguard" }) + +o = s:option(DummyValue, _n("gen_wireguard_key")) +o.prefix = option_prefix +o.template = m:template_path("/server/server_wireguard") +o:depends({ [_n("protocol")] = "wireguard" }) + o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) o.default = "0" o:depends({ [_n("custom")] = false }) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua index 63b07f3be..a092af7ca 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua @@ -53,6 +53,9 @@ if singbox_tags:find("with_quic") then o:value("hysteria2", "Hysteria2") end o:value("anytls", "AnyTLS") +if singbox_tags:find("with_wireguard") then + o:value("wireguard", "WireGuard") +end o:value("direct", "Direct") o:depends({ [_n("custom")] = false }) @@ -76,6 +79,7 @@ o:depends({ [_n("protocol")] = "hysteria" }) o:depends({ [_n("protocol")] = "tuic" }) o:depends({ [_n("protocol")] = "hysteria2" }) o:depends({ [_n("protocol")] = "anytls" }) +o:depends({ [_n("protocol")] = "wireguard" }) if singbox_tags:find("with_quic") then o = s:option(Value, _n("hysteria_obfs"), translate("Obfs Password")) @@ -400,6 +404,32 @@ o = s:option(Value, _n("tcpbrutal_down_mbps"), translate("Max download Mbps")) o.default = "50" o:depends({ [_n("tcpbrutal")] = true }) +if singbox_tags:find("with_wireguard") then + o = s:option(Flag, _n("wireguard_system_interface"), translate("System interface")) + o.default = 0 + o:depends({ [_n("protocol")] = "wireguard" }) + + o = s:option(Value, _n("wireguard_mtu"), "MTU") + o.default = "1408" + o:depends({ [_n("protocol")] = "wireguard" }) + + o = s:option(DynamicList, _n("wireguard_local_address"), translate("Local Address")) + o:depends({ [_n("protocol")] = "wireguard" }) + + o = s:option(Value, _n("wireguard_private_key"), translate("Private Key")) + o.datatype = "base64" + o:depends({ [_n("protocol")] = "wireguard" }) + + o = s:option(Value, _n("wireguard_public_key"), translate("Public Key")) + o.datatype = "base64" + o:depends({ [_n("protocol")] = "wireguard" }) + + o = s:option(DummyValue, _n("gen_wireguard_key")) + o.prefix = option_prefix + o.template = m:template_path("/server/server_wireguard") + o:depends({ [_n("protocol")] = "wireguard" }) +end + o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) o.default = "0" o:depends({ [_n("custom")] = false }) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua index df5f16fa8..ee2ce3550 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua @@ -37,4 +37,18 @@ o.datatype = "uuid" o.default = api.gen_uuid() o.rmempty = false +o = s:option(Value, "wireguard_public_key", "Wireguard " .. translate("Public Key")) +o.datatype = "base64" + +o = s:option(Value, "wireguard_private_key", "Wireguard " .. translate("Private Key")) +o.datatype = "base64" + +o = s:option(DummyValue, "gen_wireguard_key") +o.template = m:template_path("/server/server_wireguard") + +o = s:option(Value, "wireguard_pre_shared_key", "Wireguard " .. translate("Pre shared key")) +o.datatype = "base64" + +o = s:option(DynamicList, "allowed_ips", "Wireguard " .. translate("Allowed IPs")) + return api.return_map(m) diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua index 02d81ef20..ec76e81f4 100644 --- a/luci-app-passwall/luasrc/passwall/api.lua +++ b/luci-app-passwall/luasrc/passwall/api.lua @@ -19,10 +19,11 @@ OPENWRT_ARCH = nil DISTRIB_ARCH = nil OPENWRT_BOARD = nil -LOCK_PREFIX = "/tmp/lock/passwall" -LOG_FILE = "/tmp/log/passwall.log" -TMP_PATH = "/tmp/etc/passwall" +LOCK_PREFIX = "/tmp/lock/" .. c_config +LOG_FILE = "/tmp/log/" .. c_config .. ".log" +TMP_PATH = "/tmp/etc/" .. c_config CACHE_PATH = TMP_PATH .. "_tmp" +S_TMP_PATH = "/tmp/etc/" .. s_config TMP_IFACE_PATH = TMP_PATH .. "/iface" function log(...) @@ -784,16 +785,16 @@ function clone(org) end function get_bin_version_cache(file, cmd) - sys.call("mkdir -p /tmp/etc/passwall_tmp") + sys.call("mkdir -p " .. CACHE_PATH) if fs.access(file) then chmod_755(file) local md5 = sys.exec("echo -n $(md5sum " .. file .. " | awk '{print $1}')") - if fs.access("/tmp/etc/passwall_tmp/" .. md5) then - return sys.exec("echo -n $(cat /tmp/etc/passwall_tmp/%s)" % md5) + if fs.access(CACHE_PATH .. "/" .. md5) then + return sys.exec("echo -n $(cat %s)" % { CACHE_PATH .. "/" .. md5 }) else local version = sys.exec(string.format("echo -n $(%s %s)", file, cmd)) if version and version ~= "" then - sys.call("echo '" .. version .. "' > " .. "/tmp/etc/passwall_tmp/" .. md5) + sys.call("echo '%s' > %s" % { version, CACHE_PATH .. "/" .. md5}) return version end end @@ -1410,29 +1411,24 @@ function set_default_cbi() if true then --Map local Map = cbi.Map - - if not Map._passwall_default_cbi then - Map._passwall_default_cbi = true - local original_parse = Map.parse - function Map.parse(self, ...) - if is_js_luci() then - apply_redirect(self) - local old = self.on_after_save - self.on_after_save = function(map) - if old then old(map) end - map:set("@global[0]", "timestamp", os.time()) - end - end - return original_parse(self, ...) - end - end - - local original_init = Map.__init__ + local default_init = Map.__init__ function Map.__init__(self, config, ...) if not config then config = c_config end - original_init(self, config, ...) + default_init(self, config, ...) self.api = require "luci.passwall.api" end + if is_js_luci() == true then + local default_parse = Map.parse + function Map.parse(self, ...) + apply_redirect(self) + local old = self.on_after_save + self.on_after_save = function(self) + if old then old(self) end + self:set("@global[0]", "timestamp", os.time()) + end + return default_parse(self, ...) + end + end function Map.foreach(self, stype, func) self.uci:foreach(self.config, stype, func) end @@ -1470,9 +1466,9 @@ function set_default_cbi() if true then --TextValue local TextValue = cbi.TextValue - local original_init = TextValue.__init__ + local default_init = TextValue.__init__ function TextValue.__init__(self, ...) - original_init(self, ...) + default_init(self, ...) self.template = appname .. "/cbi/tvalue" end end @@ -1599,7 +1595,9 @@ function luci_types(id, m, s, type_name, option_prefix) local deps = s.fields[key].deps if #deps > 0 then for index, value in ipairs(deps) do - deps[index]["type"] = type_name + if not deps[index]['!reverse'] then + deps[index]["type"] = type_name + end end else s.fields[key]:depends({ type = type_name }) @@ -2045,3 +2043,36 @@ function table_remove_duplicates(t) end return new_t end + +function gen_wireguard_key() + if sys.call("command -v wg >/dev/null") == 0 then + local private_key = sys.exec('echo -n $(wg genkey)') + local public_key = sys.exec('echo -n $(echo "%s" | wg pubkey)' % private_key) + return { + private_key = private_key, + public_key = public_key + } + end + local xray = finded_com("xray") + if xray then + local result = sys.exec(xray .. " wg | awk -F ': ' '{print $2}'") + local s = split(result, "\n") + local private_key = s[1] + local public_key = s[2] + return { + private_key = private_key, + public_key = public_key + } + end + local sb = finded_com("sing-box") + if sb then + local result = sys.exec(sb .. " generate wg-keypair | awk '{print $2}'") + local s = split(result, "\n") + local private_key = s[1] + local public_key = s[2] + return { + private_key = private_key, + public_key = public_key + } + end +end diff --git a/luci-app-passwall/luasrc/passwall/server_app.lua b/luci-app-passwall/luasrc/passwall/server_app.lua index 962d389b0..cdfb22582 100644 --- a/luci-app-passwall/luasrc/passwall/server_app.lua +++ b/luci-app-passwall/luasrc/passwall/server_app.lua @@ -7,7 +7,7 @@ local uci = api.uci local jsonc = api.jsonc local CONFIG = api.s_config -local CONFIG_PATH = "/tmp/etc/" .. CONFIG +local CONFIG_PATH = api.S_TMP_PATH local NFT_INCLUDE_FILE = CONFIG_PATH .. "/" .. CONFIG .. ".nft" local LOG_APP_FILE = "/tmp/log/" .. CONFIG .. ".log" local TMP_BIN_PATH = CONFIG_PATH .. "/bin" @@ -53,7 +53,7 @@ local function ln_run(s, d, command, output) end local function gen_include() - cmd(string.format("echo '#!/bin/sh' > /tmp/etc/%s.include", CONFIG)) + cmd(string.format("echo '#!/bin/sh' > %s.include", CONFIG_PATH)) local function extract_rules(n, a) local _ipt = ipt_bin if n == "6" then @@ -64,7 +64,7 @@ local function gen_include() result = result .. "COMMIT" return result end - local f, err = io.open("/tmp/etc/" .. CONFIG .. ".include", "a") + local f, err = io.open(CONFIG_PATH .. ".include", "a") if f and err == nil then if nft_flag == "0" then f:write(ipt_bin .. '-save -c | grep -v "PSW-SERVER" | ' .. ipt_bin .. '-restore -c' .. "\n") @@ -248,7 +248,7 @@ local function stop() cmd("nft flush chain inet fw4 PSW-SERVER 2>/dev/null") cmd("nft delete chain inet fw4 PSW-SERVER 2>/dev/null") end - cmd(string.format("rm -rf %s %s /tmp/etc/%s.include", CONFIG_PATH, LOG_APP_FILE, CONFIG)) + cmd(string.format("rm -rf %s %s %s", CONFIG_PATH, LOG_APP_FILE, CONFIG_PATH .. ".include")) end if action then diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index f8f43a9e6..46856ff80 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -661,6 +661,8 @@ function gen_outbound(flag, node, tag, proxy_table) end function gen_config_server(node) + local endpoints = {} + local inbounds = {} local outbounds = { { type = "direct", tag = "direct" } } @@ -803,6 +805,12 @@ function gen_config_server(node) u.name = user.username u.password = user.password end + if node.protocol == "wireguard" then + u.public_key = user.wireguard_public_key + u.pre_shared_key = user.wireguard_pre_shared_key + u.allowed_ips = user.allowed_ips or {} + u.persistent_keepalive_interval = 0 + end users[#users + 1] = u end end @@ -970,6 +978,18 @@ function gen_config_server(node) end end + if node.protocol == "wireguard" then + inbound.listen = nil + inbound.system = node.wireguard_system_interface == "1" and true or false + inbound.name = "sbwg_" .. node[".name"] + inbound.mtu = tonumber(node.wireguard_mtu or 1408) + inbound.address = node.wireguard_local_address + inbound.private_key = node.wireguard_private_key + if users then + inbound.peers = users + end + end + if node.protocol == "direct" then protocol_table = { network = (node.d_protocol ~= "TCP,UDP") and node.d_protocol or nil, @@ -984,6 +1004,13 @@ function gen_config_server(node) end end + if node.protocol == "wireguard" then + inbound.listen = nil + table.insert(endpoints, inbound) + else + table.insert(inbounds, inbound) + end + local route = { rules = { { @@ -1038,7 +1065,8 @@ function gen_config_server(node) tag = "direct" }} }, - inbounds = { inbound }, + endpoints = endpoints, + inbounds = inbounds, outbounds = outbounds, route = route } diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index 08bbb167a..790ded8d1 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -515,6 +515,12 @@ function gen_config_server(node) u.email = user.username u.auth = user.password end + if node.protocol == "wireguard" then + u.publicKey = user.wireguard_public_key + u.preSharedKey = user.wireguard_pre_shared_key + u.keepAlive = 0 + u.allowedIPs = user.allowed_ips + end users[#users + 1] = u end end @@ -567,6 +573,14 @@ function gen_config_server(node) address = node.d_address, port = tonumber(node.d_port) } + elseif node.protocol == "wireguard" then + settings = { + secretKey = node.wireguard_private_key, + --address = node.wireguard_local_address, + --noKernelTun = node.wireguard_system_interface ~= "1" and true or false, + mtu = tonumber(node.wireguard_mtu or 1420), + peers = users + } end if node.fallback and node.fallback == "1" then diff --git a/luci-app-passwall/luasrc/view/passwall/server/server_wireguard.htm b/luci-app-passwall/luasrc/view/passwall/server/server_wireguard.htm new file mode 100644 index 000000000..ff73bb97c --- /dev/null +++ b/luci-app-passwall/luasrc/view/passwall/server/server_wireguard.htm @@ -0,0 +1,28 @@ +<% +local map = self.map +local api = map.api +local prefix = self.prefix +-%> +
" data-index="<%=self.index%>" data-depends="<%=pcdata(self:deplist2json(section))%>"> + +
+ +
+
+ + diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index 6bfa6bbb5..997bd8226 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -1490,9 +1490,18 @@ msgstr "私钥" msgid "Pre shared key" msgstr "额外的对称加密密钥" +msgid "Allowed IPs" +msgstr "允许的 IP" + +msgid "Generate key" +msgstr "生成密钥" + msgid "Local Address" msgstr "本地地址" +msgid "System interface" +msgstr "系统接口" + msgid "Decimal numbers separated by \",\" or Base64-encoded strings." msgstr "用“,”隔开的十进制数字或 Base64 编码字符串。" diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh index bd4ec5d9c..d0e914264 100755 --- a/luci-app-passwall/root/usr/share/passwall/app.sh +++ b/luci-app-passwall/root/usr/share/passwall/app.sh @@ -1868,7 +1868,7 @@ acl_app() { } start() { - busybox pgrep -f /tmp/etc/passwall/bin > /dev/null 2>&1 && { + busybox pgrep -f ${TMP_PATH}/bin > /dev/null 2>&1 && { logger -t PSW-RESTART "Upgrade or overload residue is detected, and the subprocess is being called to perform complete cleaning..." (stop) sleep 2 diff --git a/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh b/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh index a3a07f339..a77abf8e6 100755 --- a/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh +++ b/luci-app-passwall/root/usr/share/passwall/socks_auto_switch.sh @@ -71,10 +71,10 @@ test_node() { local curlx="socks5h://127.0.0.1:${_tmp_port}" local _proxy_status=$(test_url "${probe_url}" ${retry_num} ${connect_timeout} "-x $curlx" 1) # 结束 SS 插件进程 - local pid_file="/tmp/etc/${CONFIG}/test_node_${node_id}_plugin.pid" + local pid_file="${TMP_PATH}/test_node_${node_id}_plugin.pid" [ -s "$pid_file" ] && kill -9 "$(head -n 1 "$pid_file")" >/dev/null 2>&1 busybox pgrep -af "test_node_${node_id}" | awk '! /socks_auto_switch\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1 - rm -rf /tmp/etc/${CONFIG}/test_node_${node_id}*.* + rm -rf ${TMP_PATH}/test_node_${node_id}*.* if [ "${_proxy_status}" -eq 200 ]; then return 0 fi diff --git a/luci-app-passwall/root/usr/share/passwall/test.sh b/luci-app-passwall/root/usr/share/passwall/test.sh index 72ca0a60b..29d0df9ac 100755 --- a/luci-app-passwall/root/usr/share/passwall/test.sh +++ b/luci-app-passwall/root/usr/share/passwall/test.sh @@ -64,10 +64,10 @@ url_test_node() { local probeUrl=$(config_t_get global_other url_test_url https://www.google.com/generate_204) result=$(curl --connect-timeout 3 --max-time 5 -o /dev/null -I -skL -w "%{http_code}:%{time_pretransfer}" -x ${curlx} "${probeUrl}") # 结束 SS 插件进程 - local pid_file="/tmp/etc/${CONFIG}/url_test_${node_id}_plugin.pid" + local pid_file="${TMP_PATH}/url_test_${node_id}_plugin.pid" [ -s "$pid_file" ] && kill -9 "$(head -n 1 "$pid_file")" >/dev/null 2>&1 busybox pgrep -af "url_test_${node_id}" | awk '! /test\.sh/{print $1}' | xargs kill -9 >/dev/null 2>&1 - rm -rf /tmp/etc/${CONFIG}/*url_test_${node_id}*.* + rm -rf ${TMP_PATH}/*url_test_${node_id}*.* } echo $result } diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 5f82304be..bd163f0d8 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 PKG_VERSION:=26.8.16 -PKG_RELEASE:=88 +PKG_RELEASE:=89 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/user_config.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/user_config.lua index 0cd4a3696..f2f1b7e3e 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/user_config.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/user_config.lua @@ -44,7 +44,7 @@ o = s:option(Value, "wireguard_private_key", "Wireguard " .. translate("Private o.datatype = "base64" o = s:option(DummyValue, "gen_wireguard_key") -o.template = m:template_path("/server/server_wireguard") +o.template = m:template_path("/server/gen_wireguard_key") o = s:option(Value, "wireguard_pre_shared_key", "Wireguard " .. translate("Pre shared key")) o.datatype = "base64" diff --git a/luci-theme-aurora/.claude/skills/aurora-performance/references/aurora-budgets.md b/luci-theme-aurora/.claude/skills/aurora-performance/references/aurora-budgets.md index d31542a03..46993f585 100644 --- a/luci-theme-aurora/.claude/skills/aurora-performance/references/aurora-budgets.md +++ b/luci-theme-aurora/.claude/skills/aurora-performance/references/aurora-budgets.md @@ -11,11 +11,12 @@ address, so they stay local). | Metric | Budget | Track | Source | |---|---|---|---| -| main.css (identity/raw) | ≤ 190 KB | size | production build, 2026-07 (183,820 B) | +| main.css (identity/raw) | ≤ 193 KB | size | production build, 2026-08 (192,201 B; +~2 KB custom-background mode, +~0.5 KB router progress bar / live region) | | login.css (identity/raw) | ≤ 12 KB | size | production build, 2026-07 (10,935 B, token-pruned) | -| menu-aurora.js (identity/raw) | ≤ 20 KB | size | production build, 2026-07 (19,100 B) | +| menu-aurora.js (identity/raw) | ≤ 21.5 KB | size | production build, 2026-08 (20,851 B; +1.3 KB for the router's `syncRoute`/`closeSurfaces` hooks) | +| router-aurora.js (identity/raw, Navigation-API browsers only) | ≤ 15 KB | size | production build, 2026-08 (14,568 B: template shells fetched, per-render listener teardown, timeout-as-failure, expiry gate, readonly folding, node css, wildcard actions, progress bar, visibility gate, contract check) | | Default logo (identity/raw) | ≤ 16 KB | size | production build, 2026-07 (15,057 B) | -| Core admin cold theme assets (identity/raw) | ≤ 250 KB | size | main CSS + menu JS + default font + logo, 2026-07 (241,557 B) | +| Core admin cold theme assets (identity/raw) | ≤ 267 KB | size | main CSS + menu JS + router JS + default font + logo, 2026-08 (≈266.3 KB; the router is a one-time cost that removes per-click dispatcher work) | | Login cold theme assets, excluding configured background (identity/raw) | ≤ 55 KB | size | login CSS + default font + logo, 2026-07 (49,572 B) | | Blocking requests before first paint | ≤ 4 | count | current waterfall | | Repeat-visit asset requests | ≈ 0 | count | target state; package-built CSS/JS URLs are versioned, but long-lived cache headers still need live verification | @@ -42,6 +43,19 @@ Budget revisions require a new baseline entry under `../baselines/`. - login.css pruned to its reachable custom properties at build time (the shared token sheet is admin-sized; the login page consumes a fraction). +- Client-side router (`router-aurora.js`, `.dev/docs/router.md`, + 2026-08-16): view/alias/firstchild/overview navigations become + same-document swaps on Navigation-API browsers, MPA elsewhere. + Measured on RE-SS-01 over plain HTTP (`bench-router.mjs`, RUNS=10): click → + view painted **241–544 ms → 49–251 ms warm, median −67 %**; walk of + 51/62 linked pages (mega-menu/sidebar), 42–43 served, **0 divergences** vs + full loads incl. DOM shape; 65-navigation soak flat after the first lap + once departed regions are cleared through `dom.content()` (the data-idref + registry otherwise pins every departed subtree: 26k → 72k nodes before) + and per-render window/document listeners are torn down; back traversal + through alias/firstchild entries same-document; poison gate → full load → + router again. Report in `../baselines/router-re-ss-01.md`. + ### Pending | Item | Principle | Estimated gain | |---|---|---| diff --git a/luci-theme-aurora/.claude/skills/aurora-performance/references/measuring.md b/luci-theme-aurora/.claude/skills/aurora-performance/references/measuring.md index 4976f9993..735f10ed6 100644 --- a/luci-theme-aurora/.claude/skills/aurora-performance/references/measuring.md +++ b/luci-theme-aurora/.claude/skills/aurora-performance/references/measuring.md @@ -50,6 +50,38 @@ still print. **Output.** The whole report is Markdown: paste it straight into a PR description, or archive it (see below). +## `bench-router.mjs` — router verification and A/B (CDP) + +The client-side router (`.dev/docs/router.md`) is verified against real +full loads, never against expectation: + +```bash +curl -c jar.txt -d 'luci_username=root&luci_password=…' http:///cgi-bin/luci/ +HOST=http:// COOKIE_NAME=sysauth_http COOKIE_VALUE= \ + node ../.claude/skills/aurora-performance/scripts/bench-router.mjs