From c9c56d7f6e9f3484b97c954ebb370525f701b64d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 3 Jun 2026 21:58:23 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=B6=20Sync=202026-06-03=2021:58:23?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gowebdav/Makefile | 4 +- luci-app-passwall/Makefile | 2 +- .../luasrc/controller/passwall.lua | 6 +- luci-app-passwall/luasrc/passwall/api.lua | 34 +++--- .../luasrc/passwall/util_sing-box.lua | 8 +- .../luasrc/passwall/util_xray.lua | 36 +++--- luci-app-passwall2/Makefile | 4 +- .../luasrc/controller/passwall2.lua | 35 +++--- .../model/cbi/passwall2/client/global.lua | 2 +- .../cbi/passwall2/client/type/hysteria2.lua | 2 + .../model/cbi/passwall2/client/type/ray.lua | 56 +++++++-- .../cbi/passwall2/client/type/sing-box.lua | 20 ++++ .../cbi/passwall2/server/type/hysteria2.lua | 2 + .../model/cbi/passwall2/server/type/ray.lua | 18 ++- .../cbi/passwall2/server/type/sing-box.lua | 2 + luci-app-passwall2/luasrc/passwall2/api.lua | 2 + .../luasrc/passwall2/util_hysteria2.lua | 8 +- .../luasrc/passwall2/util_sing-box.lua | 1 + .../luasrc/passwall2/util_xray.lua | 107 +++++++++++++----- .../luasrc/view/passwall2/global/backup.htm | 9 +- .../passwall2/node_config/link_share_man.htm | 6 +- luci-app-passwall2/po/fa/passwall2.po | 10 +- luci-app-passwall2/po/ru/passwall2.po | 10 +- luci-app-passwall2/po/zh-cn/passwall2.po | 10 +- luci-app-passwall2/po/zh-tw/passwall2.po | 10 +- .../root/usr/share/passwall2/app.sh | 6 +- .../root/usr/share/passwall2/subscribe.lua | 89 ++++++++++----- openwrt-fastfetch/Makefile | 4 +- opera-proxy/Makefile | 88 ++++++++++++++ opera-proxy/files/opera-proxy.config | 6 + opera-proxy/files/opera-proxy.init | 42 +++++++ qBittorrent-Enhanced-Edition/Makefile | 4 +- teleproxy/Makefile | 4 +- 33 files changed, 485 insertions(+), 162 deletions(-) create mode 100644 opera-proxy/Makefile create mode 100644 opera-proxy/files/opera-proxy.config create mode 100755 opera-proxy/files/opera-proxy.init diff --git a/gowebdav/Makefile b/gowebdav/Makefile index 5ae45173b..1dab0c35f 100644 --- a/gowebdav/Makefile +++ b/gowebdav/Makefile @@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=gowebdav -PKG_VERSION:=5.11.9 -PKG_RELEASE:=9 +PKG_VERSION:=5.11.10 +PKG_RELEASE:=10 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/hacdias/webdav/tar.gz/v$(PKG_VERSION)? diff --git a/luci-app-passwall/Makefile b/luci-app-passwall/Makefile index 5549bf4d6..6b88afea9 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.6.2 -PKG_RELEASE:=152 +PKG_RELEASE:=153 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 d440dd57e..518265f23 100644 --- a/luci-app-passwall/luasrc/controller/passwall.lua +++ b/luci-app-passwall/luasrc/controller/passwall.lua @@ -1144,10 +1144,12 @@ function fetch_certsha256() local id = http.formvalue("id") or "" local address = (id ~= "") and uci:get(appname, id, "address") or "" local port = (id ~= "") and uci:get(appname, id, "port") or 0 - if id == "" or address == "" or not api.datatypes.hostname(address) or port == 0 then + local sni = (id ~= "") and uci:get(appname, id, "tls_serverName") or "" + sni = (sni ~= "") and sni or address + if address == "" or port == 0 then http_write_json_error() return end - local data = api.fetch_cert_sha256(address, port, 5) + local data = api.fetch_cert_sha256(address, port, sni, 5) http_write_json(data ~= "" and { code = 1, data = data } or { code = 0 }) end diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua index 10886cf00..44bf97cb4 100644 --- a/luci-app-passwall/luasrc/passwall/api.lua +++ b/luci-app-passwall/luasrc/passwall/api.lua @@ -1570,31 +1570,23 @@ function cleanEmptyTables(t) return next(t) and t or nil end -function fetch_cert_sha256(host, port, timeout) - if not host or not datatypes.hostname(host) then return "" end +function fetch_cert_sha256(host, port, sni, timeout) + if not host then return "" end port = tonumber(port) or 443 + sni = sni or host timeout = tonumber(timeout) or 5 - local xray = finded_com("xray") - local cmd - if xray then - cmd = string.format( - "timeout %d %q tls ping %s:%d 2>/dev/null " .. - "| awk 'tolower($0) ~ /without sni/ {f=1} tolower($0) ~ /with sni/ {f=0} " .. - "f && tolower($0) ~ /cert.*leaf.*sha256/ {sub(/.*:/,\"\"); gsub(/[[:space:]]/,\"\"); print; exit}'", - timeout, xray, host, port - ) - else - cmd = string.format( - "timeout %d openssl s_client -connect %s:%d -servername %s -showcerts /dev/null " .. - "| awk 'BEGIN{c=0}/BEGIN CERT/{c++} c==1{print} /END CERT/{if(c==1)exit}' " .. - "| openssl x509 -outform der 2>/dev/null " .. - "| sha256sum 2>/dev/null", - timeout, host, port, host - ) - end + local cmd = string.format( + "timeout %d openssl s_client -connect %s:%d -servername %s -showcerts /dev/null " .. + "| awk 'BEGIN{c=0}/BEGIN CERT/{c++} c==1{print} /END CERT/{if(c==1)exit}' " .. + "| openssl x509 -outform der 2>/dev/null " .. + "| sha256sum 2>/dev/null", + timeout, host, port, sni + ) local out = trim(sys.exec(cmd)) local fp = out:match("^([0-9a-fA-F]+)") - if not fp then return "" end + if not fp or fp:lower():match("^e3b0c44298fc1c149afbf4c8996fb924") then + return "" + end return fp:upper() end diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index 325f80b89..f9662125d 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -1666,7 +1666,8 @@ function gen_config(var) invert = e.invert == "1" and true or nil } string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w) - if w:find("#") == 1 then return end + w = api.trim(w) + if w == "" or w:find("#") == 1 then return end if w:find("geosite:") == 1 then local _geosite = w:sub(1 + #"geosite:") --适配srs local t = geo_rule_set("geosite", _geosite) @@ -1703,7 +1704,7 @@ function gen_config(var) domain_table.fakedns = true end - if outboundTag then + if outboundTag and (rule.domain or rule.domain_suffix or rule.domain_keyword or rule.domain_regex or rule.rule_set) then table.insert(dns_domain_rules, api.clone(domain_table)) end end @@ -1712,7 +1713,8 @@ function gen_config(var) local ip_cidr = {} local is_private = false string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w) - if w:find("#") == 1 then return end + w = api.trim(w) + if w == "" or w:find("#") == 1 then return end if w:find("geoip:") == 1 then local _geoip = w:sub(1 + #"geoip:") --适配srs if _geoip == "private" then diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index a710347cc..a73d48a2b 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -498,9 +498,9 @@ function gen_config_server(node) if node.protocol == "vmess" or node.protocol == "vless" then if node.uuid then - local clients = {} + local users = {} for i = 1, #node.uuid do - clients[i] = { + users[i] = { id = node.uuid[i], flow = (node.protocol == "vless" and (node.tls == "1" or (node.decryption and node.decryption ~= "" and node.decryption ~= "none")) @@ -508,7 +508,7 @@ function gen_config_server(node) } end settings = { - clients = clients, + users = users, decryption = (node.protocol == "vless") and ((node.decryption and node.decryption ~= "") and node.decryption or "none") or nil } end @@ -516,7 +516,7 @@ function gen_config_server(node) settings = { udp = ("1" == node.udp_forward) and true or false, auth = ("1" == node.auth) and "password" or "noauth", - accounts = ("1" == node.auth) and { + users = ("1" == node.auth) and { { user = node.username, pass = node.password @@ -526,7 +526,7 @@ function gen_config_server(node) elseif node.protocol == "http" then settings = { allowTransparent = false, - accounts = ("1" == node.auth) and { + users = ("1" == node.auth) and { { user = node.username, pass = node.password @@ -544,20 +544,20 @@ function gen_config_server(node) } elseif node.protocol == "trojan" then if node.uuid then - local clients = {} + local users = {} for i = 1, #node.uuid do - clients[i] = { + users[i] = { password = node.uuid[i], } end settings = { - clients = clients + users = users } end elseif node.protocol == "hysteria2" then settings = { version = 2, - clients = node.hysteria2_auth_password and { + users = node.hysteria2_auth_password and { { auth = node.hysteria2_auth_password } } } @@ -946,7 +946,7 @@ function gen_config(var) end if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then inbound.settings.auth = "password" - inbound.settings.accounts = { + inbound.settings.users = { { user = local_socks_username, pass = local_socks_password @@ -963,7 +963,7 @@ function gen_config(var) settings = {allowTransparent = false} } if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then - inbound.settings.accounts = { + inbound.settings.users = { { user = local_http_username, pass = local_http_password @@ -1422,7 +1422,8 @@ function gen_config(var) } domains = {} string.gsub(e.domain_list, '[^' .. "\r\n" .. ']+', function(w) - if w:find("#") == 1 then return end + w = api.trim(w) + if w == "" or w:find("#") == 1 then return end if w:find("rule-set:", 1, true) == 1 or w:find("rs:") == 1 then return end table.insert(domains, w) table.insert(domain_table.domain, w) @@ -1430,16 +1431,17 @@ function gen_config(var) if inner_fakedns == "1" and node[e[".name"] .. "_fakedns"] == "1" and #domains > 0 then domain_table.fakedns = true end - if outbound_tag then + if #domains == 0 then domains = nil end + if outbound_tag and domains then table.insert(dns_domain_rules, api.clone(domain_table)) end - if #domains == 0 then domains = nil end end local ip = nil if e.ip_list then ip = {} string.gsub(e.ip_list, '[^' .. "\r\n" .. ']+', function(w) - if w:find("#") == 1 then return end + w = api.trim(w) + if w == "" or w:find("#") == 1 then return end if w:find("rule-set:", 1, true) == 1 or w:find("rs:") == 1 then return end table.insert(ip, w) end) @@ -2036,7 +2038,7 @@ function gen_proto_config(var) } if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then inbound.settings.auth = "password" - inbound.settings.accounts = { + inbound.settings.users = { { user = local_socks_username, pass = local_socks_password @@ -2056,7 +2058,7 @@ function gen_proto_config(var) } } if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then - inbound.settings.accounts = { + inbound.settings.users = { { user = local_http_username, pass = local_http_password diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile index 68be28ad4..6e3e8d74a 100644 --- a/luci-app-passwall2/Makefile +++ b/luci-app-passwall2/Makefile @@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-passwall2 -PKG_VERSION:=26.5.19 -PKG_RELEASE:=50 +PKG_VERSION:=26.6.3 +PKG_RELEASE:=51 PKG_PO_VERSION:=$(PKG_VERSION) PKG_CONFIG_DEPENDS:= \ diff --git a/luci-app-passwall2/luasrc/controller/passwall2.lua b/luci-app-passwall2/luasrc/controller/passwall2.lua index 26a459077..4bb05586c 100644 --- a/luci-app-passwall2/luasrc/controller/passwall2.lua +++ b/luci-app-passwall2/luasrc/controller/passwall2.lua @@ -22,7 +22,6 @@ function index() local appname = api.appname -- global definitions not available local uci = api.uci -- in function index() entry({"admin", "services", appname}).dependent = true - entry({"admin", "services", appname, "reset_config"}, call("reset_config")).leaf = true entry({"admin", "services", appname, "show"}, call("show_menu")).leaf = true entry({"admin", "services", appname, "hide"}, call("hide_menu")).leaf = true local e @@ -110,26 +109,12 @@ function index() --[[Backup]] entry({"admin", "services", appname, "create_backup"}, call("create_backup")).leaf = true entry({"admin", "services", appname, "restore_backup"}, call("restore_backup")).leaf = true + entry({"admin", "services", appname, "reset_config"}, call("reset_config")).leaf = true --[[geoview]] entry({"admin", "services", appname, "geo_view"}, call("geo_view")).leaf = true end -local function http_write_json(content) - http.prepare_content("application/json") - http.write(jsonStringify(content or {code = 1})) -end - -local function http_write_json_ok(data) - http.prepare_content("application/json") - http.write(jsonStringify({code = 1, data = data})) -end - -local function http_write_json_error(data) - http.prepare_content("application/json") - http.write(jsonStringify({code = 0, data = data})) -end - function check_site(host, port) local nixio = require "nixio" local socket = nixio.socket("inet", "stream") @@ -185,7 +170,24 @@ function check_ip() luci.http.write_json(e) end +local function http_write_json(content) + http.prepare_content("application/json") + http.write(jsonStringify(content or {code = 1})) +end + +local function http_write_json_ok(data) + http.prepare_content("application/json") + http.write(jsonStringify({code = 1, data = data})) +end + +local function http_write_json_error(data) + http.prepare_content("application/json") + http.write(jsonStringify({code = 0, data = data})) +end + function reset_config() + uci:revert(appname) + luci.sys.call("echo '' > /tmp/log/passwall2.log") luci.sys.call('/etc/init.d/passwall2 stop') luci.sys.call('[ -f "/usr/share/passwall2/0_default_config" ] && cp -f /usr/share/passwall2/0_default_config /etc/config/passwall2') http.redirect(api.url()) @@ -801,6 +803,7 @@ function restore_backup() fp:write(decoded) fp:close() if chunk_index + 1 == total_chunks then + uci:revert(appname) api.sys.call("echo '' > /tmp/log/passwall2.log") api.log(0, string.format(" * PassWall2 %s", i18n.translate("Configuration file uploaded successfully…"))) local temp_dir = '/tmp/passwall2_bak' diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua index 8ee881e32..92de2f978 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/global.lua @@ -72,7 +72,7 @@ end m:append(Template(appname .. "/global/status")) -global_cfgid = m:get("@global[0]")[".name"] +global_cfgid = (m:get("@global[0]") or {})[".name"] or "" s = m:section(TypedSection, "global") s.anonymous = true diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/hysteria2.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/hysteria2.lua index f5c66225a..8cf95aed9 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/hysteria2.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/hysteria2.lua @@ -59,11 +59,13 @@ o.rewrite_option = o.option o = s:option(ListValue, _n("obfs_type"), translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") +o:value("gecko") o.rewrite_option = o.option o = s:option(Value, _n("obfs_password"), translate("Obfs Password")) o.rewrite_option = o.option o:depends({ [_n("obfs_type")] = "salamander" }) +o:depends({ [_n("obfs_type")] = "gecko" }) o = s:option(Flag, _n("fast_open"), translate("Fast Open")) o.default = "0" diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua index b3a32bc2c..041567a36 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/ray.lua @@ -339,13 +339,28 @@ o:depends({ [_n("protocol")] = "vless" }) ---- [[hysteria2]] o = s:option(Value, _n("hysteria2_hop"), translate("Port hopping range")) o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).") -o:depends({ [_n("protocol")] = "hysteria2" }) +o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5.")) o.datatype = "or(uinteger,portrange)" o.placeholder = "30" o.default = "30" -o:depends({ [_n("protocol")] = "hysteria2" }) +o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) + +o = s:option(Flag, _n("hysteria2_realms"), translate("Realms")) +o.default = "0" +if api.compare_versions(xray_version, ">", "26.5.9") then + o:depends({ [_n("protocol")] = "hysteria2"}) +else + o:depends({ [_n("protocol")] = "__hide"}) +end + +o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") +o:depends({ [_n("hysteria2_realms")] = "1" }) + +o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN")) +o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } +o:depends({ [_n("hysteria2_realms")] = "1" }) o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password")) o.password = true @@ -354,10 +369,12 @@ o:depends({ [_n("protocol")] = "hysteria2"}) o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") +o:value("gecko") o:depends({ [_n("protocol")] = "hysteria2" }) o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password")) o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) +o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps")) o:depends({ [_n("protocol")] = "hysteria2" }) @@ -431,11 +448,26 @@ if api.compare_versions(xray_version, ">=", "26.1.31") then o:depends({ [_n("protocol")] = "hysteria2" }) end -o = s:option(Flag, _n("ech"), translate("ECH")) +o = s:option(Flag, _n("tls_certificate"), translate("TLS Certificate (PEM)")) o.default = "0" o:depends({ [_n("tls")] = true, [_n("reality")] = false }) o:depends({ [_n("protocol")] = "hysteria2" }) +o = s:option(TextValue, _n("tls_certificate_pem"), " ", translate("Full certificate (chain), PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ [_n("tls_certificate")] = true }) +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value +end + +o = s:option(Flag, _n("ech"), translate("ECH")) +o.default = "0" +o:depends({ [_n("tls")] = true, [_n("reality")] = false }) +o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) + o = s:option(TextValue, _n("ech_config"), translate("ECH Config")) o.default = "" o.rows = 5 @@ -706,7 +738,7 @@ o:depends({ [_n("protocol")] = "vless" }) o:depends({ [_n("protocol")] = "trojan" }) o:depends({ [_n("protocol")] = "shadowsocks" }) o:depends({ [_n("protocol")] = "wireguard" }) -o:depends({ [_n("protocol")] = "hysteria2" }) +o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) o = s:option(TextValue, _n("finalmask"), " ") o:depends({ [_n("use_finalmask")] = true }) @@ -775,10 +807,14 @@ local protocols = s.fields[_n("protocol")].keylist if #protocols > 0 then for i, v in ipairs(protocols) do if not v:find("^_") then - s.fields[_n("address")]:depends({ [_n("protocol")] = v }) - s.fields[_n("port")]:depends({ [_n("protocol")] = v }) - s.fields[_n("domain_resolver")]:depends({ [_n("protocol")] = v }) - s.fields[_n("domain_strategy")]:depends({ [_n("protocol")] = v }) + local depends_condition = { [_n("protocol")] = v } + if v == "hysteria2" then + depends_condition[_n("hysteria2_realms")] = false + end + s.fields[_n("address")]:depends(depends_condition) + s.fields[_n("port")]:depends(depends_condition) + s.fields[_n("domain_resolver")]:depends(depends_condition) + s.fields[_n("domain_strategy")]:depends(depends_condition) if v ~= "hysteria2" then s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) @@ -801,7 +837,7 @@ if not load_shunt_options then o:value("2", translate("Landing Node")) o1 = s:option(ListValue, _n("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy.")) - o1:depends({ [_n("chain_proxy")] = "1" }) + o1:depends({ [_n("chain_proxy")] = "1", [_n("hysteria2_realms")] = false }) o1.template = appname .. "/cbi/nodes_listvalue" o1.group = {} @@ -813,7 +849,7 @@ if not load_shunt_options then end o2 = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Only support a layer of proxy.")) - o2:depends({ [_n("chain_proxy")] = "2" }) + o2:depends({ [_n("chain_proxy")] = "2", [_n("hysteria2_realms")] = false }) o2.template = appname .. "/cbi/nodes_listvalue" o2.group = {} diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua index a3c591ca5..55d75677f 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/client/type/sing-box.lua @@ -423,10 +423,12 @@ if singbox_tags:find("with_quic") then o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") + o:value("gecko") o:depends({ [_n("protocol")] = "hysteria2" }) o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password")) o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) + o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps")) o:depends({ [_n("protocol")] = "hysteria2" }) @@ -531,6 +533,24 @@ o:depends({ [_n("protocol")] = "hysteria"}) o:depends({ [_n("protocol")] = "tuic" }) o:depends({ [_n("protocol")] = "hysteria2" }) +o = s:option(Flag, _n("tls_certificate"), translate("TLS Certificate (PEM)")) +o.default = "0" +o:depends({ [_n("tls")] = true, [_n("reality")] = false }) +o:depends({ [_n("protocol")] = "hysteria"}) +o:depends({ [_n("protocol")] = "tuic" }) +o:depends({ [_n("protocol")] = "hysteria2" }) +o:depends({ [_n("protocol")] = "naive" }) + +o = s:option(TextValue, _n("tls_certificate_pem"), " ", translate("Full certificate (chain), PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ [_n("tls_certificate")] = true }) +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value +end + o = s:option(Flag, _n("ech"), translate("ECH")) o.default = "0" o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false }) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/hysteria2.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/hysteria2.lua index 89742db88..cc9a733a8 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/hysteria2.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/hysteria2.lua @@ -48,12 +48,14 @@ o:depends({ [_n("custom")] = false }) o = s:option(ListValue, _n("obfs_type"), translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") +o:value("gecko") o.rewrite_option = o.option o:depends({ [_n("custom")] = false }) o = s:option(Value, _n("obfs_password"), translate("Obfs Password")) o.rewrite_option = o.option o:depends({ [_n("obfs_type")] = "salamander" }) +o:depends({ [_n("obfs_type")] = "gecko" }) o = s:option(Flag, _n("udp"), translate("UDP")) o.default = "1" diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua index ff99b15b8..14a48bc54 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/ray.lua @@ -127,6 +127,17 @@ o:value("xtls-rprx-vision") o:depends({ [_n("protocol")] = "vless" }) ---- [[ hysteria2 ]] +o = s:option(Flag, _n("hysteria2_realms"), translate("Realms")) +o.default = "0" +o:depends({ [_n("protocol")] = "hysteria2"}) + +o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") +o:depends({ [_n("hysteria2_realms")] = "1" }) + +o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN")) +o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } +o:depends({ [_n("hysteria2_realms")] = "1" }) + o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password")) o.password = true o:depends({ [_n("protocol")] = "hysteria2"}) @@ -134,10 +145,12 @@ o:depends({ [_n("protocol")] = "hysteria2"}) o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") +o:value("gecko") o:depends({ [_n("protocol")] = "hysteria2" }) o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password")) o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) +o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control")) o.default = 0 @@ -210,7 +223,8 @@ function o.write(self, section, value) end o = s:option(ListValue, _n("alpn"), translate("alpn")) -o.default = "h2,http/1.1" +o.default = "default" +o:value("default", translate("Default")) o:value("h3") o:value("h2") o:value("h3,h2") @@ -378,7 +392,7 @@ 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" }) +o:depends({ [_n("custom")] = false, [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) o = s:option(TextValue, _n("finalmask"), "FinalMask JSON") o:depends({ [_n("use_finalmask")] = true }) diff --git a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua index dd3cb2f44..f367a01cb 100644 --- a/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua +++ b/luci-app-passwall2/luasrc/model/cbi/passwall2/server/type/sing-box.lua @@ -175,10 +175,12 @@ if singbox_tags:find("with_quic") then o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) o:value("", translate("Disable")) o:value("salamander") + o:value("gecko") o:depends({ [_n("protocol")] = "hysteria2" }) o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password")) o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) + o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"), translate("Commands the client to use the BBR flow control algorithm")) o.default = 0 diff --git a/luci-app-passwall2/luasrc/passwall2/api.lua b/luci-app-passwall2/luasrc/passwall2/api.lua index e2510f517..5ee4cb7b3 100644 --- a/luci-app-passwall2/luasrc/passwall2/api.lua +++ b/luci-app-passwall2/luasrc/passwall2/api.lua @@ -154,12 +154,14 @@ function base64Encode(text) end function UrlEncode(szText) + if type(szText) ~= "string" then return "" end return szText:gsub("([^%w%-_%.%~])", function(c) return string.format("%%%02X", string.byte(c)) end) end function UrlDecode(szText) + if type(szText) ~= "string" then return "" end return szText and szText:gsub("%+", " "):gsub("%%(%x%x)", function(h) return string.char(tonumber(h, 16)) end) or nil diff --git a/luci-app-passwall2/luasrc/passwall2/util_hysteria2.lua b/luci-app-passwall2/luasrc/passwall2/util_hysteria2.lua index 7075dd11e..43b586e2f 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_hysteria2.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_hysteria2.lua @@ -20,8 +20,8 @@ function gen_config_server(node) key = node.tls_keyFile, }, obfs = (node.hysteria2_obfs_type and node.hysteria2_obfs_password) and { - type = "salamander", - salamander = { + type = node.hysteria2_obfs_type, + [node.hysteria2_obfs_type] = { password = node.hysteria2_obfs_password } } or nil, @@ -101,8 +101,8 @@ function gen_config(var) end)() or nil }, obfs = (node.hysteria2_obfs_type and node.hysteria2_obfs_password) and { - type = "salamander", - salamander = { + type = node.hysteria2_obfs_type, + [node.hysteria2_obfs_type] = { password = node.hysteria2_obfs_password } } or nil, diff --git a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua index 8080b147b..c7c980075 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_sing-box.lua @@ -255,6 +255,7 @@ function gen_outbound(flag, node, tag, proxy_table) --max_version = "1.3", fragment = fragment, record_fragment = record_fragment, + certificate = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and split(node.tls_certificate_pem, "\n") or nil, ech = (node.ech == "1") and (function() local function get_ech_domain(s) --兼容xray "域名+DNS" 格式ech local domain, dns = s:match("^([^+]+)%+(.+)$") diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua index 8fba45974..00e9aa4fc 100644 --- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua +++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua @@ -73,8 +73,8 @@ function gen_outbound(flag, node, tag, proxy_table) local run_socks_instance = true if proxy_table ~= nil and type(proxy_table) == "table" then proxy_tag = proxy_table.tag or nil - fragment = proxy_table.fragment or nil - noise = proxy_table.noise or nil + fragment = (proxy_table.fragment and not node.hysteria2_realms) and true or nil + noise = (proxy_table.noise and not node.hysteria2_realms) and true or nil run_socks_instance = proxy_table.run_socks_instance end @@ -189,7 +189,11 @@ function gen_outbound(flag, node, tag, proxy_table) if not node.tls_CertByName then return "" end return node.tls_CertByName end)(), - echConfigList = (node.ech == "1") and node.ech_config or nil + echConfigList = (node.ech == "1") and node.ech_config or nil, + certificates = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and { + certificate = api.split(node.tls_certificate_pem, "\n"), + usage = "verify" + } or nil } or nil, realitySettings = (node.stream_security == "reality") and { serverName = node.tls_serverName, @@ -298,14 +302,36 @@ function gen_outbound(flag, node, tag, proxy_table) udp[#udp+1] = c finalmask.udp = udp elseif TP == "hysteria" then + local udp = {} if node.hysteria2_obfs_type and node.hysteria2_obfs_type ~= "" then - finalmask.udp = {{ - type = node.hysteria2_obfs_type, + local o = { + type = "salamander", settings = node.hysteria2_obfs_password and { - password = node.hysteria2_obfs_password + password = node.hysteria2_obfs_password, + packetSize = node.hysteria2_obfs_type == "gecko" and "512-1200" or nil } or nil - }} + } + udp[#udp+1] = o end + if node.hysteria2_realms then + local realm = api.parse_realm_uri(node.hysteria2_realm_url) + local url, stun + if realm then + if realm.token and realm.server_url and realm.realm_id then + url = "realm://" .. realm.token .. "@" .. realm.server_url .. "/" .. realm.realm_id + end + stun = realm.stun_servers or node.hysteria2_realm_stun + end + local r = { + type = "realm", + settings = { + url = url, + stunServers = stun + } + } + udp[#udp+1] = r + end + finalmask.udp = udp local up = tonumber(node.hysteria2_up_mbps) or 0 local down = tonumber(node.hysteria2_down_mbps) or 0 finalmask.quicParams = { @@ -415,6 +441,13 @@ function gen_outbound(flag, node, tag, proxy_table) if node.protocol == "wireguard" then result.settings.kernelMode = false + if node.finalmask and node.finalmask ~= "" then + local ok, fm = pcall(jsonc.parse, api.base64Decode(node.finalmask)) + if ok and type(fm) == "table" then + result.streamSettings = result.streamSettings or {} + result.streamSettings.finalmask = fm + end + end end local alpn = {} @@ -487,9 +520,9 @@ function gen_config_server(node) if node.protocol == "vmess" or node.protocol == "vless" then if node.uuid then - local clients = {} + local users = {} for i = 1, #node.uuid do - clients[i] = { + users[i] = { id = node.uuid[i], flow = (node.protocol == "vless" and (node.tls == "1" or (node.decryption and node.decryption ~= "" and node.decryption ~= "none")) @@ -497,7 +530,7 @@ function gen_config_server(node) } end settings = { - clients = clients, + users = users, decryption = (node.protocol == "vless") and ((node.decryption and node.decryption ~= "") and node.decryption or "none") or nil } end @@ -505,7 +538,7 @@ function gen_config_server(node) settings = { udp = ("1" == node.udp_forward) and true or false, auth = ("1" == node.auth) and "password" or "noauth", - accounts = ("1" == node.auth) and { + users = ("1" == node.auth) and { { user = node.username, pass = node.password @@ -515,7 +548,7 @@ function gen_config_server(node) elseif node.protocol == "http" then settings = { allowTransparent = false, - accounts = ("1" == node.auth) and { + users = ("1" == node.auth) and { { user = node.username, pass = node.password @@ -533,20 +566,20 @@ function gen_config_server(node) } elseif node.protocol == "trojan" then if node.uuid then - local clients = {} + local users = {} for i = 1, #node.uuid do - clients[i] = { - password = node.uuid[i] + users[i] = { + password = node.uuid[i], } end settings = { - clients = clients + users = users } end elseif node.protocol == "hysteria2" then settings = { version = 2, - clients = node.hysteria2_auth_password and { + users = node.hysteria2_auth_password and { { auth = node.hysteria2_auth_password } } } @@ -724,14 +757,36 @@ function gen_config_server(node) udp[#udp+1] = c finalmask.udp = udp elseif node.transport == "hysteria" then + local udp = {} if node.hysteria2_obfs_type and node.hysteria2_obfs_type ~= "" then - finalmask.udp = {{ - type = node.hysteria2_obfs_type, + local o = { + type = "salamander", settings = node.hysteria2_obfs_password and { - password = node.hysteria2_obfs_password + password = node.hysteria2_obfs_password, + packetSize = node.hysteria2_obfs_type == "gecko" and "512-1200" or nil } or nil - }} + } + udp[#udp+1] = o end + if node.hysteria2_realms then + local realm = api.parse_realm_uri(node.hysteria2_realm_url) + local url, stun + if realm then + if realm.token and realm.server_url and realm.realm_id then + url = "realm://" .. realm.token .. "@" .. realm.server_url .. "/" .. realm.realm_id + end + stun = realm.stun_servers or node.hysteria2_realm_stun + end + local r = { + type = "realm", + settings = { + url = url, + stunServers = stun + } + } + udp[#udp+1] = r + end + finalmask.udp = udp local ignore = tonumber(node.hysteria2_ignore_client_bandwidth) == 1 local up = (not ignore) and tonumber(node.hysteria2_up_mbps) or 0 local down = (not ignore) and tonumber(node.hysteria2_down_mbps) or 0 @@ -761,7 +816,7 @@ function gen_config_server(node) } local alpn = {} - if node.alpn then + if node.alpn and node.alpn ~= "default" then string.gsub(node.alpn, '[^' .. "," .. ']+', function(w) table.insert(alpn, w) end) @@ -907,7 +962,7 @@ function gen_config(var) end if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then inbound.settings.auth = "password" - inbound.settings.accounts = { + inbound.settings.users = { { user = local_socks_username, pass = local_socks_password @@ -925,7 +980,7 @@ function gen_config(var) settings = {allowTransparent = false} } if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then - inbound.settings.accounts = { + inbound.settings.users = { { user = local_http_username, pass = local_http_password @@ -2047,7 +2102,7 @@ function gen_proto_config(var) } if local_socks_username and local_socks_password and local_socks_username ~= "" and local_socks_password ~= "" then inbound.settings.auth = "password" - inbound.settings.accounts = { + inbound.settings.users = { { user = local_socks_username, pass = local_socks_password @@ -2067,7 +2122,7 @@ function gen_proto_config(var) } } if local_http_username and local_http_password and local_http_username ~= "" and local_http_password ~= "" then - inbound.settings.accounts = { + inbound.settings.users = { { user = local_http_username, pass = local_http_password diff --git a/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm b/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm index aec626b8e..c155754ec 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/global/backup.htm @@ -150,12 +150,9 @@ local api = require "luci.passwall2.api" if (confirm("<%: Do you want to restore the client to default settings?%>")) { setTimeout(function () { if (confirm("<%: Are you sure you want to restore the client to default settings?%>")) { - var xhr1 = new XMLHttpRequest(); - xhr1.open("GET",'<%= api.url("clear_log") %>', false); - xhr1.send(); - var xhr2 = new XMLHttpRequest(); - xhr2.open("GET",'<%= api.url("reset_config") %>', false); - xhr2.send(); + const xhr = new XMLHttpRequest(); + xhr.open("GET",'<%= api.url("reset_config") %>', false); + xhr.send(); window.location.href = '<%= api.url("log") %>' } }, 1000); diff --git a/luci-app-passwall2/luasrc/view/passwall2/node_config/link_share_man.htm b/luci-app-passwall2/luasrc/view/passwall2/node_config/link_share_man.htm index 7b7ed9a68..281283801 100644 --- a/luci-app-passwall2/luasrc/view/passwall2/node_config/link_share_man.htm +++ b/luci-app-passwall2/luasrc/view/passwall2/node_config/link_share_man.htm @@ -600,7 +600,7 @@ local current_node = map:get(section) v_password = opt.get("hysteria2_auth_password"); var dom_obfs = opt.get("hysteria2_obfs_password"); if (dom_obfs && dom_obfs.value != "") { - params += "&obfs=" + "salamander"; + params += opt.query("obfs", "hysteria2_obfs_type"); params += opt.query("obfs-password", "hysteria2_obfs_password"); } params += opt.query("mport", "hysteria2_hop"); @@ -1598,7 +1598,7 @@ local current_node = map:get(section) opt.set(dom_prefix + 'protocol', "hysteria2"); opt.set(dom_prefix + 'hysteria2_auth_password', decodeURIComponent(password)); if (queryParam["obfs-password"] || queryParam["obfs_password"]) { - opt.set(dom_prefix + 'hysteria2_obfs_type', "salamander"); + opt.set(dom_prefix + 'hysteria2_obfs_type', queryParam.obfs || "salamander"); opt.set(dom_prefix + 'hysteria2_obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]); } opt.set(dom_prefix + 'hysteria2_hop', queryParam.mport || ""); @@ -1609,7 +1609,7 @@ local current_node = map:get(section) dom_prefix = "hysteria2_" opt.set(dom_prefix + 'auth_password', decodeURIComponent(password)); if (queryParam["obfs-password"] || queryParam["obfs_password"]) { - opt.set(dom_prefix + 'obfs_type', "salamander"); + opt.set(dom_prefix + 'obfs_type', queryParam.obfs || "salamander"); opt.set(dom_prefix + 'obfs_password', queryParam["obfs-password"] || queryParam["obfs_password"]); } opt.set(dom_prefix + 'hop', queryParam.mport || ""); diff --git a/luci-app-passwall2/po/fa/passwall2.po b/luci-app-passwall2/po/fa/passwall2.po index dfb606698..e2cf45c5a 100644 --- a/luci-app-passwall2/po/fa/passwall2.po +++ b/luci-app-passwall2/po/fa/passwall2.po @@ -1656,6 +1656,12 @@ msgstr "نام گواهی TLS (CertName)" msgid "TLS is used to verify the leaf certificate name." msgstr "TLS برای تأیید نام گواهی برگ (Leaf Certificate) استفاده می‌شود." +msgid "TLS Certificate (PEM)" +msgstr "گواهی TLS (PEM)" + +msgid "Full certificate (chain), PEM format." +msgstr "گواهی کامل (زنجیره‌ای)، فرمت PEM." + msgid "ECH Config" msgstr "پیکربندی ECH" @@ -2281,8 +2287,8 @@ msgstr "نادیده گرفتن گره %s به دلیل ناسازگاری با msgid "Skip node: %s. Because Sing-Box does not support the %s protocol's %s transmission method, Xray needs to be used instead." msgstr "صرف‌نظر از گره: %s. زیرا Sing-Box از روش انتقال %s پروتکل %s پشتیبانی نمی‌کند، باید به جای آن از Xray استفاده شود." -msgid "Xray unsupport %s plugin." -msgstr "Xray از افزونه %s پشتیبانی نمی‌کند." +msgid "%s unsupport SS %s plugin." +msgstr "%s از افزونه %s پشتیبانی نمی‌کند." msgid "Plugin options Incomplete." msgstr "گزینه‌های افزونه ناقص است." diff --git a/luci-app-passwall2/po/ru/passwall2.po b/luci-app-passwall2/po/ru/passwall2.po index cb5b89690..be21069c7 100644 --- a/luci-app-passwall2/po/ru/passwall2.po +++ b/luci-app-passwall2/po/ru/passwall2.po @@ -1657,6 +1657,12 @@ msgstr "Имя TLS-сертификата (CertName)" msgid "TLS is used to verify the leaf certificate name." msgstr "Используется TLS для проверки имени конечного сертификата." +msgid "TLS Certificate (PEM)" +msgstr "Сертификат TLS (PEM)" + +msgid "Full certificate (chain), PEM format." +msgstr "Полный сертификат (цепочка), формат PEM." + msgid "ECH Config" msgstr "Конфигурация ECH" @@ -2279,8 +2285,8 @@ msgstr "Пропуск сервера %s: несовместимость с яд msgid "Skip node: %s. Because Sing-Box does not support the %s protocol's %s transmission method, Xray needs to be used instead." msgstr "Пропуск сервера: %s. Sing-Box не поддерживает метод передачи %s протокола %s, необходимо использовать Xray." -msgid "Xray unsupport %s plugin." -msgstr "Xray не поддерживает плагин %s." +msgid "%s unsupport SS %s plugin." +msgstr "%s не поддерживает плагин %s." msgid "Plugin options Incomplete." msgstr "Опции плагина указаны не полностью." diff --git a/luci-app-passwall2/po/zh-cn/passwall2.po b/luci-app-passwall2/po/zh-cn/passwall2.po index 1010101ba..026e4e918 100644 --- a/luci-app-passwall2/po/zh-cn/passwall2.po +++ b/luci-app-passwall2/po/zh-cn/passwall2.po @@ -1648,6 +1648,12 @@ msgstr "TLS 证书名称(CertName)" msgid "TLS is used to verify the leaf certificate name." msgstr "TLS 用于验证 leaf 证书的 name。" +msgid "TLS Certificate (PEM)" +msgstr "TLS 证书(PEM)" + +msgid "Full certificate (chain), PEM format." +msgstr "完整证书(链),PEM 格式。" + msgid "ECH Config" msgstr "ECH 配置" @@ -2267,8 +2273,8 @@ msgstr "跳过 %s 节点,因未适配到 %s 核心程序,或未正确设置 msgid "Skip node: %s. Because Sing-Box does not support the %s protocol's %s transmission method, Xray needs to be used instead." msgstr "跳过节点:%s,因 Sing-Box 不支持 %s 协议的 %s 传输方式,需更换 Xray。" -msgid "Xray unsupport %s plugin." -msgstr "Xray 不支持 %s 插件。" +msgid "%s unsupport SS %s plugin." +msgstr "%s 不支持 %s 插件。" msgid "Plugin options Incomplete." msgstr "插件选项不完整。" diff --git a/luci-app-passwall2/po/zh-tw/passwall2.po b/luci-app-passwall2/po/zh-tw/passwall2.po index efea133a3..cf6d30896 100644 --- a/luci-app-passwall2/po/zh-tw/passwall2.po +++ b/luci-app-passwall2/po/zh-tw/passwall2.po @@ -1648,6 +1648,12 @@ msgstr "TLS 憑證名稱(CertName)" msgid "TLS is used to verify the leaf certificate name." msgstr "TLS 用於驗證 leaf 憑證的 name。" +msgid "TLS Certificate (PEM)" +msgstr "TLS 憑證(PEM)" + +msgid "Full certificate (chain), PEM format." +msgstr "完整憑證(鏈),PEM 格式。" + msgid "ECH Config" msgstr "ECH 配置" @@ -2273,8 +2279,8 @@ msgstr "跳過 %s 節點,因未適配到 %s 核心程序,或未正確設置 msgid "Skip node: %s. Because Sing-Box does not support the %s protocol's %s transmission method, Xray needs to be used instead." msgstr "跳過節點:%s,因 Sing-Box 不支持 %s 協議的 %s 傳輸方式,需更換 Xray。" -msgid "Xray unsupport %s plugin." -msgstr "Xray 不支持 %s 插件。" +msgid "%s unsupport SS %s plugin." +msgstr "%s 不支持 %s 插件。" msgid "Plugin options Incomplete." msgstr "插件選項不完整。" diff --git a/luci-app-passwall2/root/usr/share/passwall2/app.sh b/luci-app-passwall2/root/usr/share/passwall2/app.sh index b65a32176..4a159e82d 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/app.sh +++ b/luci-app-passwall2/root/usr/share/passwall2/app.sh @@ -1012,9 +1012,10 @@ acl_app() { [ -n "$items" ] && { local index=0 local item - local redir_port dns_port dnsmasq_port + local redir_port dns_port dnsmasq_port socks_port local ipt_tmp msg msg2 redir_port=11200 + socks_port=11600 dns_port=11300 dnsmasq_port=${GLOBAL_DNSMASQ_PORT:-11400} for item in $items; do @@ -1098,12 +1099,13 @@ acl_app() { set_cache_var "ACL_${sid}_default" "1" else redir_port=$(get_new_port $(expr $redir_port + 1)) + socks_port=$(get_new_port $(expr $socks_port + 1)) local type=$(echo $(config_n_get $node type) | tr 'A-Z' 'a-z') if [ -n "${type}" ]; then config_file=$TMP_ACL_PATH/${node}_TCP_UDP_DNS_${redir_port}.json dns_port=$(get_new_port $(expr $dns_port + 1)) - local acl_socks_port=$(get_new_port $(expr $redir_port + $index)) + local acl_socks_port=$socks_port local run_func [ -n "${XRAY_BIN}" ] && run_func="run_xray" [ -n "${SINGBOX_BIN}" ] && run_func="run_singbox" diff --git a/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua b/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua index 35104922d..f8c8f01e4 100755 --- a/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua +++ b/luci-app-passwall2/root/usr/share/passwall2/subscribe.lua @@ -528,36 +528,50 @@ local function parseClashNode(node, add_mode, group, sub_cfg) elseif node.plugin == "v2ray-plugin" then result.plugin = "v2ray-plugin" end - if node["plugin-opts"] then - if node.plugin == "obfs" then - local plugin_opts = "" - local opts_mode = node["plugin-opts"].mode - if opts_mode then - plugin_opts = plugin_opts .. "obfs=" .. opts_mode .. ";" + if result.plugin then + result.plugin_enabled = "1" + if result.type == 'Xray' then + if result.plugin ~= "obfs-local" then + result.plugin_enabled = nil + result.error_msg = i18n.translatef("%s unsupport SS %s plugin.", "Xray", result.plugin) end - local opts_host = node["plugin-opts"].host - if opts_host then - plugin_opts = plugin_opts .. "obfs-host=" .. opts_host + elseif result.type == 'sing-box' then + if result.plugin ~= "obfs-local" and result.plugin ~= "v2ray-plugin" then + result.plugin_enabled = nil + result.error_msg = i18n.translatef("%s unsupport SS %s plugin.", "Sing-Box", result.plugin) end - result.plugin_opts = plugin_opts - elseif node.plugin == "v2ray-plugin" then - local plugin_opts = "" - local opts_mode = node["plugin-opts"].mode - local opts_tls = node["plugin-opts"].tls - if opts_tls then - plugin_opts = plugin_opts .. "tls;" + end + if node["plugin-opts"] and result.plugin_enabled == "1" then + if node.plugin == "obfs" then + local plugin_opts = "" + local opts_mode = node["plugin-opts"].mode + if opts_mode then + plugin_opts = plugin_opts .. "obfs=" .. opts_mode .. ";" + end + local opts_host = node["plugin-opts"].host + if opts_host then + plugin_opts = plugin_opts .. "obfs-host=" .. opts_host + end + result.plugin_opts = plugin_opts + elseif node.plugin == "v2ray-plugin" then + local plugin_opts = "" + local opts_mode = node["plugin-opts"].mode + local opts_tls = node["plugin-opts"].tls + if opts_tls then + plugin_opts = plugin_opts .. "tls;" + end + local opts_skip_cert_verify = node["plugin-opts"]["skip-cert-verify"] + local opts_host = node["plugin-opts"].host + if opts_host then + plugin_opts = plugin_opts .. "host=" .. opts_host .. ";" + end + local opts_path = node["plugin-opts"].path + local opts_mux = node["plugin-opts"].mux + if node["plugin-opts"].headers then + --todo + end + result.plugin_opts = plugin_opts end - local opts_skip_cert_verify = node["plugin-opts"]["skip-cert-verify"] - local opts_host = node["plugin-opts"].host - if opts_host then - plugin_opts = plugin_opts .. "host=" .. opts_host .. ";" - end - local opts_path = node["plugin-opts"].path - local opts_mux = node["plugin-opts"].mux - if node["plugin-opts"].headers then - --todo - end - result.plugin_opts = plugin_opts end end elseif node.type == 'ssr' then @@ -961,6 +975,11 @@ local function processData(szType, content, add_mode, group, sub_cfg) result.tls = "0" end + if info.ech and info.ech ~= "" then + result.ech = "1" + result.ech_config = info.ech + end + result.tcp_fast_open = info.tfo info.fm = (info.fm and info.fm ~= "") and UrlDecode(info.fm) or nil @@ -1090,7 +1109,7 @@ local function processData(szType, content, add_mode, group, sub_cfg) if result.type == 'Xray' then -- The obfs-local plugin converts data to a format supported by xray. if result.plugin ~= "obfs-local" then - result.error_msg = i18n.translatef("Xray unsupport %s plugin.", result.plugin) + result.error_msg = i18n.translatef("%s unsupport SS %s plugin.", "Xray", result.plugin) else local obfs = result.plugin_opts:match("obfs=([^;]+)") or "" local obfs_host = result.plugin_opts:match("obfs%-host=([^;]+)") or "" @@ -1110,6 +1129,12 @@ local function processData(szType, content, add_mode, group, sub_cfg) result.plugin = nil result.plugin_opts = nil end + elseif result.type == 'sing-box' then + if result.plugin ~= "obfs-local" and result.plugin ~= "v2ray-plugin" then + result.error_msg = i18n.translatef("%s unsupport SS %s plugin.", "Sing-Box", result.plugin) + else + result.plugin_enabled = "1" + end else result.plugin_enabled = "1" end @@ -1223,7 +1248,7 @@ local function processData(szType, content, add_mode, group, sub_cfg) local insecure = params.allowinsecure or params.allowInsecure or params.insecure result.tls_allowInsecure = (insecure == "1" or insecure == "0") and insecure or (sub_allowinsecure and "1" or "0") result.uot = params.udp - elseif (params.type ~= "tcp" and params.type ~= "raw") and (params.headerType and params.headerType ~= "none") then + else result.error_msg = i18n.translatef("Please replace Xray or Sing-Box to support more transmission methods in Shadowsocks.") end end @@ -1684,7 +1709,7 @@ local function processData(szType, content, add_mode, group, sub_cfg) result.hysteria2_down_mbps = params.downmbps or sub_hy_down_mbps result.hysteria2_hop = params.mport if params["obfs-password"] or params["obfs_password"] then - result.hysteria2_obfs_type = "salamander" + result.hysteria2_obfs_type = params.obfs or "salamander" result.hysteria2_obfs_password = params["obfs-password"] or params["obfs_password"] end @@ -1818,6 +1843,10 @@ local function processData(szType, content, add_mode, group, sub_cfg) result.reality_publicKey = params.pbk or nil result.reality_shortId = params.sid or nil end + if params.ech and params.ech ~= "" then + result.ech = "1" + result.ech_config = params.ech + end end result.port = port local insecure = params.allowinsecure or params.insecure diff --git a/openwrt-fastfetch/Makefile b/openwrt-fastfetch/Makefile index cd2bad2e4..2edb28420 100644 --- a/openwrt-fastfetch/Makefile +++ b/openwrt-fastfetch/Makefile @@ -5,8 +5,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=fastfetch -PKG_VERSION:=2.63.1 -PKG_RELEASE:=6 +PKG_VERSION:=2.64.0 +PKG_RELEASE:=7 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/fastfetch-cli/fastfetch/tar.gz/$(PKG_VERSION)? diff --git a/opera-proxy/Makefile b/opera-proxy/Makefile new file mode 100644 index 000000000..56c53c96e --- /dev/null +++ b/opera-proxy/Makefile @@ -0,0 +1,88 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=opera-proxy +PKG_VERSION:=1.22.0 +PKG_RELEASE:=1 + +PKG_MAINTAINER:=Konstantine Shevlakov +PKG_LICENSE:=MIT + +PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(PKG_VERSION) + +# --- Маппинг OpenWrt ARCH+CPU → имя бинарника на GitHub --- +# Формат имён на GitHub: opera-proxy.linux- +# +# OpenWrt $(ARCH) / $(CONFIG_CPU_TYPE) → суффикс GitHub +# mips / 24kc → mips +# mipsel / 24kc → mipsle +# aarch64 / cortex-a53 и др. → arm64 +# arm / cortex-a7 и др. → arm +# arm / cortex-a9+vfpv3 → arm (armv6 нет, ближайший arm) +# x86_64 / - → amd64 +# i386 / - → 386 + +ifeq ($(ARCH),mips) + GOARCH_SUFFIX:=mips +else ifeq ($(ARCH),mipsel) + GOARCH_SUFFIX:=mipsle +else ifeq ($(ARCH),mips64) + GOARCH_SUFFIX:=mips64 +else ifeq ($(ARCH),mips64el) + GOARCH_SUFFIX:=mips64le +else ifeq ($(ARCH),aarch64) + GOARCH_SUFFIX:=arm64 +else ifeq ($(ARCH),arm) + GOARCH_SUFFIX:=arm +else ifeq ($(ARCH),x86_64) + GOARCH_SUFFIX:=amd64 +else ifeq ($(ARCH),i386) + GOARCH_SUFFIX:=386 +else + GOARCH_SUFFIX:=$(ARCH) +endif + +PKG_SOURCE_URL:=https://github.com/Alexey71/opera-proxy/releases/download/v$(PKG_VERSION) +PKG_SOURCE:=opera-proxy.linux-$(GOARCH_SUFFIX) +PKG_HASH:=skip + +include $(INCLUDE_DIR)/package.mk + +define Package/opera-proxy + SECTION:=net + CATEGORY:=Network + TITLE:=Standalone Opera VPN proxy client + URL:=https://github.com/Alexey71/opera-proxy + DEPENDS:= +endef + +define Package/opera-proxy/description + Standalone Opera VPN client. Starts a plain HTTP/SOCKS5 proxy server + forwarding traffic through Opera VPN proxies. + Supports country selection: EU, AS, AM. +endef + +define Package/opera-proxy/conffiles +/etc/config/opera-proxy +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) $(DL_DIR)/$(PKG_SOURCE) $(PKG_BUILD_DIR)/opera-proxy + chmod +x $(PKG_BUILD_DIR)/opera-proxy +endef + +define Build/Compile +endef + +define Package/opera-proxy/install + $(INSTALL_DIR) $(1)/usr/bin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/opera-proxy $(1)/usr/bin/opera-proxy + + $(INSTALL_DIR) $(1)/etc/init.d + $(INSTALL_BIN) $(CURDIR)/files/opera-proxy.init $(1)/etc/init.d/opera-proxy + + $(INSTALL_DIR) $(1)/etc/config + $(INSTALL_CONF) $(CURDIR)/files/opera-proxy.config $(1)/etc/config/opera-proxy +endef + +$(eval $(call BuildPackage,opera-proxy)) diff --git a/opera-proxy/files/opera-proxy.config b/opera-proxy/files/opera-proxy.config new file mode 100644 index 000000000..45e6a3d35 --- /dev/null +++ b/opera-proxy/files/opera-proxy.config @@ -0,0 +1,6 @@ +config opera-proxy 'main' + option country 'EU' + option bind_address '127.0.0.1:18080' + option verbosity '20' + option timeout '10s' + option socks_mode '0' diff --git a/opera-proxy/files/opera-proxy.init b/opera-proxy/files/opera-proxy.init new file mode 100755 index 000000000..0442804d1 --- /dev/null +++ b/opera-proxy/files/opera-proxy.init @@ -0,0 +1,42 @@ +#!/bin/sh /etc/rc.common + +USE_PROCD=1 +START=90 +STOP=10 + +NAME=opera-proxy +PROG=/usr/bin/${NAME} + +start_service() { + local country bind_address verbosity socks_mode timeout + + config_load opera-proxy + config_get country main country "EU" + config_get bind_address main bind_address "127.0.0.1:18080" + config_get verbosity main verbosity "20" + config_get timeout main timeout "10s" + config_get_bool socks_mode main socks_mode 0 + + procd_open_instance + procd_set_param command "$PROG" + procd_append_param command -country "$country" + procd_append_param command -bind-address "$bind_address" + procd_append_param command -verbosity "$verbosity" + procd_append_param command -timeout "$timeout" + + [ "$socks_mode" = "1" ] && procd_append_param command -socks-mode + + procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5} + procd_set_param stdout 1 + procd_set_param stderr 1 + procd_close_instance +} + +reload_service() { + stop + start +} + +service_triggers() { + procd_add_reload_trigger "opera-proxy" +} diff --git a/qBittorrent-Enhanced-Edition/Makefile b/qBittorrent-Enhanced-Edition/Makefile index 84259296f..b78ab4364 100644 --- a/qBittorrent-Enhanced-Edition/Makefile +++ b/qBittorrent-Enhanced-Edition/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=qBittorrent-Enhanced-Edition -PKG_VERSION:=5.1.3.10 -PKG_RELEASE:=7 +PKG_VERSION:=5.2.1.10 +PKG_RELEASE:=8 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/c0re100/qBittorrent-Enhanced-Edition/tar.gz/release-$(PKG_VERSION)? diff --git a/teleproxy/Makefile b/teleproxy/Makefile index 7715a1df7..296911877 100644 --- a/teleproxy/Makefile +++ b/teleproxy/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=teleproxy -PKG_VERSION:=4.14.1 -PKG_RELEASE:=17 +PKG_VERSION:=4.15.0 +PKG_RELEASE:=18 PKG_MAINTAINER:=Kosntantine Shevlakov PKG_LICENSE:=GPLv2