diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua index 769e125d..fe6fd30e 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua @@ -564,9 +564,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(Value, "cipherSuites", translate("Cipher Suites"), '***' .. " " .. translate("Configures the list of supported cipher suites, separated by :")) @@ -585,9 +588,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.")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua index 52d5df67..c4a564a8 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua @@ -453,9 +453,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")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua index 59a843d4..65e69f99 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua @@ -253,12 +253,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("Certificate or 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 @@ -311,14 +318,21 @@ o:depends({ protocol = "hysteria" }) -- [[ TLS部分 ]] -- -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/" .. arg[1] .. ".crt" -if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) 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/" .. arg[1] .. ".crt" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) 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 @@ -333,11 +347,11 @@ end 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/" .. arg[1] .. ".key" if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) 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 @@ -349,6 +363,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 }) @@ -362,13 +402,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")) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua index 01781421..b126f021 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua @@ -193,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("Certificate or 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 @@ -263,11 +270,15 @@ end -- [[ TLS部分 ]] -- +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 = 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 }) -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 @@ -282,8 +293,8 @@ end 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 @@ -295,6 +306,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 }) diff --git a/luci-app-passwall/luasrc/passwall/util_sing-box.lua b/luci-app-passwall/luasrc/passwall/util_sing-box.lua index b795ed42..de86ddcb 100644 --- a/luci-app-passwall/luasrc/passwall/util_sing-box.lua +++ b/luci-app-passwall/luasrc/passwall/util_sing-box.lua @@ -248,7 +248,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 api.split(node.tls_certificate_pem, "\n") 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 @@ -273,7 +273,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 @@ -709,8 +709,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) @@ -724,6 +726,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, diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua index fb78f852..0c1c94e4 100644 --- a/luci-app-passwall/luasrc/passwall/util_xray.lua +++ b/luci-app-passwall/luasrc/passwall/util_xray.lua @@ -181,7 +181,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 or nil @@ -697,8 +697,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 diff --git a/luci-app-passwall/po/zh-cn/passwall.po b/luci-app-passwall/po/zh-cn/passwall.po index d06bedde..81e68cb8 100644 --- a/luci-app-passwall/po/zh-cn/passwall.po +++ b/luci-app-passwall/po/zh-cn/passwall.po @@ -1613,8 +1613,17 @@ msgstr "ECH 密钥路径" msgid "Can't find this file!" msgstr "找不到这个文件!" -msgid "Certificate or 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 "服务器端" @@ -1808,6 +1817,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 "ECH Config" msgstr "ECH 配置" diff --git a/luci-app-wizard/po/zh_Hans/wizard.po b/luci-app-wizard/po/zh_Hans/wizard.po index 470760bf..8117518e 100644 --- a/luci-app-wizard/po/zh_Hans/wizard.po +++ b/luci-app-wizard/po/zh_Hans/wizard.po @@ -23,7 +23,7 @@ msgid "Set the router's wireless name and password. For more advanced settings, msgstr "设置路由器的无线名字和密码,更多高级设置请进入 网络-无线 页面。" msgid "Leave empty to use ISP DNS" -msgstr "留空则使用阿里DNS" +msgstr "留空则使用运营商DNS" msgid "Enter the main router IP" msgstr "请输入主路由IP"