mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-11-01 13:43:56 +08:00
update 2026-09-20 02:20:59
This commit is contained in:
1 parent
deb27aee9d
commit
33c69f15d2
1985 files changed
+460
-1523312
No files matched your search
@@ -598,9 +598,12 @@ o.default = ""
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ tls_certificate = true })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "tls_certificate_pem") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
o = s:option(DynamicList, "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."))
|
||||
@@ -632,9 +635,12 @@ o.default = ""
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ ech = true })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "ech_config") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
o = s:option(Value, "ech_query_server_name", translate("ECH Query Domain"), translate("Overrides the domain name used for ECH HTTPS record queries."))
|
||||
|
||||
@@ -451,9 +451,12 @@ o.default = ""
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ tls_certificate = true })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "tls_certificate_pem") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
o = s:option(Flag, "ech", translate("ECH"))
|
||||
|
||||
@@ -50,7 +50,7 @@ o.validate = function(self, value)
|
||||
if v then return v end
|
||||
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
|
||||
end
|
||||
o.cfgvalue = function(self, section, value)
|
||||
o.cfgvalue = function(self, section)
|
||||
local config_str = m:get(section, "config_str")
|
||||
if config_str then
|
||||
return api.base64Decode(config_str)
|
||||
@@ -77,7 +77,8 @@ o = s:option(Value, "port", translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ custom = false })
|
||||
|
||||
o = s:option(DynamicList, "users", translate("User"))
|
||||
o = s:option(MultiValue, "users", translate("User"))
|
||||
o.cast = "table"
|
||||
for i, v in ipairs(user_list) do
|
||||
o:value(v[".name"], v.username)
|
||||
end
|
||||
@@ -250,12 +251,19 @@ o.default = 0
|
||||
o.validate = function(self, value, t)
|
||||
if value then
|
||||
local reality = s.fields["reality"] and s.fields["reality"]:formvalue(t) or nil
|
||||
local use_pem = s.fields["tls_use_pem"] and s.fields["tls_use_pem"]:formvalue(t) or nil
|
||||
if reality and reality == "1" then return value end
|
||||
if value == "1" then
|
||||
if value == "1" and use_pem ~= "1" then
|
||||
local ca = s.fields["tls_certificateFile"] and s.fields["tls_certificateFile"]:formvalue(t) or ""
|
||||
local key = s.fields["tls_keyFile"] and s.fields["tls_keyFile"]:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Public key and Private key path can not be empty!")
|
||||
return nil, translate("Certificate and Private key path can not be empty!")
|
||||
end
|
||||
elseif value == "1" and use_pem == "1" then
|
||||
local ca = s.fields["tls_certificate"] and s.fields["tls_certificate"]:formvalue(t) or ""
|
||||
local key = s.fields["tls_key"] and s.fields["tls_key"]:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Certificate and Private key PEM can not be empty!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
@@ -308,14 +316,21 @@ o:depends({ protocol = "hysteria" })
|
||||
|
||||
-- [[ TLS ]] --
|
||||
|
||||
o = s:option(FileUpload, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. s.section .. ".pem"
|
||||
if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
|
||||
o = s:option(Flag, "tls_use_pem", translate("Use PEM"), translate("Use certificate and private key PEM content."))
|
||||
o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "naive" })
|
||||
o:depends({ protocol = "hysteria" })
|
||||
o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
|
||||
o = s:option(FileUpload, "tls_certificateFile", translate("Path to the certificate file"), translate("as:") .. "/etc/ssl/fullchain.crt")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. s.section .. ".crt"
|
||||
if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
|
||||
o:depends({ tls = true, reality = false, tls_use_pem = false })
|
||||
o:depends({ protocol = "naive", tls_use_pem = false })
|
||||
o:depends({ protocol = "hysteria", tls_use_pem = false })
|
||||
o:depends({ protocol = "tuic", tls_use_pem = false })
|
||||
o:depends({ protocol = "hysteria2", tls_use_pem = false })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not api.fs.access(value) then
|
||||
@@ -327,14 +342,14 @@ o.validate = function(self, value, t)
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, "tls_keyFile", translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o = s:option(FileUpload, "tls_keyFile", translate("Path to the private key file"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. s.section .. ".key"
|
||||
if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
|
||||
o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "naive" })
|
||||
o:depends({ protocol = "hysteria" })
|
||||
o:depends({ protocol = "tuic" })
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
o:depends({ tls = true, reality = false, tls_use_pem = false })
|
||||
o:depends({ protocol = "naive", tls_use_pem = false })
|
||||
o:depends({ protocol = "hysteria", tls_use_pem = false })
|
||||
o:depends({ protocol = "tuic", tls_use_pem = false })
|
||||
o:depends({ protocol = "hysteria2", tls_use_pem = false })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not api.fs.access(value) then
|
||||
@@ -346,6 +361,32 @@ o.validate = function(self, value, t)
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(TextValue, "tls_certificate", "TLS Certificate (PEM)", translate("Full certificate (chain), PEM format."))
|
||||
o.default = ""
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ tls_use_pem = true })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "tls_certificate") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
o = s:option(TextValue, "tls_key", "TLS Private Key (PEM)", translate("Private key in PEM format."))
|
||||
o.default = ""
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ tls_use_pem = true })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "tls_key") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
o = s:option(Flag, "ech", translate("ECH"))
|
||||
o.default = "0"
|
||||
o:depends({ tls = true, flow = "", reality = false })
|
||||
@@ -359,13 +400,12 @@ o.default = ""
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ ech = true })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "ech_key") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = value:gsub("^%s+", ""):gsub("%s+$","\n"):gsub("\r\n","\n"):gsub("[ \t]*\n[ \t]*", "\n")
|
||||
value = value:gsub("^%s*\n", "")
|
||||
if value:sub(-1) == "\n" then
|
||||
value = value:sub(1, -2)
|
||||
end
|
||||
return value
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
o = s:option(ListValue, "transport", translate("Transport"))
|
||||
@@ -489,7 +529,7 @@ o.default = "0"
|
||||
o:depends({ custom = false })
|
||||
|
||||
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
|
||||
o.rmempty = false
|
||||
o.rmempty = not m.is_js_luci
|
||||
o.nocreate = true
|
||||
o.allowany = true
|
||||
o.default = "wan"
|
||||
|
||||
@@ -46,7 +46,7 @@ o.validate = function(self, value)
|
||||
if v then return v end
|
||||
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
|
||||
end
|
||||
o.cfgvalue = function(self, section, value)
|
||||
o.cfgvalue = function(self, section)
|
||||
local config_str = m:get(section, "config_str")
|
||||
if config_str then
|
||||
return api.base64Decode(config_str)
|
||||
@@ -72,7 +72,8 @@ o = s:option(Value, "port", translate("Listen Port"))
|
||||
o.datatype = "port"
|
||||
o:depends({ custom = false })
|
||||
|
||||
o = s:option(DynamicList, "users", translate("User"))
|
||||
o = s:option(MultiValue, "users", translate("User"))
|
||||
o.cast = "table"
|
||||
for i, v in ipairs(user_list) do
|
||||
o:value(v[".name"], v.username)
|
||||
end
|
||||
@@ -192,12 +193,19 @@ o.default = 0
|
||||
o.validate = function(self, value, t)
|
||||
if value then
|
||||
local reality = s.fields["reality"] and s.fields["reality"]:formvalue(t) or nil
|
||||
local use_pem = s.fields["tls_use_pem"] and s.fields["tls_use_pem"]:formvalue(t) or nil
|
||||
if reality and reality == "1" then return value end
|
||||
if value == "1" then
|
||||
if value == "1" and use_pem ~= "1" then
|
||||
local ca = s.fields["tls_certificateFile"] and s.fields["tls_certificateFile"]:formvalue(t) or ""
|
||||
local key = s.fields["tls_keyFile"] and s.fields["tls_keyFile"]:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Public key and Private key path can not be empty!")
|
||||
return nil, translate("Certificate and Private key path can not be empty!")
|
||||
end
|
||||
elseif value == "1" and use_pem == "1" then
|
||||
local ca = s.fields["tls_certificate"] and s.fields["tls_certificate"]:formvalue(t) or ""
|
||||
local key = s.fields["tls_key"] and s.fields["tls_key"]:formvalue(t) or ""
|
||||
if ca == "" or key == "" then
|
||||
return nil, translate("Certificate and Private key PEM can not be empty!")
|
||||
end
|
||||
end
|
||||
return value
|
||||
@@ -262,11 +270,16 @@ end
|
||||
--o:depends({ tls = true })
|
||||
|
||||
-- [[ TLS ]] --
|
||||
o = s:option(FileUpload, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. s.section .. ".pem"
|
||||
if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
|
||||
|
||||
o = s:option(Flag, "tls_use_pem", translate("Use PEM"), translate("Use certificate and private key PEM content."))
|
||||
o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "hysteria2"})
|
||||
o:depends({ protocol = "hysteria2" })
|
||||
|
||||
o = s:option(FileUpload, "tls_certificateFile", translate("Path to the certificate file"), translate("as:") .. "/etc/ssl/fullchain.crt")
|
||||
o.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. s.section .. ".crt"
|
||||
if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
|
||||
o:depends({ tls = true, reality = false, tls_use_pem = false })
|
||||
o:depends({ protocol = "hysteria2", tls_use_pem = false })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not api.fs.access(value) then
|
||||
@@ -278,11 +291,11 @@ o.validate = function(self, value, t)
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(FileUpload, "tls_keyFile", translate("Private key absolute path"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o = s:option(FileUpload, "tls_keyFile", translate("Path to the private key file"), translate("as:") .. "/etc/ssl/private.key")
|
||||
o.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. s.section .. ".key"
|
||||
if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
|
||||
o:depends({ tls = true, reality = false })
|
||||
o:depends({ protocol = "hysteria2"})
|
||||
o:depends({ tls = true, reality = false, tls_use_pem = false })
|
||||
o:depends({ protocol = "hysteria2", tls_use_pem = false })
|
||||
o.validate = function(self, value, t)
|
||||
if value and value ~= "" then
|
||||
if not api.fs.access(value) then
|
||||
@@ -294,6 +307,32 @@ o.validate = function(self, value, t)
|
||||
return nil
|
||||
end
|
||||
|
||||
o = s:option(TextValue, "tls_certificate", "TLS Certificate (PEM)", translate("Full certificate (chain), PEM format."))
|
||||
o.default = ""
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ tls_use_pem = true })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "tls_certificate") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
o = s:option(TextValue, "tls_key", "TLS Private Key (PEM)", translate("Private key in PEM format."))
|
||||
o.default = ""
|
||||
o.rows = 5
|
||||
o.wrap = "off"
|
||||
o:depends({ tls_use_pem = true })
|
||||
o.cfgvalue = function(self, section)
|
||||
return (m:get(section, "tls_key") or ""):gsub("\\n", "\n")
|
||||
end
|
||||
o.validate = function(self, value)
|
||||
value = api.trim(value):gsub("\r\n", "\n"):gsub("\r", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n")
|
||||
return value:gsub("\n", "\\n")
|
||||
end
|
||||
|
||||
o = s:option(Flag, "ech", translate("ECH"))
|
||||
o.default = "0"
|
||||
o:depends({ tls = true, reality = false })
|
||||
@@ -407,7 +446,7 @@ o:depends({ use_finalmask = true })
|
||||
o.rows = 10
|
||||
o.wrap = "off"
|
||||
o.datatype = "json"
|
||||
o.cfgvalue = function(self, section, value)
|
||||
o.cfgvalue = function(self, section)
|
||||
local raw = m:get(section, "finalmask")
|
||||
if raw then
|
||||
return api.base64Decode(raw)
|
||||
@@ -488,7 +527,7 @@ o.default = "0"
|
||||
o:depends({ custom = false })
|
||||
|
||||
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
|
||||
o.rmempty = false
|
||||
o.rmempty = not m.is_js_luci
|
||||
o.nocreate = true
|
||||
o.allowany = true
|
||||
o.default = "wan"
|
||||
|
||||
@@ -41,7 +41,7 @@ o.validate = function(self, value)
|
||||
if v then return v end
|
||||
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
|
||||
end
|
||||
o.cfgvalue = function(self, section, value)
|
||||
o.cfgvalue = function(self, section)
|
||||
local config_str = m:get(section, "config_str")
|
||||
if config_str then
|
||||
return api.base64Decode(config_str)
|
||||
@@ -79,7 +79,7 @@ o.default = "0"
|
||||
o:depends({ custom = false })
|
||||
|
||||
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
|
||||
o.rmempty = false
|
||||
o.rmempty = not m.is_js_luci
|
||||
o.nocreate = true
|
||||
o.allowany = true
|
||||
o.default = "wan"
|
||||
|
||||
@@ -54,7 +54,7 @@ o.validate = function(self, value)
|
||||
if v then return v end
|
||||
return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!")
|
||||
end
|
||||
o.cfgvalue = function(self, section, value)
|
||||
o.cfgvalue = function(self, section)
|
||||
local config_str = m:get(section, "config_str")
|
||||
if config_str then
|
||||
return api.base64Decode(config_str)
|
||||
@@ -110,7 +110,7 @@ o.default = "0"
|
||||
o:depends({ custom = false })
|
||||
|
||||
o = s:option(Value, "firewall_allow_src", translate("Source zone"))
|
||||
o.rmempty = false
|
||||
o.rmempty = not m.is_js_luci
|
||||
o.nocreate = true
|
||||
o.allowany = true
|
||||
o.default = "wan"
|
||||
|
||||
@@ -1565,7 +1565,13 @@ function set_type_cbi(s)
|
||||
obj.option_prefix = s_self.option_prefix
|
||||
obj.option = s_self.option_prefix .. option
|
||||
obj.cfgvalue = function(self, section)
|
||||
return self.map:get(section, self.config_option)
|
||||
local v = self.map:get(section, self.config_option)
|
||||
if util.instanceof(self, cbi.MultiValue) then
|
||||
if v and self.cast == "table" then
|
||||
return table.concat(v, " ")
|
||||
end
|
||||
end
|
||||
return v
|
||||
end
|
||||
obj.write = function(self, section, value)
|
||||
if s1.fields["type"]:formvalue(s_self.section) == s_self.type_name then
|
||||
@@ -1583,6 +1589,21 @@ function set_type_cbi(s)
|
||||
new_val = new_t
|
||||
end
|
||||
end
|
||||
if util.instanceof(self, cbi.MultiValue) then
|
||||
local new_t = {}
|
||||
if type(value) == "table" then
|
||||
new_t = table_remove_duplicates(value)
|
||||
else
|
||||
string.gsub(value, '[^' .. " " .. ']+', function(v)
|
||||
new_t[#new_t + 1] = v
|
||||
end)
|
||||
end
|
||||
if self.cast == "string" then
|
||||
new_val = table.concat(new_t, " ")
|
||||
else
|
||||
new_val = new_t
|
||||
end
|
||||
end
|
||||
self.map:set(section, self.config_option, new_val)
|
||||
end
|
||||
end
|
||||
@@ -1630,6 +1651,7 @@ end
|
||||
function type_cbi_section(s, s2)
|
||||
for i, v in ipairs(s2.children) do
|
||||
local o = s2.children[i]
|
||||
o.section = s
|
||||
s:append(o)
|
||||
s.fields[o.option] = o
|
||||
end
|
||||
|
||||
@@ -253,8 +253,8 @@ 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,
|
||||
cipher_suites = (node.cipherSuites and #node.cipherSuites > 0) and node.cipherSuites or nil,
|
||||
certificate = (node.tls_certificate == "1" and node.tls_certificate_pem ~= "") and api.split(node.tls_certificate_pem:gsub("\\n", "\n"), "\n") or nil,
|
||||
cipher_suites = (node.cipherSuites and node.cipherSuites ~= "") and api.split(node.cipherSuites, ":") or nil,
|
||||
ech = (node.ech == "1") and (function()
|
||||
local function get_ech_domain(s) --兼容xray "域名+DNS" 格式ech
|
||||
local domain, dns = s:match("^([^+]+)%+(.+)$")
|
||||
@@ -278,7 +278,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
ech.query_server_name = qname
|
||||
ech_domain[qname] = true
|
||||
elseif config then
|
||||
ech.config = { config }
|
||||
ech.config = api.split(config:gsub("\\n", "\n"), "\n")
|
||||
elseif node.tls_serverName and node.tls_serverName ~= "" then
|
||||
ech_domain[node.tls_serverName] = true
|
||||
end
|
||||
@@ -714,8 +714,10 @@ function gen_config_server(node)
|
||||
|
||||
local tls = {
|
||||
enabled = true,
|
||||
certificate_path = node.tls_certificateFile,
|
||||
key_path = node.tls_keyFile,
|
||||
certificate_path = (node.tls_use_pem ~= "1") and node.tls_certificateFile or nil,
|
||||
key_path = (node.tls_use_pem ~= "1") and node.tls_keyFile or nil,
|
||||
certificate = (node.tls_use_pem == "1" and node.tls_certificate) and api.split(node.tls_certificate:gsub("\\n", "\n"), "\n") or nil,
|
||||
key = (node.tls_use_pem == "1" and node.tls_key) and api.split(node.tls_key:gsub("\\n", "\n"), "\n") or nil,
|
||||
alpn = (node.alpn and node.alpn ~= "default") and (function()
|
||||
local alpn = {}
|
||||
string.gsub(node.alpn, '[^,]+', function(w)
|
||||
@@ -729,6 +731,8 @@ function gen_config_server(node)
|
||||
if node.tls == "1" and node.reality == "1" then
|
||||
tls.certificate_path = nil
|
||||
tls.key_path = nil
|
||||
tls.certificate = nil
|
||||
tls.key = nil
|
||||
tls.server_name = node.reality_handshake_server
|
||||
tls.reality = {
|
||||
enabled = true,
|
||||
@@ -746,7 +750,7 @@ function gen_config_server(node)
|
||||
if node.tls == "1" and node.ech == "1" then
|
||||
tls.ech = {
|
||||
enabled = true,
|
||||
key = node.ech_key and { node.ech_key } or nil
|
||||
key = node.ech_key and api.split(node.ech_key:gsub("\\n", "\n"), "\n") or nil
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
verifyPeerCertByName = node.tls_CertByName or "",
|
||||
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"),
|
||||
certificate = api.split(node.tls_certificate_pem:gsub("\\n", "\n"), "\n"),
|
||||
usage = "verify"
|
||||
} or nil,
|
||||
cipherSuites = (node.cipherSuites and #node.cipherSuites > 0) and table.concat(node.cipherSuites, ":") or nil,
|
||||
@@ -226,8 +226,8 @@ function gen_outbound(flag, node, tag, proxy_table)
|
||||
tti = 50,
|
||||
uplinkCapacity = 12,
|
||||
downlinkCapacity = 100,
|
||||
CwndMultiplier = 1,
|
||||
MaxSendingWindow = 2 * 1024 * 1024
|
||||
cwndMultiplier = 1,
|
||||
maxSendingWindow = 2 * 1024 * 1024
|
||||
} or nil,
|
||||
wsSettings = (node.transport == "ws") and {
|
||||
path = node.ws_path or "/",
|
||||
@@ -702,8 +702,10 @@ function gen_config_server(node)
|
||||
disableSystemRoot = false,
|
||||
certificates = {
|
||||
{
|
||||
certificateFile = node.tls_certificateFile,
|
||||
keyFile = node.tls_keyFile
|
||||
certificateFile = (node.tls_use_pem ~= "1") and node.tls_certificateFile or nil,
|
||||
keyFile = (node.tls_use_pem ~= "1") and node.tls_keyFile or nil,
|
||||
certificate = (node.tls_use_pem == "1" and node.tls_certificate) and api.split(node.tls_certificate:gsub("\\n", "\n"), "\n") or nil,
|
||||
key = (node.tls_use_pem == "1" and node.tls_key) and api.split(node.tls_key:gsub("\\n", "\n"), "\n") or nil
|
||||
}
|
||||
},
|
||||
echServerKeys = (node.ech == "1") and node.ech_key or nil
|
||||
@@ -730,8 +732,8 @@ function gen_config_server(node)
|
||||
tti = 50,
|
||||
uplinkCapacity = 12,
|
||||
downlinkCapacity = 100,
|
||||
CwndMultiplier = 1,
|
||||
MaxSendingWindow = 2 * 1024 * 1024
|
||||
cwndMultiplier = 1,
|
||||
maxSendingWindow = 2 * 1024 * 1024
|
||||
} or nil,
|
||||
wsSettings = (node.transport == "ws") and {
|
||||
host = node.ws_host or nil,
|
||||
|
||||
@@ -688,12 +688,40 @@ local current_node = map:get(section)
|
||||
params += opt.query("congestion_control", dom_prefix + "naive_congestion_control");
|
||||
}
|
||||
|
||||
params += "#" + encodeURI(v_alias.value);
|
||||
if (params[0] == "&") {
|
||||
params = params.substring(1);
|
||||
}
|
||||
url += params;
|
||||
} else if (v_type === "sing-box" && opt.get(dom_prefix + "protocol").value === "snell") {
|
||||
protocol = "snell";
|
||||
var v_userkey = opt.get(dom_prefix + "password");
|
||||
var v_psk = opt.get(dom_prefix + "snell_psk");
|
||||
var v_port = opt.get(dom_prefix + "port");
|
||||
url = encodeURIComponent(v_psk.value) +
|
||||
"@" + _address +
|
||||
":" + v_port.value + "?";
|
||||
|
||||
var params = "psk=" + encodeURIComponent(v_psk.value);
|
||||
if (v_userkey.value !== "") {
|
||||
params += "&userkey=" + encodeURIComponent(v_userkey.value);
|
||||
}
|
||||
params += opt.query("version", dom_prefix + "snell_version");
|
||||
if (opt.get(dom_prefix + "snell_version").value === '4') {
|
||||
params += opt.query("obfs", dom_prefix + "snell_obfs_mode");
|
||||
params += opt.query("obfs-host", dom_prefix + "snell_obfs_host");
|
||||
} else {
|
||||
params += opt.query("mode", dom_prefix + "snell_mode");
|
||||
}
|
||||
params += opt.query("reuse", dom_prefix + "snell_reuse");
|
||||
|
||||
params += "#" + encodeURI(v_alias.value);
|
||||
if (params[0] == "&") {
|
||||
params = params.substring(1);
|
||||
}
|
||||
url += params;
|
||||
}
|
||||
|
||||
if (url) {
|
||||
url = protocol.toLowerCase() + "://" + url;
|
||||
return url;
|
||||
@@ -1760,6 +1788,37 @@ local current_node = map:get(section)
|
||||
opt.set('remarks', decodeURIComponent(hash.substr(1)));
|
||||
}
|
||||
}
|
||||
if (link_type === "snell") {
|
||||
if (has_singbox) {
|
||||
dom_prefix = "singbox_";
|
||||
opt.set('type', "sing-box");
|
||||
}
|
||||
opt.set(dom_prefix + 'protocol', "snell");
|
||||
var m = parseNodeUrl(link);
|
||||
opt.set(dom_prefix + 'address', unbracketIP(m.hostname));
|
||||
opt.set(dom_prefix + 'port', m.port || "443");
|
||||
var queryParam = {};
|
||||
if (m.search.length > 1) {
|
||||
var query = m.search.replace('/?', '?').split('?')
|
||||
var queryParams = query[1];
|
||||
var queryArray = queryParams.split('&');
|
||||
var params;
|
||||
for (i = 0; i < queryArray.length; i++) {
|
||||
params = queryArray[i].split('=');
|
||||
queryParam[decodeURIComponent(params[0]).toLowerCase()] = decodeURIComponent(params[1] || '');
|
||||
}
|
||||
}
|
||||
opt.set(dom_prefix + 'password', queryParam.userkey || '');
|
||||
opt.set(dom_prefix + 'snell_psk', queryParam.psk || m.passwd || '');
|
||||
opt.set(dom_prefix + 'snell_version', queryParam.version || '4');
|
||||
opt.set(dom_prefix + 'snell_reuse', queryParam.reuse === '1');
|
||||
opt.set(dom_prefix + 'snell_obfs_mode', queryParam.obfs || 'none');
|
||||
opt.set(dom_prefix + 'snell_obfs_host', queryParam['obfs-host'] || queryParam.obfs_host || '');
|
||||
opt.set(dom_prefix + 'snell_mode', queryParam.mode || 'default');
|
||||
if (m.hash) {
|
||||
opt.set('remarks', decodeURIComponent(m.hash.substr(1)));
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_type) {
|
||||
sessionStorage.setItem("fromUrl", JSON.stringify({
|
||||
|
||||
@@ -1453,17 +1453,26 @@ msgstr "پورت راه دور"
|
||||
msgid "as:"
|
||||
msgstr "به عنوان:"
|
||||
|
||||
msgid "Public key absolute path"
|
||||
msgstr "مسیر مطلق کلید عمومی"
|
||||
msgid "Path to the certificate file"
|
||||
msgstr "مسیر فایل گواهینامه"
|
||||
|
||||
msgid "Private key absolute path"
|
||||
msgstr "مسیر مطلق کلید خصوصی"
|
||||
msgid "Path to the private key file"
|
||||
msgstr "مسیر فایل کلید خصوصی"
|
||||
|
||||
msgid "Can't find this file!"
|
||||
msgstr "این فایل پیدا نشد!"
|
||||
|
||||
msgid "Public key and Private key path can not be empty!"
|
||||
msgstr "مسیر کلید عمومی و کلید خصوصی نمیتواند خالی باشد!"
|
||||
msgid "Certificate and Private key path can not be empty!"
|
||||
msgstr "مسیر گواهی و کلید خصوصی نمیتواند خالی باشد!"
|
||||
|
||||
msgid "Certificate and Private key PEM can not be empty!"
|
||||
msgstr "گواهی و کلید خصوصی PEM نمیتوانند خالی باشند!"
|
||||
|
||||
msgid "Use PEM"
|
||||
msgstr "از PEM استفاده کنید"
|
||||
|
||||
msgid "Use certificate and private key PEM content."
|
||||
msgstr "از محتوای PEM گواهی و کلید خصوصی استفاده کنید."
|
||||
|
||||
msgid "Server-Side"
|
||||
msgstr "سمت سرور"
|
||||
@@ -1648,6 +1657,12 @@ msgstr "گواهی TLS (PEM)"
|
||||
msgid "Full certificate (chain), PEM format."
|
||||
msgstr "گواهی کامل (زنجیرهای)، فرمت PEM."
|
||||
|
||||
msgid "TLS Private Key (PEM)"
|
||||
msgstr "کلید خصوصی TLS (PEM)"
|
||||
|
||||
msgid "Private key in PEM format."
|
||||
msgstr "کلید خصوصی با فرمت PEM."
|
||||
|
||||
msgid "Fetch Manually"
|
||||
msgstr "دریافت دستی"
|
||||
|
||||
|
||||
@@ -1454,17 +1454,26 @@ msgstr "Удалённый порт"
|
||||
msgid "as:"
|
||||
msgstr "например:"
|
||||
|
||||
msgid "Public key absolute path"
|
||||
msgstr "Полный путь к публичному ключу"
|
||||
msgid "Path to the certificate file"
|
||||
msgstr "Путь к файлу сертификата"
|
||||
|
||||
msgid "Private key absolute path"
|
||||
msgstr "Полный путь к приватному ключу"
|
||||
msgid "Path to the private key file"
|
||||
msgstr "Путь к файлу закрытого ключа"
|
||||
|
||||
msgid "Can't find this file!"
|
||||
msgstr "Файл не найден!"
|
||||
|
||||
msgid "Public key and Private key path can not be empty!"
|
||||
msgstr "Пути к публичному и приватному ключам не могут быть пустыми!"
|
||||
msgid "Certificate and Private key path can not be empty!"
|
||||
msgstr "Пути к сертификату и закрытому ключу не могут быть пустыми!"
|
||||
|
||||
msgid "Certificate and Private key PEM can not be empty!"
|
||||
msgstr "Сертификат и закрытый ключ в формате PEM не могут быть пустыми!"
|
||||
|
||||
msgid "Use PEM"
|
||||
msgstr "Используйте PEM"
|
||||
|
||||
msgid "Use certificate and private key PEM content."
|
||||
msgstr "Используйте содержимое сертификата и закрытого ключа в формате PEM."
|
||||
|
||||
msgid "Server-Side"
|
||||
msgstr "Серверная часть"
|
||||
@@ -1649,6 +1658,12 @@ msgstr "Сертификат TLS (PEM)"
|
||||
msgid "Full certificate (chain), PEM format."
|
||||
msgstr "Полный сертификат (цепочка), формат PEM."
|
||||
|
||||
msgid "TLS Private Key (PEM)"
|
||||
msgstr "Закрытый ключ TLS (PEM)"
|
||||
|
||||
msgid "Private key in PEM format."
|
||||
msgstr "Закрытый ключ в формате PEM."
|
||||
|
||||
msgid "Fetch Manually"
|
||||
msgstr "Получить вручную"
|
||||
|
||||
|
||||
@@ -1296,7 +1296,7 @@ msgid "Private Key"
|
||||
msgstr "私钥"
|
||||
|
||||
msgid "Pre shared key"
|
||||
msgstr "额外的对称加密密钥"
|
||||
msgstr "预共享密钥"
|
||||
|
||||
msgid "Allowed IPs"
|
||||
msgstr "允许的 IP"
|
||||
@@ -1445,17 +1445,26 @@ msgstr "远程端口"
|
||||
msgid "as:"
|
||||
msgstr "如:"
|
||||
|
||||
msgid "Public key absolute path"
|
||||
msgstr "公钥文件绝对路径"
|
||||
msgid "Path to the certificate file"
|
||||
msgstr "证书文件路径"
|
||||
|
||||
msgid "Private key absolute path"
|
||||
msgstr "私钥文件绝对路径"
|
||||
msgid "Path to the private key file"
|
||||
msgstr "私钥文件路径"
|
||||
|
||||
msgid "Can't find this file!"
|
||||
msgstr "找不到这个文件!"
|
||||
|
||||
msgid "Public key and Private key path can not be empty!"
|
||||
msgstr "公钥和私钥文件路径不能为空!"
|
||||
msgid "Certificate and Private key path can not be empty!"
|
||||
msgstr "证书和私钥文件路径不能为空!"
|
||||
|
||||
msgid "Certificate and Private key PEM can not be empty!"
|
||||
msgstr "证书和私钥 PEM 不能为空!"
|
||||
|
||||
msgid "Use PEM"
|
||||
msgstr "使用 PEM"
|
||||
|
||||
msgid "Use certificate and private key PEM content."
|
||||
msgstr "使用证书和私钥的 PEM 内容。"
|
||||
|
||||
msgid "Server-Side"
|
||||
msgstr "服务器端"
|
||||
@@ -1640,6 +1649,12 @@ msgstr "TLS 证书(PEM)"
|
||||
msgid "Full certificate (chain), PEM format."
|
||||
msgstr "完整证书(链),PEM 格式。"
|
||||
|
||||
msgid "TLS Private Key (PEM)"
|
||||
msgstr "TLS 私钥(PEM)"
|
||||
|
||||
msgid "Private key in PEM format."
|
||||
msgstr "PEM 格式的私钥。"
|
||||
|
||||
msgid "Fetch Manually"
|
||||
msgstr "手动获取"
|
||||
|
||||
|
||||
@@ -1296,7 +1296,7 @@ msgid "Private Key"
|
||||
msgstr "私鑰"
|
||||
|
||||
msgid "Pre shared key"
|
||||
msgstr "额外的對称加密密鑰"
|
||||
msgstr "預共享密鑰"
|
||||
|
||||
msgid "Allowed IPs"
|
||||
msgstr "允許的 IP"
|
||||
@@ -1445,17 +1445,26 @@ msgstr "遠程端口"
|
||||
msgid "as:"
|
||||
msgstr "如:"
|
||||
|
||||
msgid "Public key absolute path"
|
||||
msgstr "公鑰文件绝對路径"
|
||||
msgid "Path to the certificate file"
|
||||
msgstr "證書檔案路徑"
|
||||
|
||||
msgid "Private key absolute path"
|
||||
msgstr "私鑰文件绝對路径"
|
||||
msgid "Path to the private key file"
|
||||
msgstr "私鑰檔案路徑"
|
||||
|
||||
msgid "Can't find this file!"
|
||||
msgstr "找不到這個文件!"
|
||||
|
||||
msgid "Public key and Private key path can not be empty!"
|
||||
msgstr "公鑰和私鑰文件路径不能為空!"
|
||||
msgid "Certificate and Private key path can not be empty!"
|
||||
msgstr "憑證和私鑰路徑不能為空!"
|
||||
|
||||
msgid "Certificate and Private key PEM can not be empty!"
|
||||
msgstr "憑證和私鑰 PEM 檔案不能為空!"
|
||||
|
||||
msgid "Use PEM"
|
||||
msgstr "使用 PEM"
|
||||
|
||||
msgid "Use certificate and private key PEM content."
|
||||
msgstr "使用憑證和私鑰 PEM 內容。"
|
||||
|
||||
msgid "Server-Side"
|
||||
msgstr "服務器端"
|
||||
@@ -1640,6 +1649,12 @@ msgstr "TLS 憑證(PEM)"
|
||||
msgid "Full certificate (chain), PEM format."
|
||||
msgstr "完整憑證(鏈),PEM 格式。"
|
||||
|
||||
msgid "TLS Private Key (PEM)"
|
||||
msgstr "TLS 私鑰 (PEM)"
|
||||
|
||||
msgid "Private key in PEM format."
|
||||
msgstr "PEM格式的私鑰。"
|
||||
|
||||
msgid "Fetch Manually"
|
||||
msgstr "手動獲取"
|
||||
|
||||
|
||||
@@ -760,7 +760,7 @@ local function parseClashNode(node, add_mode, group, sub_cfg)
|
||||
result.type = 'sing-box'
|
||||
result.protocol = "anytls"
|
||||
else
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "AnyTLS", "AnyTLS", "Sing-Box 1.12"))
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "AnyTLS", "Sing-Box 1.12"))
|
||||
return nil
|
||||
end
|
||||
result.password = node.password
|
||||
@@ -783,6 +783,25 @@ local function parseClashNode(node, add_mode, group, sub_cfg)
|
||||
if node["disable-reuse"] then
|
||||
result.anytls_disable_reuse = "1"
|
||||
end
|
||||
elseif node.type == 'snell' then
|
||||
if has_singbox then
|
||||
result.type = 'sing-box'
|
||||
result.protocol = "snell"
|
||||
else
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "Snell", "Sing-Box 1.14"))
|
||||
return nil
|
||||
end
|
||||
result.password = node.password
|
||||
result.snell_psk = node.psk
|
||||
result.snell_version = node.version or "4"
|
||||
if result.snell_version == "4" then
|
||||
local obfs_opts = node["obfs-opts"] or {}
|
||||
result.snell_obfs_mode = obfs_opts.mode or "none"
|
||||
result.snell_obfs_host = obfs_opts.host
|
||||
else
|
||||
result.snell_mode = "default"
|
||||
end
|
||||
result.snell_reuse = node.reuse and "1" or "0"
|
||||
end
|
||||
if not result.remarks or result.remarks == "" then
|
||||
if result.address and result.port then
|
||||
@@ -1665,7 +1684,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.type = 'sing-box'
|
||||
result.protocol = "hysteria"
|
||||
else
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "Hysteria", "Hysteria", "Sing-Box"))
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "Hysteria", "Sing-Box"))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1778,7 +1797,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.type = 'sing-box'
|
||||
result.protocol = "tuic"
|
||||
else
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "Tuic", "Tuic", "Sing-Box"))
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "Tuic", "Sing-Box"))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1836,7 +1855,7 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.type = 'sing-box'
|
||||
result.protocol = "anytls"
|
||||
else
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "AnyTLS", "AnyTLS", "Sing-Box 1.12"))
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "AnyTLS", "Sing-Box 1.12"))
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -1962,6 +1981,62 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.naive_quic = "1"
|
||||
result.naive_congestion_control = params.congestion_control or "bbr"
|
||||
end
|
||||
elseif szType == "snell" then
|
||||
if has_singbox then
|
||||
result.type = 'sing-box'
|
||||
result.protocol = "snell"
|
||||
else
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "Snell", "Sing-Box 1.14"))
|
||||
return nil
|
||||
end
|
||||
|
||||
local alias = ""
|
||||
if content:find("#") then
|
||||
local idx_sp = content:find("#")
|
||||
alias = content:sub(idx_sp + 1, -1)
|
||||
content = content:sub(0, idx_sp - 1)
|
||||
end
|
||||
result.remarks = UrlDecode(alias)
|
||||
local Info = content
|
||||
if content:find("@") then
|
||||
local info = split(content, "@")
|
||||
result.snell_psk = UrlDecode(info[1])
|
||||
Info = info[2]
|
||||
end
|
||||
Info = (Info or ""):gsub("/%?", "?")
|
||||
local query = split(Info, "%?")
|
||||
local host_port = query[1]
|
||||
local params = {}
|
||||
for _, v in pairs(split(query[2], '&')) do
|
||||
local s = v:find("=", 1, true)
|
||||
if s and s > 1 then
|
||||
params[UrlDecode(v:sub(1, s - 1)):lower()] = UrlDecode(v:sub(s + 1))
|
||||
end
|
||||
end
|
||||
-- [2001:4860:4860::8888]:443
|
||||
-- 8.8.8.8:443
|
||||
result.port = "443"
|
||||
if host_port:find(":") then
|
||||
local sp = split(host_port, ":")
|
||||
result.port = sp[#sp]
|
||||
if api.is_ipv6addrport(host_port) then
|
||||
result.address = api.get_ipv6_only(host_port)
|
||||
else
|
||||
result.address = sp[1]
|
||||
end
|
||||
else
|
||||
result.address = host_port
|
||||
end
|
||||
result.snell_psk = params.psk or result.snell_psk
|
||||
result.password = params.userkey
|
||||
result.snell_version = params.version or "4"
|
||||
if result.snell_version == "4" then
|
||||
result.snell_obfs_mode = params.obfs or "none"
|
||||
result.snell_obfs_host = params['obfs-host'] or params.obfs_host
|
||||
else
|
||||
result.snell_mode = params.mode or "default"
|
||||
end
|
||||
result.snell_reuse = (params.reuse == "1") and "1" or "0"
|
||||
else
|
||||
log(2, i18n.translatef("%s type node subscriptions are not currently supported, skip this node.", szType))
|
||||
return nil
|
||||
|
||||
Reference in new issue
Block a user