mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-03 07:03:56 +08:00
update 2026-10-05 19:05:58
This commit is contained in:
1 parent
ce2c617af4
commit
ec960a1df0
185 files changed
+212
-41511
No files matched your search
@@ -37,6 +37,7 @@ local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | aw
|
||||
|
||||
local singbox_version = api.get_app_version("sing-box"):match("[^v]+")
|
||||
local version_ge_1_14_0 = api.compare_versions(singbox_version, ">=", "1.14.0")
|
||||
local version_ge_1_15_0 = api.compare_versions(singbox_version, ">=", "1.15.0")
|
||||
|
||||
o = s:option(ListValue, "protocol", translate("Protocol"))
|
||||
o:value("socks", "Socks")
|
||||
@@ -65,6 +66,9 @@ end
|
||||
if version_ge_1_14_0 then
|
||||
o:value("snell", "Snell")
|
||||
end
|
||||
if version_ge_1_15_0 and singbox_tags:find("with_quic") then
|
||||
o:value("masque", "MASQUE")
|
||||
end
|
||||
o:value("_urltest", translate("URLTest"))
|
||||
o:value("_shunt", translate("Shunt"))
|
||||
o:value("_iface", translate("Custom Interface"))
|
||||
@@ -193,6 +197,7 @@ o:depends({ protocol = "http" })
|
||||
o:depends({ protocol = "socks" })
|
||||
o:depends({ protocol = "ssh" })
|
||||
o:depends({ protocol = "naive" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(Value, "password", translate("Password"))
|
||||
o.password = true
|
||||
@@ -204,6 +209,34 @@ o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "anytls" })
|
||||
o:depends({ protocol = "ssh" })
|
||||
o:depends({ protocol = "naive" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
-- [[ MASQUE ]] --
|
||||
o = s:option(Value, "masque_path", translate("MASQUE Path"))
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(TextValue, "masque_headers", translate("Custom HTTP Headers"))
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ protocol = "masque" })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "masque_headers") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n")
|
||||
local headers = {}
|
||||
for line in value:gmatch("[^\n]+") do
|
||||
if api.trim(line) ~= "" then
|
||||
local key = line:match("^%s*([^:]+):")
|
||||
key = key and api.trim(key):lower()
|
||||
if not key or not key:match("^[!#$%%&'*+%.%^_`|~%w%-]+$") or headers[key] then
|
||||
return nil, translate("Not true format, please re-enter!") .. " (" .. line .. ")"
|
||||
end
|
||||
headers[key] = true
|
||||
end
|
||||
end
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
if version_ge_1_14_0 then
|
||||
-- snell
|
||||
@@ -523,6 +556,7 @@ o:depends({ tls = true })
|
||||
o:depends({ protocol = "hysteria"})
|
||||
o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(Value, "tls_serverName", "SNI " .. translate("Domain"))
|
||||
o:depends({ tls = true })
|
||||
@@ -530,6 +564,7 @@ o:depends({ protocol = "hysteria"})
|
||||
o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ protocol = "naive" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(Flag, "tls_allowInsecure", translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped."))
|
||||
o.default = "0"
|
||||
@@ -537,12 +572,14 @@ o:depends({ tls = true })
|
||||
o:depends({ protocol = "hysteria" })
|
||||
o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(Value, "tls_pinSHA256", translate("TLS Chain Fingerprint (SHA256)"))
|
||||
o:depends({ tls = true })
|
||||
o:depends({ protocol = "hysteria" })
|
||||
o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ protocol = "masque" })
|
||||
o.description = translate("Once set, connects only when the server’s chain fingerprint matches.") ..
|
||||
string.format("<a href='javascript:void(0)' onclick='javascript:fetchCertSha256(this)'>%s</a>", "→ " .. translate("Fetch Manually"))
|
||||
|
||||
@@ -553,6 +590,7 @@ o:depends({ protocol = "hysteria"})
|
||||
o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ protocol = "naive" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(TextValue, "tls_certificate_pem", " ", translate("Full certificate (chain), PEM format."))
|
||||
o.default = ""
|
||||
@@ -569,6 +607,7 @@ end
|
||||
|
||||
o = s:option(Value, "cipherSuites", translate("Cipher Suites"), '<a href="https://go.dev/src/crypto/tls/cipher_suites.go#L44" target="_blank">***</a>' .. " " .. translate("Configures the list of supported cipher suites, separated by :"))
|
||||
o:depends({ tls = true })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(Flag, "ech", translate("ECH"))
|
||||
o.default = "0"
|
||||
@@ -577,6 +616,7 @@ o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria" })
|
||||
o:depends({ protocol = "hysteria2", hysteria2_realms = false })
|
||||
o:depends({ protocol = "naive" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(TextValue, "ech_config", translate("ECH Config"))
|
||||
o.default = ""
|
||||
@@ -750,6 +790,7 @@ o:depends({ transport = "http" })
|
||||
o:depends({ transport = "ws" })
|
||||
o:depends({ transport = "httpupgrade" })
|
||||
o:depends({ protocol = "naive" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
-- [[ Mux ]]--
|
||||
o = s:option(Flag, "mux", translate("Mux"))
|
||||
|
||||
@@ -44,6 +44,9 @@ o:value("wireguard", translate("WireGuard"))
|
||||
if api.compare_versions(xray_version, ">=", "26.1.13") then
|
||||
o:value("hysteria2", translate("Hysteria2"))
|
||||
end
|
||||
if api.compare_versions(xray_version, ">=", "26.9.30") then
|
||||
o:value("masque", "MASQUE")
|
||||
end
|
||||
if api.compare_versions(xray_version, ">=", "1.8.12") then
|
||||
o:value("_balancing", translate("Balancing"))
|
||||
end
|
||||
@@ -260,6 +263,7 @@ o:depends({ protocol = "vless" })
|
||||
o = s:option(Value, "username", translate("Username"))
|
||||
o:depends({ protocol = "http" })
|
||||
o:depends({ protocol = "socks" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(Value, "password", translate("Password"))
|
||||
o.password = true
|
||||
@@ -267,6 +271,34 @@ o:depends({ protocol = "http" })
|
||||
o:depends({ protocol = "socks" })
|
||||
o:depends({ protocol = "shadowsocks" })
|
||||
o:depends({ protocol = "trojan" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
-- [[ MASQUE ]] --
|
||||
o = s:option(Value, "masque_path", translate("MASQUE Path"))
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(TextValue, "masque_headers", translate("Custom HTTP Headers"))
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ protocol = "masque" })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "masque_headers") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n")
|
||||
local headers = {}
|
||||
for line in value:gmatch("[^\n]+") do
|
||||
if api.trim(line) ~= "" then
|
||||
local key = line:match("^%s*([^:]+):")
|
||||
key = key and api.trim(key):lower()
|
||||
if not key or not key:match("^[!#$%%&'*+%.%^_`|~%w%-]+$") or headers[key] or key == "host" or key == "capsule-protocol" then
|
||||
return nil, translate("Not true format, please re-enter!") .. " (" .. line .. ")"
|
||||
end
|
||||
headers[key] = true
|
||||
end
|
||||
end
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
o = s:option(ListValue, "security", translate("Encrypt Method"))
|
||||
for a, t in ipairs(security_list) do o:value(t) end
|
||||
@@ -419,21 +451,25 @@ o:depends({ tls = true, reality = false })
|
||||
o = s:option(Value, "tls_serverName", "SNI " .. translate("Domain"))
|
||||
o:depends({ tls = true })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(Value, "tls_pinSHA256", translate("TLS Chain Fingerprint (SHA256)"))
|
||||
o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ protocol = "masque" })
|
||||
o.description = translate("Once set, connects only when the server’s chain fingerprint matches.") ..
|
||||
string.format("<a href='javascript:void(0)' onclick='javascript:fetchCertSha256(this)'>%s</a>", "→ " .. translate("Fetch Manually"))
|
||||
|
||||
o = s:option(Value, "tls_CertByName", translate("TLS Certificate Name (CertName)"), translate("TLS is used to verify the leaf certificate name."))
|
||||
o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(Flag, "tls_certificate", translate("TLS Certificate (PEM)"))
|
||||
o.default = "0"
|
||||
o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(TextValue, "tls_certificate_pem", " ", translate("Full certificate (chain), PEM format."))
|
||||
o.default = ""
|
||||
@@ -452,6 +488,7 @@ o = s:option(Flag, "ech", translate("ECH"))
|
||||
o.default = "0"
|
||||
o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "hysteria2", hysteria2_realms = false })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(TextValue, "ech_config", translate("ECH Config"))
|
||||
o.default = ""
|
||||
@@ -495,6 +532,7 @@ o:depends({ tls = true, reality = true })
|
||||
|
||||
o = s:option(Value, "cipherSuites", translate("Cipher Suites"), '<a href="https://go.dev/src/crypto/tls/cipher_suites.go#L44" target="_blank">***</a>' .. " " .. translate("Configures the list of supported cipher suites, separated by :"))
|
||||
o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
o = s:option(Flag, "use_mldsa65Verify", translate("ML-DSA-65"))
|
||||
o.default = "0"
|
||||
@@ -702,6 +740,7 @@ o:depends({ transport = "ws" })
|
||||
o:depends({ transport = "httpupgrade" })
|
||||
o:depends({ transport = "xhttp" })
|
||||
o:depends({ transport = "grpc" })
|
||||
o:depends({ protocol = "masque" })
|
||||
|
||||
-- [[ Mux.Cool ]]--
|
||||
o = s:option(Flag, "mux", "Mux", translate("Enable Mux.Cool"))
|
||||
|
||||
@@ -1462,10 +1462,7 @@ function to_check_self()
|
||||
release = release[1]
|
||||
end
|
||||
if type(release) ~= "table" or not release.tag_name then
|
||||
return {
|
||||
code = 1,
|
||||
error = i18n.translate("Get remote version info failed.")
|
||||
}
|
||||
return {code = 1, error = i18n.translate("Get remote version info failed.")}
|
||||
end
|
||||
local local_version = get_version()
|
||||
-- Keep the release suffix (-1, -2, ...) so package revisions are compared too.
|
||||
@@ -1482,15 +1479,20 @@ function to_check_self()
|
||||
extension = ".ipk"
|
||||
end
|
||||
local main, i18n_package
|
||||
for _, asset in ipairs(release.assets or {}) do
|
||||
local name = asset.name or ""
|
||||
if name:find(prefix, 1, true) == 1 and name:sub(-#extension) == extension then
|
||||
name = name:sub(#prefix + 1)
|
||||
if name:match("^luci%-app%-" .. appname .. "[_%-]%d") then main = asset end
|
||||
if name:match("^luci%-i18n%-" .. appname .. "%-zh%-cn[_%-]%d") then i18n_package = asset end
|
||||
for _, search_prefix in ipairs({prefix, ""}) do
|
||||
for _, asset in ipairs(release.assets or {}) do
|
||||
local name = asset.name or ""
|
||||
if name:find(search_prefix, 1, true) == 1 and name:sub(-#extension) == extension then
|
||||
name = name:sub(#search_prefix + 1)
|
||||
if not main and name:match("^luci%-app%-" .. appname .. "[_%-]%d") then main = asset end
|
||||
if not i18n_package and name:match("^luci%-i18n%-" .. appname .. "%-zh%-cn[_%-]%d") then i18n_package = asset end
|
||||
end
|
||||
end
|
||||
if main and i18n_package then break end
|
||||
end
|
||||
if not main or not i18n_package then
|
||||
return {code = 1, error = i18n.translate("Get remote version info failed.")}
|
||||
end
|
||||
if not main or not i18n_package then return {code = 1} end
|
||||
return {
|
||||
code = 0, has_update = has_update, local_version = local_version,
|
||||
remote_version = remote_version, html_url = release.html_url,
|
||||
|
||||
@@ -96,8 +96,8 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
local proxy_tag, fragment, record_fragment
|
||||
if proxy_table ~= nil and type(proxy_table) == "table" then
|
||||
proxy_tag = proxy_table.tag or nil
|
||||
fragment = (proxy_table.fragment and node.protocol ~= "naive" and not node.hysteria2_realms) and true or nil
|
||||
record_fragment = (proxy_table.record_fragment and node.protocol ~= "naive" and not node.hysteria2_realms) and true or nil
|
||||
fragment = (proxy_table.fragment and node.protocol ~= "naive" and node.protocol ~= "masque" and not node.hysteria2_realms) and true or nil
|
||||
record_fragment = (proxy_table.record_fragment and node.protocol ~= "naive" and node.protocol ~= "masque" and not node.hysteria2_realms) and true or nil
|
||||
end
|
||||
|
||||
if node.type ~= "sing-box" then
|
||||
@@ -227,7 +227,14 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
end
|
||||
|
||||
local tls = nil
|
||||
if node.protocol == "hysteria" or node.protocol == "hysteria2" or node.protocol == "tuic" or node.protocol == "naive" then
|
||||
if node.protocol == "masque" then
|
||||
node.alpn = nil
|
||||
node.utls = nil
|
||||
node.reality = nil
|
||||
node.transport = nil
|
||||
node.mux = nil
|
||||
end
|
||||
if node.protocol == "hysteria" or node.protocol == "hysteria2" or node.protocol == "tuic" or node.protocol == "naive" or node.protocol == "masque" then
|
||||
node.tls = "1"
|
||||
end
|
||||
if node.tls == "1" then
|
||||
@@ -687,6 +694,25 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
}
|
||||
end
|
||||
|
||||
if node.protocol == "masque" then
|
||||
local headers = {}
|
||||
if node.user_agent and node.user_agent ~= "" then
|
||||
headers["user-agent"] = { node.user_agent }
|
||||
end
|
||||
for line in (node.masque_headers or ""):gsub("\\n", "\n"):gmatch("[^\r\n]+") do
|
||||
local key, value = line:match("^%s*([^:]+):%s*(.-)%s*$")
|
||||
if key then headers[api.trim(key):lower()] = { value } end
|
||||
end
|
||||
protocol_table = {
|
||||
type = "masque-client",
|
||||
username = not headers.authorization and node.username or nil,
|
||||
password = not headers.authorization and node.password or nil,
|
||||
path = (node.masque_path and node.masque_path ~= "") and node.masque_path or nil,
|
||||
headers = next(headers) and headers or nil,
|
||||
tls = tls
|
||||
}
|
||||
end
|
||||
|
||||
if node.protocol == "snell" then
|
||||
protocol_table = {
|
||||
version = tonumber(node.snell_version),
|
||||
@@ -2389,6 +2415,9 @@ function gen_config(var)
|
||||
}
|
||||
endpoints[#endpoints + 1] = endpoint
|
||||
table.remove(config.outbounds, i)
|
||||
elseif value.type == "masque-client" then
|
||||
endpoints[#endpoints + 1] = value
|
||||
table.remove(config.outbounds, i)
|
||||
end
|
||||
end
|
||||
if #endpoints > 0 then
|
||||
|
||||
@@ -135,6 +135,13 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
node.transport = "hysteria"
|
||||
node.stream_security = "tls"
|
||||
end
|
||||
if node.protocol == "masque" then
|
||||
node.transport = "masque"
|
||||
node.stream_security = "tls"
|
||||
node.alpn = nil
|
||||
node.utls = nil
|
||||
node.finalmask = nil
|
||||
end
|
||||
|
||||
if node.protocol == "http" and node.stream_security == "tls" then
|
||||
node.transport = "raw"
|
||||
@@ -152,13 +159,13 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
_flag_proxy_tag = proxy_tag,
|
||||
tag = tag,
|
||||
protocol = node.protocol,
|
||||
mux = {
|
||||
mux = (node.protocol ~= "masque") and {
|
||||
enabled = (node.mux == "1") and true or false,
|
||||
concurrency = (node.mux == "1" and ((node.mux_concurrency) and tonumber(node.mux_concurrency) or -1)) or nil,
|
||||
xudpConcurrency = (node.mux == "1" and ((node.xudp_concurrency) and tonumber(node.xudp_concurrency) or 8)) or nil
|
||||
} or nil,
|
||||
-- 底层传输配置
|
||||
streamSettings = (node.streamSettings or dialer_proxy_tag or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria" or node.protocol == "http") and {
|
||||
streamSettings = (node.streamSettings or dialer_proxy_tag or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria" or node.protocol == "http" or node.protocol == "masque") and {
|
||||
sockopt = {
|
||||
mark = 255,
|
||||
domainStrategy = node.domain_strategy or "UseIP",
|
||||
@@ -268,6 +275,23 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
return api.cleanEmptyTables(extra)
|
||||
end)()
|
||||
} or nil,
|
||||
masqueSettings = (node.protocol == "masque") and {
|
||||
path = (node.masque_path and node.masque_path ~= "") and node.masque_path or nil,
|
||||
headers = (function()
|
||||
local headers = {}
|
||||
if (node.username and node.username ~= "") or (node.password and node.password ~= "") then
|
||||
headers["authorization"] = "Basic " .. api.base64Encode((node.username or "") .. ":" .. (node.password or ""))
|
||||
end
|
||||
if node.user_agent and node.user_agent ~= "" then
|
||||
headers["user-agent"] = node.user_agent
|
||||
end
|
||||
for line in (node.masque_headers or ""):gsub("\\n", "\n"):gmatch("[^\r\n]+") do
|
||||
local key, value = line:match("^%s*([^:]+):%s*(.-)%s*$")
|
||||
if key then headers[api.trim(key):lower()] = value end
|
||||
end
|
||||
return next(headers) and headers or nil
|
||||
end)()
|
||||
} or nil,
|
||||
hysteriaSettings = (node.transport == "hysteria") and {
|
||||
version = 2,
|
||||
auth = node.hysteria2_auth_password
|
||||
|
||||
@@ -2177,3 +2177,9 @@ msgstr "更新失败"
|
||||
|
||||
msgid "Unknown error"
|
||||
msgstr "未知错误"
|
||||
|
||||
msgid "MASQUE Path"
|
||||
msgstr "MASQUE 路径"
|
||||
|
||||
msgid "Custom HTTP Headers"
|
||||
msgstr "自定义 HTTP 请求头"
|
||||
@@ -946,7 +946,7 @@ start_crontab() {
|
||||
clean_crontab
|
||||
|
||||
if [ "$ENABLED" != "1" ]; then
|
||||
/etc/init.d/cron restart
|
||||
[ -x /etc/init.d/cron ] && /etc/init.d/cron restart >/dev/null 2>&1
|
||||
return
|
||||
fi
|
||||
|
||||
@@ -1042,13 +1042,13 @@ start_crontab() {
|
||||
echolog "运行于非代理模式,仅允许服务启停的定时任务。"
|
||||
fi
|
||||
|
||||
/etc/init.d/cron restart
|
||||
[ -x /etc/init.d/cron ] && /etc/init.d/cron restart >/dev/null 2>&1
|
||||
}
|
||||
|
||||
stop_crontab() {
|
||||
[ "$1" = "cron" ] && return
|
||||
clean_crontab
|
||||
/etc/init.d/cron restart
|
||||
[ -x /etc/init.d/cron ] && /etc/init.d/cron restart >/dev/null 2>&1
|
||||
#echolog "清除定时执行命令。"
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user