update 2026-09-20 02:20:59

This commit is contained in:
action committed 2026-09-20 02:20:59 +08:00
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"
+23 -1
View File
@@ -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({
+21 -6
View File
@@ -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 "دریافت دستی"
+21 -6
View File
@@ -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 "Получить вручную"
+22 -7
View File
@@ -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 "手动获取"
+22 -7
View File
@@ -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