diff --git a/luci-app-bandix/htdocs/luci-static/resources/view/bandix/index.js b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/index.js index e8a6f7a5..52f4d209 100644 --- a/luci-app-bandix/htdocs/luci-static/resources/view/bandix/index.js +++ b/luci-app-bandix/htdocs/luci-static/resources/view/bandix/index.js @@ -9,11 +9,6 @@ var BANDIX_COLOR_UPLOAD = '#f97316'; // 橙色 - 上传/上行 var BANDIX_COLOR_DOWNLOAD = '#06b6d4'; // 青色 - 下载/下行 -// 远程广告配置 -var BANDIX_AD_CONFIG_URL = 'https://raw.githubusercontent.com/timsaya/bandix-ads/main/ads.json'; -var BANDIX_AD_DEFAULT_REFRESH_INTERVAL = 3600; -var BANDIX_AD_RETRY_INTERVAL = 900; - // 悬浮框背景色定义 var BANDIX_TOOLTIP_BG_OPENWRT2020_LIGHT = '#ffffff'; // OpenWrt 2020 浅色主题悬浮框背景 var BANDIX_TOOLTIP_BG_OPENWRT2020_DARK = '#2a2a2a'; // OpenWrt 2020 深色主题悬浮框背景 @@ -562,143 +557,11 @@ return view.extend({ transform: translateY(-1px); } - .bandix-ad-row { - display: grid; - grid-template-columns: repeat(var(--bandix-ad-count, 6), minmax(112px, 1fr)); - gap: 8px; - margin: 12px 0; - overflow-x: auto; - scrollbar-width: thin; - } - - .bandix-ad-slot { - flex: 1 1 0; - min-width: 112px; - padding: 0; - aspect-ratio: 3 / 1; - border: 1px solid rgba(107, 114, 128, 0.35); - border-radius: 6px; - background: linear-gradient(135deg, rgba(225, 37, 27, 0.08), rgba(107, 114, 128, 0.04)); - display: flex; - align-items: center; - color: inherit; - box-sizing: border-box; - overflow: hidden; - position: relative; - text-decoration: none; - transition: border-color 0.2s ease, transform 0.2s ease; - } - - .bandix-ad-slot:not(.bandix-ad-disabled):hover, - .bandix-ad-slot:not(.bandix-ad-disabled):focus-visible { - border-color: rgba(225, 37, 27, 0.75); - box-shadow: 0 4px 12px rgba(225, 37, 27, 0.12); - transform: translateY(-2px); - } - - .bandix-ad-disabled { - cursor: default; - } - - .bandix-ad-label { - align-self: flex-start; - padding: 1px 5px; - border: none; - border-radius: 3px; - background: rgba(225, 37, 27, 0.88); - color: #ffffff; - font-size: 0.5625rem; - font-weight: 700; - letter-spacing: 0.08em; - line-height: 1.4; - } - - .bandix-ad-copy { - align-self: stretch; - flex: 1 1 auto; - min-width: 0; - padding: 6px 4px 6px 8px; - display: flex; - flex-direction: column; - justify-content: center; - align-items: flex-start; - gap: 3px; - box-sizing: border-box; - } - - .bandix-ad-title { - width: 100%; - font-size: 0.6875rem; - font-weight: 600; - line-height: 1.25; - text-align: left; - overflow: hidden; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - } - - .bandix-ad-media { - align-self: stretch; - flex: 0 0 33.333333%; - min-width: 0; - aspect-ratio: 1 / 1; - display: flex; - align-items: center; - justify-content: center; - background: rgba(255, 255, 255, 0.92); - } - - .bandix-ad-image { - display: block; - width: 100%; - height: 100%; - object-fit: contain; - } - - .bandix-ad-placeholder { - flex: 0 0 33.333333%; - aspect-ratio: 1 / 1; - align-self: stretch; - display: flex; - align-items: center; - justify-content: center; - padding: 3px; - background: rgba(255, 255, 255, 0.92); - color: #e1251b; - font-size: 0.625rem; - font-weight: 700; - line-height: 1.2; - text-align: center; - box-sizing: border-box; - } - - /* 移动端隐藏版本信息和更新徽章 */ @media (max-width: 768px) { .bandix-version-wrapper { display: none; } - - .bandix-ad-row { - display: flex; - gap: 6px; - padding-bottom: 4px; - } - - .bandix-ad-slot { - flex: 0 0 180px; - min-width: 180px; - height: 60px; - } - - .bandix-ad-copy { - padding-left: 7px; - } - - .bandix-ad-title { - font-size: 0.625rem; - } } .device-mode-group { @@ -2956,25 +2819,6 @@ return view.extend({ ]) ]), - // 广告数据从公开仓库动态加载 - E('div', { - 'class': 'bandix-ad-row', - 'id': 'bandix-ad-row', - 'aria-label': _('Advertising spaces') - }, [1, 2, 3, 4, 5, 6].map(function (index) { - return E('div', { - 'class': 'bandix-ad-slot bandix-ad-disabled', - 'data-ad-slot': String(index), - 'aria-disabled': 'true' - }, [ - E('div', { 'class': 'bandix-ad-copy' }, [ - E('span', { 'class': 'bandix-ad-label' }, _('AD')), - E('span', { 'class': 'bandix-ad-title' }, _('Advertising space') + ' ' + index) - ]), - E('span', { 'class': 'bandix-ad-placeholder' }, _('Advertising space')) - ]); - })), - // 警告提示(包含在线设备数) E('div', { 'class': 'bandix-alert' + (getThemeType() === 'wide' ? ' wide-theme' : '') @@ -8147,205 +7991,6 @@ return view.extend({ updateTrafficIncrements(startMs, endMs, null, null); }, 700); - // 异步加载远程广告(不阻塞主流程) - (function () { - var refreshTimer = null; - - function resolveHttpsUrl(value, baseUrl) { - if (typeof value !== 'string' || !value) return null; - - try { - var resolved = new URL(value, baseUrl); - return resolved.protocol === 'https:' ? resolved.href : null; - } catch (e) { - return null; - } - } - - function scheduleRefresh(seconds) { - var interval = Number(seconds); - if (!Number.isFinite(interval)) interval = BANDIX_AD_DEFAULT_REFRESH_INTERVAL; - interval = Math.max(300, Math.min(86400, interval)); - - if (refreshTimer !== null) window.clearTimeout(refreshTimer); - refreshTimer = window.setTimeout(loadAdvertisements, interval * 1000); - } - - function normalizeAdvertisementLocale(value) { - if (typeof value !== 'string') return ''; - - var locale = value.trim().replace(/_/g, '-').toLowerCase(); - if (!locale || locale === 'auto' || locale === 'und') return ''; - - if (locale === 'zh' || locale === 'zh-cn' || locale === 'zh-sg' || locale === 'zh-hans') { - return 'zh-hans'; - } - if (locale === 'zh-tw' || locale === 'zh-hk' || locale === 'zh-mo' || locale === 'zh-hant') { - return 'zh-hant'; - } - - return locale; - } - - function getAdvertisementLocale() { - var candidates = []; - if (L.env) candidates.push(L.env.lang || L.env.language || ''); - var htmlLanguage = document.documentElement.getAttribute('lang'); - if (htmlLanguage) candidates.push(htmlLanguage); - if (window.navigator) candidates.push(window.navigator.language || ''); - - for (var i = 0; i < candidates.length; i++) { - var locale = normalizeAdvertisementLocale(candidates[i]); - if (locale) return locale; - } - - return ''; - } - - function selectLocalizedAdvertisements(config) { - // 兼容旧版单语言配置,方便两个仓库分开部署 - if (config.version === 1 && Array.isArray(config.ads)) { - return { locale: 'legacy', ads: config.ads }; - } - - if (config.version !== 2 || !config.locales || typeof config.locales !== 'object') { - throw new Error('Invalid advertising configuration'); - } - - var currentLocale = getAdvertisementLocale(); - var defaultLocale = normalizeAdvertisementLocale(config.default_locale); - var localeCandidates = []; - - if (currentLocale) { - localeCandidates.push(currentLocale); - var separatorIndex = currentLocale.indexOf('-'); - if (separatorIndex > 0) localeCandidates.push(currentLocale.substring(0, separatorIndex)); - } - if (defaultLocale) localeCandidates.push(defaultLocale); - - for (var i = 0; i < localeCandidates.length; i++) { - var candidate = localeCandidates[i]; - if (Object.prototype.hasOwnProperty.call(config.locales, candidate) && - Array.isArray(config.locales[candidate])) { - return { locale: candidate, ads: config.locales[candidate] }; - } - } - - throw new Error('No advertising locale is available'); - } - - function renderAdvertisements(config) { - var adRow = document.getElementById('bandix-ad-row'); - if (!adRow || !config) { - throw new Error('Invalid advertising configuration'); - } - - var selection = selectLocalizedAdvertisements(config); - adRow.setAttribute('data-ad-locale', selection.locale); - - var ads = selection.ads.slice(0, 6).map(function (ad, index) { - if (!ad || typeof ad !== 'object') ad = {}; - - var href = resolveHttpsUrl(ad.href, BANDIX_AD_CONFIG_URL); - var image = resolveHttpsUrl(ad.image, BANDIX_AD_CONFIG_URL); - var title = typeof ad.title === 'string' ? ad.title.trim() : _('Advertising space') + ' ' + (index + 1); - if (!title) title = _('Advertising space') + ' ' + (index + 1); - var alt = typeof ad.alt === 'string' ? ad.alt.trim() : title; - - return { - enabled: ad.enabled === true && href !== null, - href: href, - image: image, - title: title, - alt: alt || title - }; - }); - - while (ads.length < 6) { - ads.push({ - enabled: false, - href: null, - image: null, - title: _('Advertising space') + ' ' + (ads.length + 1), - alt: _('Advertising space') - }); - } - - while (adRow.firstChild) adRow.removeChild(adRow.firstChild); - - ads.forEach(function (ad, index) { - var tagName = ad.enabled ? 'a' : 'div'; - var attributes = { - 'class': 'bandix-ad-slot' + (ad.enabled ? '' : ' bandix-ad-disabled'), - 'data-ad-slot': String(index + 1), - 'title': ad.title - }; - - if (ad.enabled) { - attributes.href = ad.href; - attributes.target = '_blank'; - attributes.rel = 'noopener noreferrer sponsored'; - } else { - attributes['aria-disabled'] = 'true'; - } - - var content = [E('div', { 'class': 'bandix-ad-copy' }, [ - E('span', { 'class': 'bandix-ad-label' }, _('AD')), - E('span', { 'class': 'bandix-ad-title' }, ad.title) - ])]; - if (ad.enabled && ad.image) { - content.push(E('div', { 'class': 'bandix-ad-media' }, [ - E('img', { - 'class': 'bandix-ad-image', - 'src': ad.image, - 'alt': ad.alt, - 'loading': 'lazy', - 'referrerpolicy': 'no-referrer' - }) - ])); - } else { - content.push(E('span', { 'class': 'bandix-ad-placeholder' }, _('Advertising space'))); - } - - adRow.appendChild(E(tagName, attributes, content)); - }); - - adRow.style.setProperty('--bandix-ad-count', '6'); - } - - function loadAdvertisements() { - var adRow = document.getElementById('bandix-ad-row'); - if (!adRow) return; - - if (typeof window.fetch !== 'function') { - console.debug('Failed to load advertisements: Fetch API is unavailable'); - scheduleRefresh(BANDIX_AD_RETRY_INTERVAL); - return; - } - - var separator = BANDIX_AD_CONFIG_URL.indexOf('?') === -1 ? '?' : '&'; - var configUrl = BANDIX_AD_CONFIG_URL + separator + '_=' + Date.now(); - - window.fetch(configUrl, { - method: 'GET', - mode: 'cors', - credentials: 'omit', - cache: 'no-store' - }).then(function (response) { - if (!response.ok) throw new Error('HTTP ' + response.status); - return response.json(); - }).then(function (config) { - renderAdvertisements(config); - scheduleRefresh(config.refresh_interval); - }).catch(function (err) { - console.debug('Failed to load advertisements:', err); - scheduleRefresh(BANDIX_AD_RETRY_INTERVAL); - }); - } - - window.setTimeout(loadAdvertisements, 200); - })(); - // 异步加载版本信息(不阻塞主流程) (function () { // 延迟执行,确保页面先完成初始化 diff --git a/luci-app-bandix/po/zh_Hans/bandix.po b/luci-app-bandix/po/zh_Hans/bandix.po index 0aa5f8c0..ee1c1945 100644 --- a/luci-app-bandix/po/zh_Hans/bandix.po +++ b/luci-app-bandix/po/zh_Hans/bandix.po @@ -1094,15 +1094,6 @@ msgstr "有更新" msgid "Update available, click to go to settings" msgstr "有更新,点击前往设置" -msgid "Advertising spaces" -msgstr "广告位" - -msgid "Advertising space" -msgstr "广告位" - -msgid "AD" -msgstr "广告" - msgid "Traffic Statistics" msgstr "流量统计" diff --git a/luci-app-bandix/po/zh_Hant/bandix.po b/luci-app-bandix/po/zh_Hant/bandix.po index 671ead3c..43d3a9cb 100644 --- a/luci-app-bandix/po/zh_Hant/bandix.po +++ b/luci-app-bandix/po/zh_Hant/bandix.po @@ -1279,12 +1279,3 @@ msgstr "TCX 出站錨點程式 ID" msgid "Used when tc_order is before/after. Must be a valid egress program id on the same interface." msgstr "當 tc_order 為 before/after 時使用。必須是同一介面上的有效出站程式 ID。" - -msgid "Advertising spaces" -msgstr "廣告位" - -msgid "Advertising space" -msgstr "廣告位" - -msgid "AD" -msgstr "廣告" diff --git a/luci-app-mosdns/Makefile b/luci-app-mosdns/Makefile index 731f82f9..3e4b0c3c 100644 --- a/luci-app-mosdns/Makefile +++ b/luci-app-mosdns/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-mosdns -PKG_VERSION:=1.7.5 +PKG_VERSION:=1.7.6 PKG_RELEASE:=1 LUCI_TITLE:=LuCI Support for mosdns diff --git a/luci-app-mosdns/root/usr/share/rpcd/ucode/luci.mosdns b/luci-app-mosdns/root/usr/share/rpcd/ucode/luci.mosdns index 83afc4c5..9760722f 100644 --- a/luci-app-mosdns/root/usr/share/rpcd/ucode/luci.mosdns +++ b/luci-app-mosdns/root/usr/share/rpcd/ucode/luci.mosdns @@ -2,7 +2,7 @@ 'use strict'; -import { popen, writefile, stat, readfile } from 'fs'; +import { popen, stat, readfile, open } from 'fs'; import { cursor } from 'uci'; function to_array(val) { @@ -99,8 +99,12 @@ const methods = { try { let path = get_logfile_path_internal(); if (path) { - writefile(path, ''); - return { success: true }; + let f = open(path, 'w'); + if (f) { + f.close(); + return { success: true }; + } + return { error: 'Failed to open log file for writing.' }; } else { return { error: 'Log file path could not be determined.' }; } diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua index 8c1b65f5..20f8ff3f 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/node_config.lua @@ -8,7 +8,6 @@ if not arg[1] or not m:get(arg[1]) then luci.http.redirect(m.redirect) end -fs = require "nixio.fs" formvalue_key = "cbid." .. m.config .. "." .. arg[1] .. "." m:appendTemplate("/node_config/header", {section = arg[1]}) @@ -24,7 +23,7 @@ m:foreach("nodes", function(s) end end) -s = m:section(NamedSection, arg[1], "nodes", translate("Node Config")) +local s = m:section(NamedSection, arg[1], "nodes", translate("Node Config")) s.addremove = false s.dynamic = false @@ -74,33 +73,35 @@ end o = s:option(ListValue, "type", translate("Type")) if api.is_finded("ipt2socks") then - s.fields["type"]:value("Socks", translate("Socks")) + local type_name = "Socks" - if s.val["type"] == "Socks" then - local function _n(name) - return "socks_" .. name - end - o = s:option(ListValue, _n("del_protocol"), " ") --始终隐藏,用于删除 protocol - o:depends({ [_n("__hide")] = "1" }) + s.fields["type"]:value(type_name, "Socks") + + if s.val["type"] == type_name then + local s2 = NamedSection(m, arg[1], "server") + s2.type_name = type_name + s2.option_prefix = "socks_" + + o = s2:option(ListValue, "del_protocol", " ") --始终隐藏,用于删除 protocol + o:depends({ __hide = "1" }) o.rewrite_option = "protocol" - o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) + o = s2:option(Value, "address", translate("Address (Support Domain Name)")) - o = s:option(Value, _n("port"), translate("Port")) + o = s2:option(Value, "port", translate("Port")) o.datatype = "port" - o = s:option(Value, _n("username"), translate("Username")) + o = s2:option(Value, "username", translate("Username")) - o = s:option(Value, _n("password"), translate("Password")) + o = s2:option(Value, "password", translate("Password")) o.password = true - api.luci_types(arg[1], m, s, "Socks", "socks_") + api.luci_types(s, s2) end - end local type_table = {} -for filename in fs.dir(types_dir) do +for filename in api.fs.dir(types_dir) do table.insert(type_table, filename) end table.sort(type_table) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua index 6f0aabb6..b9707722 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/socks_config.lua @@ -76,6 +76,20 @@ o = s:option(Flag, "log", translate("Enable") .. " " .. translate("Log")) o.default = 1 o.rmempty = false +o = s:option(DummyValue, "_log", translate("Log File")) +o.rawhtml = true +o.cfgvalue = function(t, n) + local log_path = api.TMP_PATH .. "/" .. arg[1] .. ".log" + local log_url = api.url("get_socks_log") .. "?name=" .. arg[1] + return string.format( + '%s  ', + log_path, + translate("View Log"), + log_url + ) +end +o:depends("log", true) + o = s:option(Flag, "enable_autoswitch", translate("Auto Switch")) o.default = 0 o.rmempty = false 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 new file mode 100644 index 00000000..cbab6003 --- /dev/null +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua @@ -0,0 +1,917 @@ +local singbox_bin = api.finded_com("sing-box") + +if not singbox_bin then + return +end + +-- [[ sing-box ]] +local m, s1 = ... +local type_name = "sing-box" + +s1.fields["type"]:value(type_name, "Sing-Box") +if not s1.fields["type"].default then + s1.fields["type"].default = type_name +end + +if s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "singbox_" + +local formvalue_proto = luci.http.formvalue(formvalue_key .. "protocol") + +if formvalue_proto then s1.val["protocol"] = formvalue_proto end + +local arg_select_proto = luci.http.formvalue("select_proto") or "" + +local ss_method_new_list = { + "none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" +} + +local ss_method_old_list = { + "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20", +} + +local security_list = { "none", "auto", "aes-128-gcm", "chacha20-poly1305", "zero" } + +local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'") + +local singbox_version = api.get_app_version("sing-box"):match("[^v]+") + +o = s:option(ListValue, "protocol", translate("Protocol")) +o:value("socks", "Socks") +o:value("http", "HTTP") +o:value("shadowsocks", "Shadowsocks") +o:value("vmess", "Vmess") +o:value("trojan", "Trojan") +if singbox_tags:find("with_wireguard") then + o:value("wireguard", "WireGuard") +end +if singbox_tags:find("with_quic") then + o:value("hysteria", "Hysteria") +end +o:value("vless", "VLESS") +if singbox_tags:find("with_quic") then + o:value("tuic", "TUIC") +end +if singbox_tags:find("with_quic") then + o:value("hysteria2", "Hysteria2") +end +o:value("anytls", "AnyTLS") +o:value("ssh", "SSH") +if singbox_tags:find("with_naive_outbound") then + o:value("naive", "NaïveProxy") +end +o:value("_urltest", translate("URLTest")) +o:value("_shunt", translate("Shunt")) +o:value("_iface", translate("Custom Interface")) +function o.custom_cfgvalue(self, section) + if arg_select_proto ~= "" then + return arg_select_proto + else + return m:get(section, self.config_option) + end +end + +local load_urltest_options = s1.val["protocol"] == "_urltest" or arg_select_proto == "_urltest" +local load_shunt_options = s1.val["protocol"] == "_shunt" or arg_select_proto == "_shunt" +local load_iface_options = s1.val["protocol"] == "_iface" or arg_select_proto == "_iface" +local load_normal_options = true +if load_urltest_options or load_shunt_options or load_iface_options then + load_normal_options = nil +end +if not arg_select_proto:find("_") then + load_normal_options = true +end + +local netdev_list = api.get_network_devices() +local node_list = api.get_node_list() + +if load_urltest_options then -- [[ URLTest Start ]] + o = s:option(ListValue, "node_add_mode", translate("Node Addition Method")) + o:depends({ protocol = "_urltest" }) + o.default = "manual" + o:value("manual", translate("Manual")) + o:value("batch", translate("Batch")) + + o = s:option(MultiValue, "urltest_node", translate("URLTest node list"), translate("List of nodes to test, document")) + o:depends({ node_add_mode = "manual" }) + o.widget = "checkbox" + o.template = m:template_path("/cbi/nodes_multivalue") + o.group = {} + for k1, v1 in pairs(node_list) do + if k1 == "socks_list" or k1 == "normal_list" then + for i, v in ipairs(v1) do + o:value(v.id, v.remark) + o.group[#o.group+1] = v.group or "" + end + end + end + -- 读取旧 DynamicList + function o.custom_cfgvalue(self, section) + return table.concat(m:get(section, "urltest_node") or {}, " ") + end + -- 写入保持 DynamicList + function o.custom_write(self, section, value) + local old = m:get(section, "urltest_node") or {} + local new, set = {}, {} + for v in value:gmatch("%S+") do + new[#new + 1] = v + set[v] = 1 + end + for _, v in ipairs(old) do + if not set[v] then + m:set(section, "urltest_node", new) + return + end + set[v] = nil + end + for _ in pairs(set) do + m:set(section, "urltest_node", new) + return + end + end + + o = s:option(MultiValue, "node_group", translate("Select Group")) + o:depends({ node_add_mode = "batch" }) + o.widget = "checkbox" + o:value("default", translate("default")) + for k, v in pairs(groups) do + o:value(api.UrlEncode(k), k) + end + + o = s:option(Value, "node_match_rule", translate("Node Matching Rules")) + o:depends({ node_add_mode = "batch" }) + local descrStr = "Example: ^A && B && !C && D$
" + descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" + descrStr = descrStr .. "Conditions are joined by && (AND), and their order does not affect the result.
" + descrStr = descrStr .. "Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" + descrStr = descrStr .. "Example: A && B || C && D means (A AND B) OR (C AND D)." + o.description = translate(descrStr) + + o = s:option(Value, "urltest_url", translate("Probe URL")) + o:depends({ protocol = "_urltest" }) + o:value("https://cp.cloudflare.com/", "Cloudflare") + o:value("https://www.gstatic.com/generate_204", "Gstatic") + o:value("https://www.google.com/generate_204", "Google") + o:value("https://www.youtube.com/generate_204", "YouTube") + o:value("https://connect.rom.miui.com/generate_204", "MIUI (CN)") + o:value("https://connectivitycheck.platform.hicloud.com/generate_204", "HiCloud (CN)") + o:value("https://wifi.vivo.com.cn/generate_204", "VIVO (CN)") + o.default = o.keylist[3] + o.description = translate("The URL used to detect the connection status.") + + o = s:option(Value, "urltest_interval", translate("Test interval")) + o:depends({ protocol = "_urltest" }) + o.default = "3m" + o.placeholder = "3m" + o.description = translate("The interval between initiating probes.") .. "
" .. + translate("The time format is numbers + units, such as '10s', '2h45m', and the supported time units are s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "
" .. + translate("When the unit is not filled in, it defaults to seconds.") .. "
" .. + translate("Test interval must be less or equal than idle timeout.") + + o = s:option(Value, "urltest_tolerance", translate("Test tolerance"), translate("The test tolerance in milliseconds.")) + o:depends({ protocol = "_urltest" }) + o.datatype = "uinteger" + o.placeholder = "50" + o.default = "50" + + o = s:option(Value, "urltest_idle_timeout", translate("Idle timeout")) + o:depends({ protocol = "_urltest" }) + o.placeholder = "30m" + o.default = "30m" + o.description = translate("The idle timeout.") .. "
" .. + translate("The time format is numbers + units, such as '10s', '2h45m', and the supported time units are s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "
" .. + translate("When the unit is not filled in, it defaults to seconds.") + + o = s:option(Flag, "urltest_interrupt_exist_connections", translate("Interrupt existing connections")) + o:depends({ protocol = "_urltest" }) + o.default = "0" + o.description = translate("Interrupt existing connections when the selected outbound has changed.") +end -- [[ URLTest End ]] + +if load_iface_options then -- [[ 自定义接口 Start ]] + o = s:option(Value, "iface", translate("Interface")) + o:depends({ protocol = "_iface" }) + for _, d in ipairs(netdev_list) do + o:value(d.name, d.label) + end +end + + +if load_normal_options then + +o = s:option(Value, "address", translate("Address (Support Domain Name)")) + +o = s:option(Value, "port", translate("Port")) +o.datatype = "port" + +o = s:option(Value, "uuid", translate("ID")) +o.password = true +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "tuic" }) + +o = s:option(Value, "username", translate("Username")) +o:depends({ protocol = "http" }) +o:depends({ protocol = "socks" }) +o:depends({ protocol = "ssh" }) +o:depends({ protocol = "naive" }) + +o = s:option(Value, "password", translate("Password")) +o.password = true +o:depends({ protocol = "http" }) +o:depends({ protocol = "socks" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "trojan" }) +o:depends({ protocol = "tuic" }) +o:depends({ protocol = "anytls" }) +o:depends({ protocol = "ssh" }) +o:depends({ protocol = "naive" }) + +o = s:option(ListValue, "security", translate("Encrypt Method")) +for a, t in ipairs(security_list) do o:value(t) end +o:depends({ protocol = "vmess" }) + +o = s:option(ListValue, "ss_method", translate("Encrypt Method")) +o.rewrite_option = "method" +for a, t in ipairs(ss_method_new_list) do o:value(t) end +for a, t in ipairs(ss_method_old_list) do o:value(t) end +o:depends({ protocol = "shadowsocks" }) + +o = s:option(Flag, "uot", translate("UDP over TCP")) +o:depends({ protocol = "socks" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "naive" }) + +o = s:option(Value, "alter_id", "Alter ID") +o.datatype = "uinteger" +o.default = "0" +o:depends({ protocol = "vmess" }) + +o = s:option(Flag, "global_padding", "global_padding", translate("Protocol parameter. Will waste traffic randomly if enabled.")) +o.default = "0" +o:depends({ protocol = "vmess" }) + +o = s:option(Flag, "authenticated_length", "authenticated_length", translate("Protocol parameter. Enable length block encryption.")) +o.default = "0" +o:depends({ protocol = "vmess" }) + +o = s:option(ListValue, "flow", translate("flow")) +o.default = "" +o:value("", translate("Disable")) +o:value("xtls-rprx-vision") +o:depends({ protocol = "vless", tls = true }) + +if singbox_tags:find("with_quic") then + o = s:option(Value, "hysteria_hop", translate("Port hopping range")) + o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).") + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_hop_interval", translate("Hop Interval(second)"), translate("Example:") .. "30 (≥5)") + o.datatype = "uinteger" + o.placeholder = "30" + o.default = "30" + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_obfs", translate("Obfs Password")) + o:depends({ protocol = "hysteria" }) + + o = s:option(ListValue, "hysteria_auth_type", translate("Auth Type")) + o:value("disable", translate("Disable")) + o:value("string", translate("STRING")) + o:value("base64", translate("BASE64")) + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_auth_password", translate("Auth Password")) + o.password = true + o:depends({ protocol = "hysteria", hysteria_auth_type = "string"}) + o:depends({ protocol = "hysteria", hysteria_auth_type = "base64"}) + + o = s:option(Value, "hysteria_up_mbps", translate("Max upload Mbps")) + o.default = "10" + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_down_mbps", translate("Max download Mbps")) + o.default = "50" + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_recv_window_conn", translate("QUIC stream receive window")) + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_recv_window", translate("QUIC connection receive window")) + o:depends({ protocol = "hysteria" }) + + o = s:option(Flag, "hysteria_disable_mtu_discovery", translate("Disable MTU detection")) + o:depends({ protocol = "hysteria" }) +end + +if singbox_tags:find("with_quic") then + o = s:option(ListValue, "tuic_congestion_control", translate("Congestion control algorithm")) + o.default = "cubic" + o:value("bbr", translate("BBR")) + o:value("cubic", translate("CUBIC")) + o:value("new_reno", translate("New Reno")) + o:depends({ protocol = "tuic" }) + + o = s:option(ListValue, "tuic_udp_relay_mode", translate("UDP relay mode")) + o.default = "native" + o:value("native", translate("native")) + o:value("quic", translate("QUIC")) + o:depends({ protocol = "tuic" }) + + --[[ + o = s:option(Flag, "tuic_udp_over_stream", translate("UDP over stream")) + o:depends({ protocol = "tuic" }) + ]]-- + + o = s:option(Flag, "tuic_zero_rtt_handshake", translate("Enable 0-RTT QUIC handshake")) + o.default = 0 + o:depends({ protocol = "tuic" }) + + o = s:option(Value, "tuic_heartbeat", translate("Heartbeat interval(second)")) + o.datatype = "uinteger" + o.default = "3" + o:depends({ protocol = "tuic" }) + + o = s:option(ListValue, "tuic_alpn", translate("QUIC TLS ALPN")) + o.default = "default" + o:value("default", translate("Default")) + o:value("h3") + o:value("h2") + o:value("h3,h2") + o:value("http/1.1") + o:value("h2,http/1.1") + o:value("h3,h2,http/1.1") + o:value("spdy/3.1") + o:value("h3,spdy/3.1") + o:depends({ protocol = "tuic" }) +end + +if singbox_tags:find("with_quic") then + o = s:option(Value, "hysteria2_hop", translate("Port hopping range")) + o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).") + o:depends({ protocol = "hysteria2", hysteria2_realms = false }) + + o = s:option(Value, "hysteria2_hop_interval", translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5.")) + o.datatype = "or(uinteger,portrange)" + o.placeholder = "30" + o.default = "30" + o:depends({ protocol = "hysteria2", hysteria2_realms = false }) + + o = s:option(Flag, "hysteria2_realms", translate("Realms")) + o.default = "0" + if api.compare_versions(singbox_version, ">=", "1.14.0") then + o:depends({ protocol = "hysteria2"}) + else + o:depends({ protocol = "__hide"}) + end + + o = s:option(Value, "hysteria2_realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") + o:depends({ hysteria2_realms = "1" }) + o.validate = function(self, value) + value = api.trim(value) + local realm = api.parse_realm_uri(value) + if realm then return value end + return nil, translate("Invalid Realm URL.") + end + + o = s:option(DynamicList, "hysteria2_realm_stun", translate("Realm STUN")) + o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } + o:depends({ hysteria2_realms = "1" }) + + o = s:option(Value, "hysteria2_auth_password", translate("Auth Password")) + o.password = true + o:depends({ protocol = "hysteria2"}) + + o = s:option(ListValue, "hysteria2_obfs_type", translate("Obfs Type")) + o:value("", translate("Disable")) + o:value("salamander") + o:value("gecko") + o:depends({ protocol = "hysteria2" }) + + o = s:option(Value, "hysteria2_obfs_password", translate("Obfs Password")) + o:depends({ hysteria2_obfs_type = "salamander" }) + o:depends({ hysteria2_obfs_type = "gecko" }) + + o = s:option(Value, "hysteria2_obfs_MinPacketSize", translate("Gecko Packet Size (min)")) + o.datatype = "uinteger" + o.placeholder = "512" + o.default = "512" + o:depends({ hysteria2_obfs_type = "gecko" }) + + o = s:option(Value, "hysteria2_obfs_MaxPacketSize", translate("Gecko Packet Size (max)")) + o.datatype = "uinteger" + o.placeholder = "1200" + o.default = "1200" + o:depends({ hysteria2_obfs_type = "gecko" }) + + o = s:option(Value, "hysteria2_up_mbps", translate("Max upload Mbps")) + o:depends({ protocol = "hysteria2" }) + + o = s:option(Value, "hysteria2_down_mbps", translate("Max download Mbps")) + o:depends({ protocol = "hysteria2" }) + + o = s:option(Value, "hysteria2_idle_timeout", translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)") + o.datatype = "range(4,120)" + o:depends({ protocol = "hysteria2"}) + + o = s:option(Value, "hysteria2_keep_alive_period", translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)") + o.datatype = "range(2,60)" + o:depends({ protocol = "hysteria2"}) + + o = s:option(Flag, "hysteria2_disable_mtu_discovery", translate("Disable MTU detection")) + o.default = "0" + o:depends({ protocol = "hysteria2"}) +end + +-- [[ SSH config start ]] -- +o = s:option(TextValue, "ssh_priv_key", translate("Private Key")) +o.rows = 5 +o.wrap = "off" +o:depends({ protocol = "ssh" }) +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value +end + +o = s:option(Value, "ssh_priv_key_pp", translate("Private Key Passphrase")) +o.password = true +o:depends({ protocol = "ssh" }) + +o = s:option(DynamicList, "ssh_host_key", translate("Host Key"), translate("Accept any if empty.")) +o:depends({ protocol = "ssh" }) + +o = s:option(DynamicList, "ssh_host_key_algo", translate("Host Key Algorithms")) +o:depends({ protocol = "ssh" }) + +o = s:option(Value, "ssh_client_version", translate("Client Version"), translate("Random version will be used if empty.")) +o:depends({ protocol = "ssh" }) +-- [[ SSH config end ]] -- + +-- [[ naive start ]] -- +o = s:option(Value, "naive_insecure_concurrency", translate("Concurrent Tunnels")) +o.datatype = "uinteger" +o.placeholder = "0" +o.default = "0" +o:depends({ protocol = "naive" }) + +o = s:option(Flag, "naive_quic", translate("QUIC")) +o.default = 0 +o:depends({ protocol = "naive" }) + +o = s:option(ListValue, "naive_congestion_control", translate("Congestion control algorithm")) +o.default = "bbr" +o:value("bbr", translate("BBR")) +o:value("bbr2", translate("BBRv2")) +o:value("cubic", translate("CUBIC")) +o:value("reno", translate("New Reno")) +o:depends({ naive_quic = "1" }) +-- [[ naive end ]] -- + +o = s:option(Flag, "tls", translate("TLS")) +o.default = 0 +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "http" }) +o:depends({ protocol = "trojan" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "anytls" }) + +o = s:option(ListValue, "alpn", translate("ALPN")) +o.default = "default" +o:value("default", translate("Default")) +o:value("h3") +o:value("h2") +o:value("h3,h2") +o:value("http/1.1") +o:value("h2,http/1.1") +o:value("h3,h2,http/1.1") +o:depends({ tls = true }) +o:depends({ protocol = "hysteria" }) + +o = s:option(Flag, "tls_disable_sni", translate("Disable SNI"), translate("Do not send server name in ClientHello.")) +o.default = "0" +o:depends({ tls = true }) +o:depends({ protocol = "hysteria"}) +o:depends({ protocol = "tuic" }) +o:depends({ protocol = "hysteria2" }) + +o = s:option(Value, "tls_serverName", "SNI " .. translate("Domain")) +o:depends({ tls = true }) +o:depends({ protocol = "hysteria"}) +o:depends({ protocol = "tuic" }) +o:depends({ protocol = "hysteria2" }) +o:depends({ protocol = "naive" }) + +o = s:option(Flag, "tls_allowInsecure", translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped.")) +o.default = "0" +o:depends({ tls = true }) +o:depends({ protocol = "hysteria"}) +o:depends({ protocol = "tuic" }) +o:depends({ protocol = "hysteria2" }) + +o = s:option(Flag, "tls_certificate", translate("TLS Certificate (PEM)")) +o.default = "0" +o:depends({ tls = true, reality = false }) +o:depends({ protocol = "hysteria"}) +o:depends({ protocol = "tuic" }) +o:depends({ protocol = "hysteria2" }) +o:depends({ protocol = "naive" }) + +o = s:option(TextValue, "tls_certificate_pem", " ", translate("Full certificate (chain), PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ tls_certificate = true }) +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value +end + +o = s:option(Value, "cipherSuites", translate("Cipher Suites"), '***' .. " " .. translate("Configures the list of supported cipher suites, separated by :")) +o:depends({ tls = true }) + +o = s:option(Flag, "ech", translate("ECH")) +o.default = "0" +o:depends({ tls = true, flow = "", reality = false }) +o:depends({ protocol = "tuic" }) +o:depends({ protocol = "hysteria" }) +o:depends({ protocol = "hysteria2", hysteria2_realms = false }) +o:depends({ protocol = "naive" }) + +o = s:option(TextValue, "ech_config", translate("ECH Config")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ ech = true }) +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value +end + +o = s:option(Value, "ech_query_server_name", translate("ECH Query Domain"), translate("Overrides the domain name used for ECH HTTPS record queries.")) +o:depends({ ech = true }) + +if singbox_tags:find("with_utls") then + o = s:option(Flag, "utls", translate("uTLS")) + o.default = "0" + o:depends({ tls = true }) + + o = s:option(ListValue, "fingerprint", translate("Finger Print")) + o:value("chrome") + o:value("firefox") + o:value("edge") + o:value("safari") + o:value("360") + o:value("qq") + o:value("ios") + o:value("android") + o:value("random") + o:value("randomized") + o.default = "chrome" + o:depends({ utls = true }) + + -- [[ REALITY部分 ]] -- + o = s:option(Flag, "reality", translate("REALITY")) + o.default = 0 + o:depends({ protocol = "vless", tls = true }) + o:depends({ protocol = "vmess", tls = true }) + o:depends({ protocol = "shadowsocks", tls = true }) + o:depends({ protocol = "trojan", tls = true }) + o:depends({ protocol = "anytls", tls = true }) + + o = s:option(Value, "reality_publicKey", translate("Public Key")) + o:depends({ reality = true }) + + o = s:option(Value, "reality_shortId", translate("Short Id")) + o:depends({ reality = true }) +end + +o = s:option(ListValue, "transport", translate("Transport")) +o:value("tcp", "TCP") +o:value("http", "HTTP") +o:value("ws", "WebSocket") +o:value("httpupgrade", "HTTPUpgrade") +if singbox_tags:find("with_quic") then + o:value("quic", "QUIC") +end +if singbox_tags:find("with_grpc") then + o:value("grpc", "gRPC") +else o:value("grpc", "gRPC-lite") +end +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "trojan" }) + +if singbox_tags:find("with_wireguard") then + o = s:option(Value, "wireguard_public_key", translate("Public Key")) + o:depends({ protocol = "wireguard" }) + + o = s:option(Value, "wireguard_secret_key", translate("Private Key")) + o:depends({ protocol = "wireguard" }) + + o = s:option(Value, "wireguard_preSharedKey", translate("Pre shared key")) + o:depends({ protocol = "wireguard" }) + + o = s:option(DynamicList, "wireguard_local_address", translate("Local Address")) + o:depends({ protocol = "wireguard" }) + + o = s:option(Value, "wireguard_mtu", translate("MTU")) + o.default = "1420" + o:depends({ protocol = "wireguard" }) + + o = s:option(Value, "wireguard_reserved", translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings.")) + o:depends({ protocol = "wireguard" }) +end + +-- [[ TCP部分(模拟) ]]-- +o = s:option(ListValue, "tcp_guise", translate("Camouflage Type")) +o:value("none", "none") +o:value("http", "http") +o:depends({ transport = "tcp" }) + +o = s:option(DynamicList, "tcp_guise_http_host", translate("HTTP Host")) +o:depends({ tcp_guise = "http" }) + +o = s:option(DynamicList, "tcp_guise_http_path", translate("HTTP Path")) +o.placeholder = "/" +o:depends({ tcp_guise = "http" }) + +-- [[ HTTP部分 ]]-- +o = s:option(DynamicList, "http_host", translate("HTTP Host")) +o:depends({ transport = "http" }) + +o = s:option(Value, "http_path", translate("HTTP Path")) +o.placeholder = "/" +o:depends({ transport = "http" }) + +o = s:option(Flag, "http_h2_health_check", translate("Health check")) +o:depends({ tls = true, transport = "http" }) + +o = s:option(Value, "http_h2_read_idle_timeout", translate("Idle timeout")) +o.default = "15" +o:depends({ http_h2_health_check = true }) + +o = s:option(Value, "http_h2_health_check_timeout", translate("Health check timeout")) +o.default = "15" +o:depends({ http_h2_health_check = true }) + +-- [[ WebSocket部分 ]]-- +o = s:option(Value, "ws_host", translate("WebSocket Host")) +o:depends({ transport = "ws" }) + +o = s:option(Value, "ws_path", translate("WebSocket Path")) +o.placeholder = "/" +o:depends({ transport = "ws" }) + +o = s:option(Flag, "ws_enableEarlyData", translate("Enable early data")) +o:depends({ transport = "ws" }) + +o = s:option(Value, "ws_maxEarlyData", translate("Early data length")) +o.default = "1024" +o:depends({ ws_enableEarlyData = true }) + +o = s:option(Value, "ws_earlyDataHeaderName", translate("Early data header name"), translate("Recommended value: Sec-WebSocket-Protocol")) +o:depends({ ws_enableEarlyData = true }) + +-- [[ HTTPUpgrade部分 ]]-- +o = s:option(Value, "httpupgrade_host", translate("HTTPUpgrade Host")) +o:depends({ transport = "httpupgrade" }) + +o = s:option(Value, "httpupgrade_path", translate("HTTPUpgrade Path")) +o.placeholder = "/" +o:depends({ transport = "httpupgrade" }) + +-- [[ gRPC部分 ]]-- +o = s:option(Value, "grpc_serviceName", "ServiceName") +o:depends({ transport = "grpc" }) + +o = s:option(Flag, "grpc_health_check", translate("Health check")) +o:depends({ transport = "grpc" }) + +o = s:option(Value, "grpc_idle_timeout", translate("Idle timeout")) +o.default = "15" +o:depends({ grpc_health_check = true }) + +o = s:option(Value, "grpc_health_check_timeout", translate("Health check timeout")) +o.default = "15" +o:depends({ grpc_health_check = true }) + +o = s:option(Flag, "grpc_permit_without_stream", translate("Permit without stream")) +o.default = "0" +o:depends({ grpc_health_check = true }) + +-- [[ User-Agent ]]-- +o = s:option(Value, "user_agent", translate("User-Agent")) +o.default = "" +o:value("", translate("default")) +o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36", "chrome") +o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0", "firefox") +o:value("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15", "safari") +o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70", "edge") +o:value("Go-http-client/1.1", "golang") +o:value("curl/7.68.0", "curl") +o:depends({ tcp_guise = "http" }) +o:depends({ transport = "http" }) +o:depends({ transport = "ws" }) +o:depends({ transport = "httpupgrade" }) +o:depends({ protocol = "naive" }) + +-- [[ Mux ]]-- +o = s:option(Flag, "mux", translate("Mux")) +o.rmempty = false +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless", flow = "" }) +o:depends({ protocol = "shadowsocks", uot = "" }) +o:depends({ protocol = "trojan" }) + +o = s:option(ListValue, "mux_type", translate("Mux")) +o:value("smux") +o:value("yamux") +o:value("h2mux") +o:depends({ mux = true }) + +o = s:option(Value, "mux_concurrency", translate("Mux concurrency")) +o.default = 4 +o:depends({ mux = true, tcpbrutal = false }) + +o = s:option(Flag, "mux_padding", translate("Padding")) +o.default = 0 +o:depends({ mux = true }) + +-- [[ TCP Brutal ]]-- +o = s:option(Flag, "tcpbrutal", translate("TCP Brutal")) +o.default = 0 +o:depends({ mux = true }) + +o = s:option(Value, "tcpbrutal_up_mbps", translate("Max upload Mbps")) +o.default = "10" +o:depends({ tcpbrutal = true }) + +o = s:option(Value, "tcpbrutal_down_mbps", translate("Max download Mbps")) +o.default = "50" +o:depends({ tcpbrutal = true }) + +o = s:option(Flag, "shadowtls", "ShadowTLS") +o.default = 0 +o:depends({ protocol = "vmess", tls = false }) +o:depends({ protocol = "shadowsocks", tls = false }) + +o = s:option(ListValue, "shadowtls_version", "ShadowTLS " .. translate("Version")) +o.default = "1" +o:value("1", "ShadowTLS v1") +o:value("2", "ShadowTLS v2") +o:value("3", "ShadowTLS v3") +o:depends({ shadowtls = true }) + +o = s:option(Value, "shadowtls_password", "ShadowTLS " .. translate("Password")) +o.password = true +o:depends({ shadowtls = true, shadowtls_version = "2" }) +o:depends({ shadowtls = true, shadowtls_version = "3" }) + +o = s:option(Value, "shadowtls_serverName", "ShadowTLS " .. translate("Domain")) +o:depends({ shadowtls = true }) + +if singbox_tags:find("with_utls") then + o = s:option(Flag, "shadowtls_utls", "ShadowTLS " .. translate("uTLS")) + o.default = "0" + o:depends({ shadowtls = true }) + + o = s:option(ListValue, "shadowtls_fingerprint", "ShadowTLS " .. translate("Finger Print")) + o:value("chrome") + o:value("firefox") + o:value("edge") + o:value("safari") + -- o:value("360") + o:value("qq") + o:value("ios") + -- o:value("android") + o:value("random") + -- o:value("randomized") + o.default = "chrome" + o:depends({ shadowtls = true, shadowtls_utls = true }) +end + +-- [[ SIP003 plugin ]]-- +o = s:option(Flag, "plugin_enabled", translate("plugin")) +o.default = 0 +o:depends({ protocol = "shadowsocks" }) + +o = s:option(ListValue, "plugin", "SIP003 " .. translate("plugin")) +o.default = "obfs-local" +o:depends({ plugin_enabled = true }) +o:value("obfs-local") +o:value("v2ray-plugin") + +o = s:option(Value, "plugin_opts", translate("opts")) +o:depends({ plugin_enabled = true }) + +o = s:option(ListValue, "domain_resolver", translate("Domain DNS Resolve")) +o.description = translate("If the node address is a domain name, this DNS will be used for resolution.") .. "
" .. string.format('%s', + translate("Note: For node-specific DNS only. Keep Auto to avoid extra overhead.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "DoH") + +o = s:option(Value, "domain_resolver_dns", "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ domain_resolver = "tcp" }) +o:depends({ domain_resolver = "udp" }) + +o = s:option(Value, "domain_resolver_dns_https", "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ domain_resolver = "https" }) + +o = s:option(ListValue, "domain_strategy", translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) +o.default = "" +o:value("", translate("Auto")) +o:value("prefer_ipv4", translate("Prefer IPv4")) +o:value("prefer_ipv6", translate("Prefer IPv6")) +o:value("ipv4_only", translate("IPv4 Only")) +o:value("ipv6_only", translate("IPv6 Only")) + + +local protocols = s.fields["protocol"].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + local depends_condition = { protocol = v } + if v == "hysteria2" then + depends_condition["hysteria2_realms"] = false + end + s.fields["address"]:depends(depends_condition) + s.fields["port"]:depends(depends_condition) + s.fields["domain_resolver"]:depends(depends_condition) + s.fields["domain_strategy"]:depends(depends_condition) + end + end +end +end +-- [[ Normal single node End ]] + +if not load_shunt_options then + o = s:option(ListValue, "chain_proxy", translate("Chain Proxy")) + o:value("", translate("Close(Not use)")) + if not (load_iface_options or load_urltest_options) then + -- Special node cannot be use pre-proxy. + o:value("1", translate("Preproxy Node")) + o:value("3", translate("Outbound Interface")) + end + o:value("2", translate("Landing Node")) + + o1 = s:option(ListValue, "preproxy_node", translate("Preproxy Node"), translate("Only support a layer of proxy.")) + o1:depends({ chain_proxy = "1", hysteria2_realms = false }) + o1.template = m:template_path("/cbi/nodes_listvalue") + o1.group = {} + + o3 = s:option(Value, "outbound_iface", translate("Outbound Interface")) + o3:depends({ chain_proxy = "3" }) + o3:value("", translate("All")) + for _, d in ipairs(netdev_list) do + o3:value(d.name, d.label) + end + + o2 = s:option(ListValue, "to_node", translate("Landing Node"), translate("Only support a layer of proxy.")) + o2:depends({ chain_proxy = "2", hysteria2_realms = false }) + o2.template = m:template_path("/cbi/nodes_listvalue") + o2.group = {} + + for k1, v1 in pairs(node_list) do + if k1 ~= "shunt_list" and k1 ~= "iface_list" then + for i, v in ipairs(v1) do + if v.id ~= arg[1] then + o1:value(v.id, v.remark) + o1.group[#o1.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + if k1 == "normal_list" then + -- Landing Node not support use special node. + o2:value(v.id, v.remark) + o2.group[#o2.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + end + end + end + end +end + +api.luci_types(s1, s) + +if load_shunt_options then + local current_node = m:get(arg[1]) or {} + local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua") + setfenv(shunt_lua, getfenv(1))(m, s1, { + node_id = arg[1], + node = current_node, + node_list = node_list, + }) +end 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 new file mode 100644 index 00000000..1697d1de --- /dev/null +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua @@ -0,0 +1,894 @@ +if not api.finded_com("xray") then + return +end + +-- [[ Xray ]] +local m, s1 = ... +local type_name = "Xray" + +s1.fields["type"]:value(type_name, "Xray") +if not s1.fields["type"].default then + s1.fields["type"].default = type_name +end + +if s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "xray_" + +local formvalue_proto = luci.http.formvalue(formvalue_key .. "protocol") + +if formvalue_proto then s1.val["protocol"] = formvalue_proto end + +local arg_select_proto = luci.http.formvalue("select_proto") or "" + +local ss_method_list = { + "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" +} + +local security_list = { "auto", "aes-128-gcm", "chacha20-poly1305" } + +local header_type_list = { + "none", "srtp", "utp", "wechat-video", "dtls", "wireguard", "dns" +} + +local xray_version = api.get_app_version("xray") + +o = s:option(ListValue, "protocol", translate("Protocol")) +o:value("socks", translate("Socks")) +o:value("http", translate("HTTP")) +o:value("vmess", translate("Vmess")) +o:value("vless", translate("VLESS")) +o:value("shadowsocks", translate("Shadowsocks")) +o:value("trojan", translate("Trojan")) +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, ">=", "1.8.12") then + o:value("_balancing", translate("Balancing")) +end +o:value("_shunt", translate("Shunt")) +o:value("_iface", translate("Custom Interface")) +function o.custom_cfgvalue(self, section) + if arg_select_proto ~= "" then + return arg_select_proto + else + return m:get(section, self.config_option) + end +end + +local load_balancing_options = s1.val["protocol"] == "_balancing" or arg_select_proto == "_balancing" +local load_shunt_options = s1.val["protocol"] == "_shunt" or arg_select_proto == "_shunt" +local load_iface_options = s1.val["protocol"] == "_iface" or arg_select_proto == "_iface" +local load_normal_options = true +if load_balancing_options or load_shunt_options or load_iface_options then + load_normal_options = nil +end +if not arg_select_proto:find("_") then + load_normal_options = true +end + +local netdev_list = api.get_network_devices() +local node_list = api.get_node_list() +local fallback_list = {} +local is_balancer = nil +for k, e in ipairs(node_list.balancing_list or {}) do + if e.id ~= arg[1] then + fallback_list[#fallback_list + 1] = { + id = e["id"], + remark = e["remark"], + group = e["group"], + fallback = e.o["fallback_node"], + } + else + is_balancer = true + end +end + +if load_balancing_options then -- [[ Load balancing Start ]] + o = s:option(ListValue, "node_add_mode", translate("Node Addition Method")) + o:depends({ protocol = "_balancing" }) + o.default = "manual" + o:value("manual", translate("Manual")) + o:value("batch", translate("Batch")) + + o = s:option(MultiValue, "balancing_node", translate("Load balancing node list"), translate("Load balancing node list, document")) + o:depends({ node_add_mode = "manual" }) + o.widget = "checkbox" + o.template = m:template_path("/cbi/nodes_multivalue") + o.group = {} + for k1, v1 in pairs(node_list) do + if k1 == "socks_list" or k1 == "normal_list" then + for i, v in ipairs(v1) do + o:value(v.id, v.remark) + o.group[#o.group+1] = v.group or "" + end + end + end + -- 读取旧 DynamicList + function o.custom_cfgvalue(self, section) + return table.concat(m:get(section, "balancing_node") or {}, " ") + end + -- 写入保持 DynamicList + function o.custom_write(self, section, value) + local old = m:get(section, "balancing_node") or {} + local new, set = {}, {} + for v in value:gmatch("%S+") do + new[#new + 1] = v + set[v] = 1 + end + for _, v in ipairs(old) do + if not set[v] then + m:set(section, "balancing_node", new) + return + end + set[v] = nil + end + for _ in pairs(set) do + m:set(section, "balancing_node", new) + return + end + end + + o = s:option(MultiValue, "node_group", translate("Select Group")) + o:depends({ node_add_mode = "batch" }) + o.widget = "checkbox" + o:value("default", translate("default")) + for k, v in pairs(groups) do + o:value(api.UrlEncode(k), k) + end + + o = s:option(Value, "node_match_rule", translate("Node Matching Rules")) + o:depends({ node_add_mode = "batch" }) + local descrStr = "Example: ^A && B && !C && D$
" + descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" + descrStr = descrStr .. "Conditions are joined by && (AND), and their order does not affect the result.
" + descrStr = descrStr .. "Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" + descrStr = descrStr .. "Example: A && B || C && D means (A AND B) OR (C AND D)." + o.description = translate(descrStr) + + o = s:option(ListValue, "balancingStrategy", translate("Balancing Strategy")) + o:depends({ protocol = "_balancing" }) + o:value("random") + o:value("roundRobin") + o:value("leastPing") + o:value("leastLoad") + o.default = "random" + + -- Fallback Node + o = s:option(ListValue, "fallback_node", translate("Fallback Node")) + o.group = {"",""} + o:value("", translate("Close(Not use)")) + o:value("_direct", translate("Direct Connection")) + o:depends({ protocol = "_balancing" }) + o.template = m:template_path("/cbi/nodes_listvalue") + -- 最大 fallback 套娃层数 + local MAX_FALLBACK_DEPTH = 3 + -- 检查是否会形成回环 + local function will_loop(start_id, target_id, depth) + depth = depth or 0 + -- 超过最大深度后停止递归 + if depth >= MAX_FALLBACK_DEPTH then + return false + end + for _, v in ipairs(fallback_list) do + if v.id == target_id then + local fb = v.fallback + -- 没有 fallback + if not fb or fb == "" or fb == "_direct" then + return false + end + -- 检测到回环 + if fb == start_id then + return true + end + -- 继续递归检查 + return will_loop(start_id, fb, depth + 1) + end + end + return false + end + -- 获取 fallback 链深度 + local function get_fallback_depth(id, depth) + depth = depth or 0 + if depth >= MAX_FALLBACK_DEPTH then + return depth + end + for _, v in ipairs(fallback_list) do + if v.id == id then + local fb = v.fallback + if not fb or fb == "" or fb == "_direct" then + return depth + end + return get_fallback_depth(fb, depth + 1) + end + end + return depth + end + for _, v in ipairs(fallback_list) do + local depth = get_fallback_depth(v.id) + -- 超过最大套娃层数后,不允许继续选择 balancer + if depth < MAX_FALLBACK_DEPTH + and not will_loop(arg[1], v.id) + then + o:value(v.id, v.remark) + o.group[#o.group + 1] = (v.group and v.group ~= "") and v.group or translate("default") + end + end + for k1, v1 in pairs(node_list) do + if k1 == "socks_list" or k1 == "normal_list" or k1 == "urltest_list" then + for i, v in ipairs(v1) do + o:value(v.id, v.remark) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + end + end + + -- 探测地址 + o = s:option(Flag, "useCustomProbeUrl", translate("Use Custom Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL.")) + o:depends({ protocol = "_balancing" }) + + o = s:option(Value, "probeUrl", translate("Probe URL")) + o:depends({ useCustomProbeUrl = true }) + o:value("https://cp.cloudflare.com/", "Cloudflare") + o:value("https://www.gstatic.com/generate_204", "Gstatic") + o:value("https://www.google.com/generate_204", "Google") + o:value("https://www.youtube.com/generate_204", "YouTube") + o:value("https://connect.rom.miui.com/generate_204", "MIUI (CN)") + o:value("https://connectivitycheck.platform.hicloud.com/generate_204", "HiCloud (CN)") + o:value("https://wifi.vivo.com.cn/generate_204", "VIVO (CN)") + o.default = o.keylist[3] + o.description = translate("The URL used to detect the connection status.") + + -- 探测间隔 + o = s:option(Value, "probeInterval", translate("Probe Interval")) + o:depends({ protocol = "_balancing" }) + o.default = "1m" + o.placeholder = "1m" + o.description = translate("The interval between initiating probes.") .. "
" .. + translate("The time format is numbers + units, such as '10s', '2h45m', and the supported time units are s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "
" .. + translate("When the unit is not filled in, it defaults to seconds.") + + o = s:option(Value, "expected", translate("Preferred Node Count")) + o:depends({ balancingStrategy = "leastLoad" }) + o.datatype = "uinteger" + o.default = "2" + o.placeholder = "2" + o.description = translate("The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them.") + + o = s:option(Value, "tolerance", translate("Failure Tolerance (%)")) + o:depends({ balancingStrategy = "leastLoad" }) + o.datatype = "uinteger" + o.default = "10" + o.placeholder = "10" + o.description = translate("The maximum acceptable speed test failure rate. For example, 1 means allowing a 1% failure rate.") +end -- [[ 负载均衡 End ]] + +if load_iface_options then -- [[ 自定义接口 Start ]] + o = s:option(Value, "iface", translate("Interface")) + o:depends({ protocol = "_iface" }) + for _, d in ipairs(netdev_list) do + o:value(d.name, d.label) + end +end -- [[ 自定义接口 End ]] + + +if load_normal_options then + +o = s:option(Value, "address", translate("Address (Support Domain Name)")) + +o = s:option(Value, "port", translate("Port")) +o.datatype = "port" + +o = s:option(Value, "uuid", translate("ID")) +o.password = true +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) + +o = s:option(Value, "username", translate("Username")) +o:depends({ protocol = "http" }) +o:depends({ protocol = "socks" }) + +o = s:option(Value, "password", translate("Password")) +o.password = true +o:depends({ protocol = "http" }) +o:depends({ protocol = "socks" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "trojan" }) + +o = s:option(ListValue, "security", translate("Encrypt Method")) +for a, t in ipairs(security_list) do o:value(t) end +o:depends({ protocol = "vmess" }) + +o = s:option(Value, "encryption", translate("Encrypt Method") .. " (encryption)") +o.default = "none" +o.placeholder = "none" +o:depends({ protocol = "vless" }) +o.validate = function(self, value) + value = api.trim(value) + return (value == "" and "none" or value) +end + +o = s:option(ListValue, "ss_method", translate("Encrypt Method")) +o.rewrite_option = "method" +for a, t in ipairs(ss_method_list) do o:value(t) end +o:depends({ protocol = "shadowsocks" }) + +o = s:option(ListValue, "flow", translate("flow")) +o.default = "" +o:value("", translate("Disable")) +o:value("xtls-rprx-vision") +o:value("xtls-rprx-vision-udp443") +o:depends({ protocol = "vless" }) + +---- [[hysteria2]] +o = s:option(Value, "hysteria2_hop", translate("Port hopping range")) +o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).") +o:depends({ protocol = "hysteria2", hysteria2_realms = false }) + +o = s:option(Value, "hysteria2_hop_interval", translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5.")) +o.datatype = "or(uinteger,portrange)" +o.placeholder = "30" +o.default = "30" +o:depends({ protocol = "hysteria2", hysteria2_realms = false }) + +o = s:option(Flag, "hysteria2_realms", translate("Realms")) +o.default = "0" +if api.compare_versions(xray_version, ">", "26.5.9") then + o:depends({ protocol = "hysteria2"}) +else + o:depends({ protocol = "__hide"}) +end + +o = s:option(Value, "hysteria2_realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") +o:depends({ hysteria2_realms = "1" }) +o.validate = function(self, value) + value = api.trim(value) + local realm = api.parse_realm_uri(value) + if realm then return value end + return nil, translate("Invalid Realm URL.") +end + +o = s:option(DynamicList, "hysteria2_realm_stun", translate("Realm STUN")) +o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } +o:depends({ hysteria2_realms = "1" }) + +o = s:option(Value, "hysteria2_auth_password", translate("Auth Password")) +o.password = true +o:depends({ protocol = "hysteria2"}) + +o = s:option(ListValue, "hysteria2_obfs_type", translate("Obfs Type")) +o:value("", translate("Disable")) +o:value("salamander") +o:value("gecko") +o:depends({ protocol = "hysteria2" }) + +o = s:option(Value, "hysteria2_obfs_password", translate("Obfs Password")) +o:depends({ hysteria2_obfs_type = "salamander" }) +o:depends({ hysteria2_obfs_type = "gecko" }) + +o = s:option(Value, "hysteria2_obfs_MinPacketSize", translate("Gecko Packet Size (min)")) +o.datatype = "uinteger" +o.placeholder = "512" +o.default = "512" +o:depends({ hysteria2_obfs_type = "gecko" }) + +o = s:option(Value, "hysteria2_obfs_MaxPacketSize", translate("Gecko Packet Size (max)")) +o.datatype = "uinteger" +o.placeholder = "1200" +o.default = "1200" +o:depends({ hysteria2_obfs_type = "gecko" }) + +o = s:option(Value, "hysteria2_up_mbps", translate("Max upload Mbps")) +o:depends({ protocol = "hysteria2" }) + +o = s:option(Value, "hysteria2_down_mbps", translate("Max download Mbps")) +o:depends({ protocol = "hysteria2" }) + +o = s:option(Value, "hysteria2_idle_timeout", translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)") +o.datatype = "range(4,120)" +o:depends({ protocol = "hysteria2"}) + +o = s:option(Value, "hysteria2_keep_alive_period", translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)") +o.datatype = "range(2,60)" +o:depends({ protocol = "hysteria2"}) + +o = s:option(Flag, "hysteria2_disable_mtu_discovery", translate("Disable MTU detection")) +o.default = "0" +o:depends({ protocol = "hysteria2"}) +---- [[hysteria2 end]] + +o = s:option(Flag, "tls", translate("TLS")) +o.default = 0 +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "trojan" }) +o:depends({ protocol = "shadowsocks" }) + +o = s:option(Flag, "reality", translate("REALITY"), translate("Only recommend to use with VLESS-TCP-XTLS-Vision.")) +o.default = 0 +o:depends({ tls = true, transport = "raw" }) +o:depends({ tls = true, transport = "ws" }) +o:depends({ tls = true, transport = "grpc" }) +o:depends({ tls = true, transport = "httpupgrade" }) +o:depends({ tls = true, transport = "xhttp" }) + +o = s:option(ListValue, "alpn", translate("alpn")) +o.default = "default" +o:value("default", translate("Default")) +o:value("h3") +o:value("h2") +o:value("h3,h2") +o:value("http/1.1") +o:value("h2,http/1.1") +o:value("h3,h2,http/1.1") +o:depends({ tls = true, reality = false }) + +-- o = s:option(Value, "minversion", translate("minversion")) +-- o.default = "1.3" +-- o:value("1.3") +-- o:depends({ tls = true }) + +o = s:option(Value, "tls_serverName", "SNI " .. translate("Domain")) +o:depends({ tls = true }) +o:depends({ protocol = "hysteria2" }) + +o = s:option(Value, "tls_pinSHA256", translate("TLS Chain Fingerprint (SHA256)")) +o:depends({ tls = true, reality = false }) +o:depends({ protocol = "hysteria2" }) +o.description = translate("Once set, connects only when the server’s chain fingerprint matches.") .. + string.format("%s", "→ " .. 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 = s:option(Flag, "tls_certificate", translate("TLS Certificate (PEM)")) +o.default = "0" +o:depends({ tls = true, reality = false }) +o:depends({ protocol = "hysteria2" }) + +o = s:option(TextValue, "tls_certificate_pem", " ", translate("Full certificate (chain), PEM format.")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ tls_certificate = true }) +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") + return value +end + +o = s:option(Flag, "ech", translate("ECH")) +o.default = "0" +o:depends({ tls = true, reality = false }) +o:depends({ protocol = "hysteria2", hysteria2_realms = false }) + +o = s:option(TextValue, "ech_config", translate("ECH Config")) +o.default = "" +o.rows = 5 +o.wrap = "soft" +o:depends({ ech = true }) +o.validate = function(self, value) + return api.trim(value:gsub("[\r\n]", "")) +end + +-- [[ REALITY部分 ]] -- +o = s:option(Value, "reality_publicKey", translate("Public Key")) +o:depends({ tls = true, reality = true }) + +o = s:option(Value, "reality_shortId", translate("Short Id")) +o:depends({ tls = true, reality = true }) + +o = s:option(Value, "reality_spiderX", translate("Spider X")) +o.placeholder = "/" +o:depends({ tls = true, reality = true }) + +o = s:option(Flag, "utls", translate("uTLS")) +o.default = "0" +o:depends({ tls = true, reality = false }) + +o = s:option(ListValue, "fingerprint", translate("Finger Print")) +o:value("chrome") +o:value("firefox") +o:value("edge") +o:value("safari") +o:value("360") +o:value("qq") +o:value("ios") +o:value("android") +o:value("random") +o:value("randomized") +o:value("unsafe") +o.default = "chrome" +o:depends({ tls = true, utls = true }) +o:depends({ tls = true, reality = true }) + +o = s:option(Value, "cipherSuites", translate("Cipher Suites"), '***' .. " " .. translate("Configures the list of supported cipher suites, separated by :")) +o:depends({ tls = true, reality = false }) + +o = s:option(Flag, "use_mldsa65Verify", translate("ML-DSA-65")) +o.default = "0" +o:depends({ tls = true, reality = true }) + +o = s:option(TextValue, "reality_mldsa65Verify", "ML-DSA-65 " .. translate("Public key")) +o.default = "" +o.rows = 5 +o.wrap = "soft" +o:depends({ use_mldsa65Verify = true }) +o.validate = function(self, value) + return api.trim(value:gsub("[\r\n]", "")) +end + +o = s:option(ListValue, "transport", translate("Transport")) +o:value("raw", "RAW (TCP)") +o:value("mkcp", "mKCP") +o:value("ws", "WebSocket") +o:value("grpc", "gRPC") +o:value("httpupgrade", "HttpUpgrade") +o:value("xhttp", "XHTTP") +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "trojan" }) + +o = s:option(Value, "wireguard_public_key", translate("Public Key")) +o:depends({ protocol = "wireguard" }) + +o = s:option(Value, "wireguard_secret_key", translate("Private Key")) +o:depends({ protocol = "wireguard" }) + +o = s:option(Value, "wireguard_preSharedKey", translate("Pre shared key")) +o:depends({ protocol = "wireguard" }) + +o = s:option(DynamicList, "wireguard_local_address", translate("Local Address")) +o:depends({ protocol = "wireguard" }) + +o = s:option(Value, "wireguard_mtu", translate("MTU")) +o.default = "1420" +o:depends({ protocol = "wireguard" }) + +if api.compare_versions(xray_version, ">=", "1.8.0") then + o = s:option(Value, "wireguard_reserved", translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings.")) + o:depends({ protocol = "wireguard" }) +end + +o = s:option(Value, "wireguard_keepAlive", translate("Keep Alive")) +o.default = "0" +o:depends({ protocol = "wireguard" }) + +-- [[ RAW部分 ]]-- + +-- TCP伪装 +o = s:option(ListValue, "tcp_guise", translate("Camouflage Type")) +o:value("none", "none") +o:value("http", "http") +o:depends({ transport = "raw" }) + +-- HTTP域名 +o = s:option(DynamicList, "tcp_guise_http_host", translate("HTTP Host")) +o:depends({ tcp_guise = "http" }) + +-- HTTP路径 +o = s:option(DynamicList, "tcp_guise_http_path", translate("HTTP Path")) +o.placeholder = "/" +o:depends({ tcp_guise = "http" }) + +-- [[ mKCP部分 ]]-- + +o = s:option(ListValue, "mkcp_guise", translate("Camouflage Type"), translate('
none: default, no masquerade, data sent is packets with no characteristics.
srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).
utp: packets disguised as uTP will be recognized as bittorrent downloaded data.
wechat-video: packets disguised as WeChat video calls.
dtls: disguised as DTLS 1.2 packet.
wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)
dns: Disguising traffic as DNS requests.')) +for a, t in ipairs(header_type_list) do o:value(t) end +o:depends({ transport = "mkcp" }) + +o = s:option(Value, "mkcp_domain", translate("Camouflage Domain"), translate("Use it together with the DNS disguised type. You can fill in any domain.")) +o:depends({ mkcp_guise = "dns" }) + +o = s:option(Value, "mkcp_mtu", translate("KCP MTU")) +o.datatype = "uinteger" +o.default = 1350 +o:depends({ transport = "mkcp" }) + +o = s:option(Value, "mkcp_seed", translate("KCP Seed")) +o:depends({ transport = "mkcp" }) + +-- [[ WebSocket部分 ]]-- +o = s:option(Value, "ws_host", translate("WebSocket Host")) +o:depends({ transport = "ws" }) + +o = s:option(Value, "ws_path", translate("WebSocket Path")) +o.placeholder = "/" +o:depends({ transport = "ws" }) + +o = s:option(Value, "ws_heartbeatPeriod", translate("HeartbeatPeriod(second)")) +o.datatype = "integer" +o:depends({ transport = "ws" }) + +-- [[ gRPC部分 ]]-- +o = s:option(Value, "grpc_serviceName", "ServiceName") +o:depends({ transport = "grpc" }) + +o = s:option(ListValue, "grpc_mode", "gRPC " .. translate("Transfer mode")) +o:value("gun") +o:value("multi") +o:depends({ transport = "grpc" }) + +o = s:option(Flag, "grpc_health_check", translate("Health check")) +o:depends({ transport = "grpc" }) + +o = s:option(Value, "grpc_idle_timeout", translate("Idle timeout")) +o.default = "10" +o:depends({ grpc_health_check = true }) + +o = s:option(Value, "grpc_health_check_timeout", translate("Health check timeout")) +o.default = "20" +o:depends({ grpc_health_check = true }) + +o = s:option(Flag, "grpc_permit_without_stream", translate("Permit without stream")) +o.default = "0" +o:depends({ grpc_health_check = true }) + +o = s:option(Value, "grpc_initial_windows_size", translate("Initial Windows Size")) +o.default = "0" +o:depends({ transport = "grpc" }) + +-- [[ HttpUpgrade部分 ]]-- +o = s:option(Value, "httpupgrade_host", translate("HttpUpgrade Host")) +o:depends({ transport = "httpupgrade" }) + +o = s:option(Value, "httpupgrade_path", translate("HttpUpgrade Path")) +o.placeholder = "/" +o:depends({ transport = "httpupgrade" }) + +-- [[ XHTTP部分 ]]-- +o = s:option(ListValue, "xhttp_mode", "XHTTP " .. translate("Mode")) +o:depends({ transport = "xhttp" }) +o.default = "auto" +o:value("auto") +o:value("packet-up") +o:value("stream-up") +o:value("stream-one") + +o = s:option(Value, "xhttp_host", translate("XHTTP Host")) +o:depends({ transport = "xhttp" }) + +o = s:option(Value, "xhttp_path", translate("XHTTP Path")) +o.placeholder = "/" +o:depends({ transport = "xhttp" }) + +o = s:option(Flag, "use_xhttp_extra", translate("XHTTP Extra")) +o.default = "0" +o:depends({ transport = "xhttp" }) + +o = s:option(TextValue, "xhttp_extra", " ", translate("An XHttpObject in JSON format, used for sharing.")) +o:depends({ use_xhttp_extra = true }) +o.rows = 10 +o.wrap = "off" +o.datatype = "json" +local o_validate = o.validate +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n") + local v = o_validate(self, value) + if v then return v end + return nil, "XHTTP Extra " .. translate("Must be JSON text!") +end +o.custom_cfgvalue = function(self, section, value) + local raw = m:get(section, "xhttp_extra") + if raw then + return api.base64Decode(raw) + end +end +o.custom_write = function(self, section, value) + m:set(section, "xhttp_extra", api.base64Encode(value) or "") + local success, data = pcall(api.jsonc.parse, value) + if success and data then + local address = (data.extra and data.extra.downloadSettings and data.extra.downloadSettings.address) + or (data.downloadSettings and data.downloadSettings.address) + if address and address ~= "" then + address = address:gsub("^%[", ""):gsub("%]$", "") + m:set(section, "download_address", address) + else + m:del(section, "download_address") + end + else + m:del(section, "download_address") + end +end +o.custom_remove = function(self, section, value) + m:del(section, "xhttp_extra") + m:del(section, "download_address") +end + +-- [[ User-Agent ]]-- +o = s:option(Value, "user_agent", translate("User-Agent")) +o.default = "" +o:value("", translate("default")) +o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36", "chrome") +o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0", "firefox") +o:value("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15", "safari") +o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70", "edge") +o:value("Go-http-client/1.1", "golang") +o:value("curl/7.68.0", "curl") +o:depends({ tcp_guise = "http" }) +o:depends({ transport = "ws" }) +o:depends({ transport = "httpupgrade" }) +o:depends({ transport = "xhttp" }) +o:depends({ transport = "grpc" }) + +-- [[ Mux.Cool ]]-- +o = s:option(Flag, "mux", "Mux", translate("Enable Mux.Cool")) +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless", transport = "raw" }) +o:depends({ protocol = "vless", transport = "ws" }) +o:depends({ protocol = "vless", transport = "grpc" }) +o:depends({ protocol = "vless", transport = "httpupgrade" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "trojan" }) + +o = s:option(Value, "mux_concurrency", translate("Mux concurrency")) +o.default = -1 +o:depends({ mux = true }) + +o = s:option(Value, "xudp_concurrency", translate("XUDP Mux concurrency")) +o.default = 8 +o:depends({ mux = true }) + +--[[FinalMask]] +o = s:option(Flag, "use_finalmask", "FinalMask") +o.default = "0" +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "trojan" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "wireguard" }) +o:depends({ protocol = "hysteria2", hysteria2_realms = false }) + +o = s:option(TextValue, "finalmask", " ") +o:depends({ use_finalmask = true }) +o.rows = 10 +o.wrap = "off" +o.description = translate("An FinalMaskObject in JSON format, used for sharing.") .. "
" .. + translate("Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related settings.") +o.datatype = "json" +local o_validate = o.validate +o.validate = function(self, value) + value = api.trim(value):gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n") + local v = o_validate(self, value) + if v then return v end + return nil, "FinalMask " .. translate("Must be JSON text!") +end +o.custom_cfgvalue = function(self, section, value) + local raw = m:get(section, "finalmask") + if raw then + return api.base64Decode(raw) + end +end +o.custom_write = function(self, section, value) + m:set(section, "finalmask", api.base64Encode(value) or "") +end + +--[[Fast Open]] +o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"), translate("Need node support required")) +o.default = 0 + +--[[tcpMptcp]] +o = s:option(Flag, "tcpMptcp", "tcpMptcp", translate("Enable Multipath TCP, need to be enabled in both server and client configuration.")) +o.default = 0 + +o = s:option(ListValue, "domain_resolver", translate("Domain DNS Resolve")) +o.description = translate("If the node address is a domain name, this DNS will be used for resolution.") .. "
" .. string.format('%s', + translate("Note: For node-specific DNS only. Keep Auto to avoid extra overhead.")) +o:value("", translate("Auto")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("https", "DoH") + +o = s:option(Value, "domain_resolver_dns", "DNS") +o.datatype = "or(ipaddr,ipaddrport)" +o:value("114.114.114.114") +o:value("223.5.5.5:53") +o.default = o.keylist[1] +o:depends({ domain_resolver = "tcp" }) +o:depends({ domain_resolver = "udp" }) + +o = s:option(Value, "domain_resolver_dns_https", "DNS") +o:value("https://120.53.53.53/dns-query", "DNSPod") +o:value("https://223.5.5.5/dns-query", "AliDNS") +o.default = o.keylist[1] +o:depends({ domain_resolver = "https" }) + +o = s:option(ListValue, "domain_strategy", translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) +o.default = "" +o:value("", translate("Auto")) +o:value("UseIPv4v6", translate("Prefer IPv4")) +o:value("UseIPv6v4", translate("Prefer IPv6")) +o:value("UseIPv4", translate("IPv4 Only")) +o:value("UseIPv6", translate("IPv6 Only")) + +o = s:option(Flag, "happy_eyeballs", translate("Enable Happy Eyeballs"), translate("Attempts IPv4 and IPv6 simultaneously; automatically uses the faster connection.")) +o.default = 0 + +local protocols = s.fields["protocol"].keylist +if #protocols > 0 then + for i, v in ipairs(protocols) do + if not v:find("^_") then + local depends_condition = { protocol = v } + if v == "hysteria2" then + depends_condition["hysteria2_realms"] = false + end + s.fields["address"]:depends(depends_condition) + s.fields["port"]:depends(depends_condition) + s.fields["domain_resolver"]:depends(depends_condition) + s.fields["happy_eyeballs"]:depends(depends_condition) + + local strategy_depends = api.clone(depends_condition) + strategy_depends["happy_eyeballs"] = false + s.fields["domain_strategy"]:depends(strategy_depends) + + if v ~= "hysteria2" then + s.fields["tcp_fast_open"]:depends({ protocol = v }) + s.fields["tcpMptcp"]:depends({ protocol = v }) + end + end + end +end +end +-- [[ Normal single node End ]] + +if not load_shunt_options then + o = s:option(ListValue, "chain_proxy", translate("Chain Proxy")) + o:value("", translate("Close(Not use)")) + if not (load_iface_options or load_balancing_options) then + -- Special node cannot be use pre-proxy. + o:value("1", translate("Preproxy Node")) + o:value("3", translate("Outbound Interface")) + end + o:value("2", translate("Landing Node")) + + o1 = s:option(ListValue, "preproxy_node", translate("Preproxy Node"), translate("Only support a layer of proxy.")) + o1:depends({ chain_proxy = "1", hysteria2_realms = false }) + o1.template = m:template_path("/cbi/nodes_listvalue") + o1.group = {} + + o3 = s:option(Value, "outbound_iface", translate("Outbound Interface")) + o3:depends({ chain_proxy = "3" }) + o3:value("", translate("All")) + for _, d in ipairs(netdev_list) do + o3:value(d.name, d.label) + end + + o2 = s:option(ListValue, "to_node", translate("Landing Node"), translate("Only support a layer of proxy.")) + o2:depends({ chain_proxy = "2", hysteria2_realms = false }) + o2.template = m:template_path("/cbi/nodes_listvalue") + o2.group = {} + + for k1, v1 in pairs(node_list) do + if k1 ~= "shunt_list" and k1 ~= "iface_list" then + for i, v in ipairs(v1) do + if v.id ~= arg[1] then + o1:value(v.id, v.remark) + o1.group[#o1.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + if k1 == "normal_list" then + -- Landing Node not support use special node. + o2:value(v.id, v.remark) + o2.group[#o2.group+1] = (v.group and v.group ~= "") and v.group or translate("default") + end + end + end + end + end +end + +api.luci_types(s1, s) + +if load_shunt_options then + local current_node = m:get(arg[1]) or {} + local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua") + setfenv(shunt_lua, getfenv(1))(m, s1, { + node_id = arg[1], + node = current_node, + node_list = node_list, + }) +end diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/3_ss-rust.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/3_ss-rust.lua new file mode 100644 index 00000000..1c7562dc --- /dev/null +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/3_ss-rust.lua @@ -0,0 +1,72 @@ +if not api.is_finded("sslocal") then + return +end + +-- [[ Shadowsocks Rust ]] +local m, s1 = ... +local type_name = "SS-Rust" + +s1.fields["type"]:value(type_name, "Shadowsocks Rust") + +if s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "ssrust_" + +local ssrust_encrypt_method_list = { + "none", "plain", + "aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", + "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" +} + +o = s:option(ListValue, "del_protocol") --始终隐藏,用于删除 protocol +o:depends({ __hide = "1" }) +o.rewrite_option = "protocol" + +o = s:option(Value, "address", translate("Address (Support Domain Name)")) + +o = s:option(Value, "port", translate("Port")) +o.datatype = "port" + +o = s:option(Value, "password", translate("Password")) +o.password = true + +o = s:option(Value, "ss_method", translate("Encrypt Method")) +for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end + +o = s:option(Value, "timeout", translate("Connection Timeout")) +o.datatype = "uinteger" +o.default = 300 + +o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"), translate("Need node support required")) +o.default = 0 + +o = s:option(Flag, "plugin_enabled", translate("plugin")) +o.default = 0 + +o = s:option(Value, "plugin", "SIP003 " .. translate("plugin"), translate("Supports custom SIP003 plugins, Make sure the plugin is installed.")) +o.default = "none" +o:value("none", translate("none")) +if api.is_finded("xray-plugin") then o:value("xray-plugin") end +if api.is_finded("v2ray-plugin") then o:value("v2ray-plugin") end +if api.is_finded("obfs-local") then o:value("obfs-local") end +if api.is_finded("shadow-tls") then o:value("shadow-tls") end +o:depends({ plugin_enabled = true }) +o.validate = function(self, value, t) + if value and value ~= "" and value ~= "none" then + if not api.is_finded(value) then + return nil, value .. ": " .. translate("Can't find this file!") + else + return value + end + end + return nil +end + +o = s:option(Value, "plugin_opts", translate("opts")) +o:depends({ plugin_enabled = true }) + +api.luci_types(s1, s) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ssr.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/4_ssr.lua similarity index 53% rename from luci-app-passwall/luasrc/model/cbi/passwall/client/type/ssr.lua rename to luci-app-passwall/luasrc/model/cbi/passwall/client/type/4_ssr.lua index 3001f626..e86e470b 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ssr.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/4_ssr.lua @@ -1,70 +1,66 @@ -local m, s = ... - -if not api.is_finded("ssr-local") and not api.is_finded("ssr-redir")then - return -end - -type_name = "SSR" - --- [[ ShadowsocksR Libev ]] - -s.fields["type"]:value(type_name, "ShadowsocksR Libev") - -if s.val["type"] ~= type_name then - return -end - -local option_prefix = "ssr_" - -local function _n(name) - return option_prefix .. name -end - -local ssr_encrypt_method_list = { - "none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb", - "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", - "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", - "cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20", - "chacha20-ietf" -} - -local ssr_protocol_list = { - "origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple", - "auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5", - "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", - "auth_chain_d", "auth_chain_e", "auth_chain_f" -} -local ssr_obfs_list = { - "plain", "http_simple", "http_post", "random_head", "tls_simple", - "tls1.0_session_auth", "tls1.2_ticket_auth" -} - -o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) - -o = s:option(Value, _n("port"), translate("Port")) -o.datatype = "port" - -o = s:option(Value, _n("password"), translate("Password")) -o.password = true - -o = s:option(ListValue, _n("method"), translate("Encrypt Method")) -for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end - -o = s:option(ListValue, _n("protocol"), translate("Protocol")) -for a, t in ipairs(ssr_protocol_list) do o:value(t) end - -o = s:option(Value, _n("protocol_param"), translate("Protocol_param")) - -o = s:option(ListValue, _n("obfs"), translate("Obfs")) -for a, t in ipairs(ssr_obfs_list) do o:value(t) end - -o = s:option(Value, _n("obfs_param"), translate("Obfs_param")) - -o = s:option(Value, _n("timeout"), translate("Connection Timeout")) -o.datatype = "uinteger" -o.default = 300 - -o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required")) -o.default = 0 - -api.luci_types(arg[1], m, s, type_name, option_prefix) +if not api.is_finded("ssr-local") and not api.is_finded("ssr-redir")then + return +end + +-- [[ ShadowsocksR Libev ]] +local m, s1 = ... +local type_name = "SSR" + +s1.fields["type"]:value(type_name, "ShadowsocksR Libev") + +if s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "ssr_" + +local ssr_encrypt_method_list = { + "none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb", + "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", + "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", + "cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20", + "chacha20-ietf" +} + +local ssr_protocol_list = { + "origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple", + "auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5", + "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", + "auth_chain_d", "auth_chain_e", "auth_chain_f" +} +local ssr_obfs_list = { + "plain", "http_simple", "http_post", "random_head", "tls_simple", + "tls1.0_session_auth", "tls1.2_ticket_auth" +} + +o = s:option(Value, "address", translate("Address (Support Domain Name)")) + +o = s:option(Value, "port", translate("Port")) +o.datatype = "port" + +o = s:option(Value, "password", translate("Password")) +o.password = true + +o = s:option(ListValue, "method", translate("Encrypt Method")) +for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end + +o = s:option(ListValue, "protocol", translate("Protocol")) +for a, t in ipairs(ssr_protocol_list) do o:value(t) end + +o = s:option(Value, "protocol_param", translate("Protocol_param")) + +o = s:option(ListValue, "obfs", translate("Obfs")) +for a, t in ipairs(ssr_obfs_list) do o:value(t) end + +o = s:option(Value, "obfs_param", translate("Obfs_param")) + +o = s:option(Value, "timeout", translate("Connection Timeout")) +o.datatype = "uinteger" +o.default = 300 + +o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open"), translate("Need node support required")) +o.default = 0 + +api.luci_types(s1, s) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/5_hysteria2.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/5_hysteria2.lua new file mode 100644 index 00000000..481fc1f2 --- /dev/null +++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/5_hysteria2.lua @@ -0,0 +1,131 @@ +if not api.finded_com("hysteria") then + return +end + +-- [[ Hysteria2 ]] +local m, s1 = ... +local type_name = "Hysteria2" + +s1.fields["type"]:value(type_name, "Hysteria2") + +if s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "hysteria2_" + +local function _n(name) + return s.option_prefix .. name +end + +o = s:option(ListValue, "protocol", translate("Protocol")) +o:value("udp", "UDP") + +o = s:option(Value, "address", translate("Address (Support Domain Name)")) +o:depends({ realms = false }) + +o = s:option(Value, "port", translate("Port")) +o.datatype = "port" +o:depends({ realms = false }) + +o = s:option(Value, "hop", translate("Port hopping range")) +o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).") +o.rewrite_option = _n(o.option) +o:depends({ realms = false }) + +o = s:option(Value, "hop_interval", translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5.")) +o.datatype = "or(uinteger,portrange)" +o.placeholder = "30" +o.default = "30" +o.rewrite_option = _n(o.option) +o:depends({ realms = false }) + +o = s:option(Flag, "realms", translate("Realms")) +o.default = "0" +o.rewrite_option = _n(o.option) + +o = s:option(Value, "realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") +o.rewrite_option = _n(o.option) +o:depends({ realms = "1" }) +o.validate = function(self, value) + value = api.trim(value) + local realm = api.parse_realm_uri(value) + if realm then return value end + return nil, translate("Invalid Realm URL.") +end + +o = s:option(DynamicList, "realm_stun", translate("Realm STUN")) +o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } +o.rewrite_option = _n(o.option) +o:depends({ realms = "1" }) + +o = s:option(Value, "auth_password", translate("Auth Password")) +o.password = true +o.rewrite_option = _n(o.option) + +o = s:option(ListValue, "obfs_type", translate("Obfs Type")) +o:value("", translate("Disable")) +o:value("salamander") +o:value("gecko") +o.rewrite_option = _n(o.option) + +o = s:option(Value, "obfs_password", translate("Obfs Password")) +o.rewrite_option = _n(o.option) +o:depends({ obfs_type = "salamander" }) +o:depends({ obfs_type = "gecko" }) + +o = s:option(Value, "obfs_MinPacketSize", translate("Gecko Packet Size (min)")) +o.datatype = "uinteger" +o.placeholder = "512" +o.default = "512" +o:depends({ obfs_type = "gecko" }) +o.rewrite_option = _n(o.option) + +o = s:option(Value, "obfs_MaxPacketSize", translate("Gecko Packet Size (max)")) +o.datatype = "uinteger" +o.placeholder = "1200" +o.default = "1200" +o:depends({ obfs_type = "gecko" }) +o.rewrite_option = _n(o.option) + +o = s:option(Flag, "fast_open", translate("Fast Open")) +o.default = "0" + +o = s:option(Value, "tls_serverName", translate("Domain")) + +o = s:option(Flag, "tls_allowInsecure", translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped.")) +o.default = "0" + +o = s:option(Value, "tls_pinSHA256", translate("PinSHA256"),translate("Certificate fingerprint")) + +o = s:option(Value, "up_mbps", translate("Max upload Mbps")) +o.rewrite_option = _n(o.option) + +o = s:option(Value, "down_mbps", translate("Max download Mbps")) +o.rewrite_option = _n(o.option) + +o = s:option(Value, "recv_window", translate("QUIC stream receive window")) +o.rewrite_option = _n(o.option) + +o = s:option(Value, "recv_window_conn", translate("QUIC connection receive window")) +o.rewrite_option = _n(o.option) + +o = s:option(Value, "idle_timeout", translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)") +o.datatype = "range(4,120)" +o.rewrite_option = _n(o.option) + +o = s:option(Value, "keep_alive_period", translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)") +o.datatype = "range(2,60)" +o.rewrite_option = _n(o.option) + +o = s:option(Flag, "disable_mtu_discovery", translate("Disable MTU detection")) +o.default = "0" +o.rewrite_option = _n(o.option) + +o = s:option(Flag, "lazy_start", translate("Lazy Start")) +o.default = "0" +o.rewrite_option = _n(o.option) + +api.luci_types(s1, s) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/hysteria2.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/hysteria2.lua deleted file mode 100644 index f6af739d..00000000 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/hysteria2.lua +++ /dev/null @@ -1,131 +0,0 @@ -local m, s = ... - -if not api.finded_com("hysteria") then - return -end - -type_name = "Hysteria2" - --- [[ Hysteria2 ]] - -s.fields["type"]:value(type_name, "Hysteria2") - -if s.val["type"] ~= type_name then - return -end - -local option_prefix = "hysteria2_" - -local function _n(name) - return option_prefix .. name -end - -o = s:option(ListValue, _n("protocol"), translate("Protocol")) -o:value("udp", "UDP") - -o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) -o:depends({ [_n("realms")] = false }) - -o = s:option(Value, _n("port"), translate("Port")) -o.datatype = "port" -o:depends({ [_n("realms")] = false }) - -o = s:option(Value, _n("hop"), translate("Port hopping range")) -o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).") -o.rewrite_option = o.option -o:depends({ [_n("realms")] = false }) - -o = s:option(Value, _n("hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5.")) -o.datatype = "or(uinteger,portrange)" -o.placeholder = "30" -o.default = "30" -o.rewrite_option = o.option -o:depends({ [_n("realms")] = false }) - -o = s:option(Flag, _n("realms"), translate("Realms")) -o.default = "0" -o.rewrite_option = o.option - -o = s:option(Value, _n("realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") -o.rewrite_option = o.option -o:depends({ [_n("realms")] = "1" }) -o.validate = function(self, value) - value = api.trim(value) - local realm = api.parse_realm_uri(value) - if realm then return value end - return nil, translate("Invalid Realm URL.") -end - -o = s:option(DynamicList, _n("realm_stun"), translate("Realm STUN")) -o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } -o.rewrite_option = o.option -o:depends({ [_n("realms")] = "1" }) - -o = s:option(Value, _n("auth_password"), translate("Auth Password")) -o.password = true -o.rewrite_option = o.option - -o = s:option(ListValue, _n("obfs_type"), translate("Obfs Type")) -o:value("", translate("Disable")) -o:value("salamander") -o:value("gecko") -o.rewrite_option = o.option - -o = s:option(Value, _n("obfs_password"), translate("Obfs Password")) -o.rewrite_option = o.option -o:depends({ [_n("obfs_type")] = "salamander" }) -o:depends({ [_n("obfs_type")] = "gecko" }) - -o = s:option(Value, _n("obfs_MinPacketSize"), translate("Gecko Packet Size (min)")) -o.datatype = "uinteger" -o.placeholder = "512" -o.default = "512" -o:depends({ [_n("obfs_type")] = "gecko" }) -o.rewrite_option = o.option - -o = s:option(Value, _n("obfs_MaxPacketSize"), translate("Gecko Packet Size (max)")) -o.datatype = "uinteger" -o.placeholder = "1200" -o.default = "1200" -o:depends({ [_n("obfs_type")] = "gecko" }) -o.rewrite_option = o.option - -o = s:option(Flag, _n("fast_open"), translate("Fast Open")) -o.default = "0" - -o = s:option(Value, _n("tls_serverName"), translate("Domain")) - -o = s:option(Flag, _n("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped.")) -o.default = "0" - -o = s:option(Value, _n("tls_pinSHA256"), translate("PinSHA256"),translate("Certificate fingerprint")) - -o = s:option(Value, _n("up_mbps"), translate("Max upload Mbps")) -o.rewrite_option = o.option - -o = s:option(Value, _n("down_mbps"), translate("Max download Mbps")) -o.rewrite_option = o.option - -o = s:option(Value, _n("recv_window"), translate("QUIC stream receive window")) -o.rewrite_option = o.option - -o = s:option(Value, _n("recv_window_conn"), translate("QUIC connection receive window")) -o.rewrite_option = o.option - -o = s:option(Value, _n("idle_timeout"), translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)") -o.datatype = "range(4,120)" -o.rewrite_option = o.option - -o = s:option(Value, _n("keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)") -o.datatype = "range(2,60)" -o.rewrite_option = o.option - -o = s:option(Flag, _n("disable_mtu_discovery"), translate("Disable MTU detection")) -o.default = "0" -o.rewrite_option = o.option - -o = s:option(Flag, _n("lazy_start"), translate("Lazy Start")) -o.default = "0" -o.rewrite_option = o.option - -api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua deleted file mode 100644 index 02b23909..00000000 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ray.lua +++ /dev/null @@ -1,900 +0,0 @@ -local m, s = ... - -if not api.finded_com("xray") then - return -end - -local jsonc = api.jsonc - -type_name = "Xray" - --- [[ Xray ]] - -s.fields["type"]:value(type_name, "Xray") -if not s.fields["type"].default then - s.fields["type"].default = type_name -end - -if s.val["type"] ~= type_name then - return -end - -local option_prefix = "xray_" - -local function _n(name) - return option_prefix .. name -end - -local formvalue_proto = luci.http.formvalue(formvalue_key .. _n("protocol")) - -if formvalue_proto then s.val["protocol"] = formvalue_proto end - -local arg_select_proto = luci.http.formvalue("select_proto") or "" - -local ss_method_list = { - "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "chacha20-ietf-poly1305", "xchacha20-poly1305", "xchacha20-ietf-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" -} - -local security_list = { "auto", "aes-128-gcm", "chacha20-poly1305" } - -local header_type_list = { - "none", "srtp", "utp", "wechat-video", "dtls", "wireguard", "dns" -} - -local xray_version = api.get_app_version("xray") - -o = s:option(ListValue, _n("protocol"), translate("Protocol")) -o:value("socks", translate("Socks")) -o:value("http", translate("HTTP")) -o:value("vmess", translate("Vmess")) -o:value("vless", translate("VLESS")) -o:value("shadowsocks", translate("Shadowsocks")) -o:value("trojan", translate("Trojan")) -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, ">=", "1.8.12") then - o:value("_balancing", translate("Balancing")) -end -o:value("_shunt", translate("Shunt")) -o:value("_iface", translate("Custom Interface")) -function o.custom_cfgvalue(self, section) - if arg_select_proto ~= "" then - return arg_select_proto - else - return m:get(section, self.option:sub(1 + #option_prefix)) - end -end - -local load_balancing_options = s.val["protocol"] == "_balancing" or arg_select_proto == "_balancing" -local load_shunt_options = s.val["protocol"] == "_shunt" or arg_select_proto == "_shunt" -local load_iface_options = s.val["protocol"] == "_iface" or arg_select_proto == "_iface" -local load_normal_options = true -if load_balancing_options or load_shunt_options or load_iface_options then - load_normal_options = nil -end -if not arg_select_proto:find("_") then - load_normal_options = true -end - -local netdev_list = api.get_network_devices() -local node_list = api.get_node_list() -local fallback_list = {} -local is_balancer = nil -for k, e in ipairs(node_list.balancing_list or {}) do - if e.id ~= arg[1] then - fallback_list[#fallback_list + 1] = { - id = e["id"], - remark = e["remark"], - group = e["group"], - fallback = e.o["fallback_node"], - } - else - is_balancer = true - end -end - -if load_balancing_options then -- [[ Load balancing Start ]] - o = s:option(ListValue, _n("node_add_mode"), translate("Node Addition Method")) - o:depends({ [_n("protocol")] = "_balancing" }) - o.default = "manual" - o:value("manual", translate("Manual")) - o:value("batch", translate("Batch")) - - o = s:option(MultiValue, _n("balancing_node"), translate("Load balancing node list"), translate("Load balancing node list, document")) - o:depends({ [_n("node_add_mode")] = "manual" }) - o.widget = "checkbox" - o.template = m:template_path("/cbi/nodes_multivalue") - o.group = {} - for k1, v1 in pairs(node_list) do - if k1 == "socks_list" or k1 == "normal_list" then - for i, v in ipairs(v1) do - o:value(v.id, v.remark) - o.group[#o.group+1] = v.group or "" - end - end - end - -- 读取旧 DynamicList - function o.custom_cfgvalue(self, section) - return table.concat(m:get(section, "balancing_node") or {}, " ") - end - -- 写入保持 DynamicList - function o.custom_write(self, section, value) - local old = m:get(section, "balancing_node") or {} - local new, set = {}, {} - for v in value:gmatch("%S+") do - new[#new + 1] = v - set[v] = 1 - end - for _, v in ipairs(old) do - if not set[v] then - m:set(section, "balancing_node", new) - return - end - set[v] = nil - end - for _ in pairs(set) do - m:set(section, "balancing_node", new) - return - end - end - - o = s:option(MultiValue, _n("node_group"), translate("Select Group")) - o:depends({ [_n("node_add_mode")] = "batch" }) - o.widget = "checkbox" - o:value("default", translate("default")) - for k, v in pairs(groups) do - o:value(api.UrlEncode(k), k) - end - - o = s:option(Value, _n("node_match_rule"), translate("Node Matching Rules")) - o:depends({ [_n("node_add_mode")] = "batch" }) - local descrStr = "Example: ^A && B && !C && D$
" - descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" - descrStr = descrStr .. "Conditions are joined by && (AND), and their order does not affect the result.
" - descrStr = descrStr .. "Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" - descrStr = descrStr .. "Example: A && B || C && D means (A AND B) OR (C AND D)." - o.description = translate(descrStr) - - o = s:option(ListValue, _n("balancingStrategy"), translate("Balancing Strategy")) - o:depends({ [_n("protocol")] = "_balancing" }) - o:value("random") - o:value("roundRobin") - o:value("leastPing") - o:value("leastLoad") - o.default = "random" - - -- Fallback Node - o = s:option(ListValue, _n("fallback_node"), translate("Fallback Node")) - o.group = {"",""} - o:value("", translate("Close(Not use)")) - o:value("_direct", translate("Direct Connection")) - o:depends({ [_n("protocol")] = "_balancing" }) - o.template = m:template_path("/cbi/nodes_listvalue") - -- 最大 fallback 套娃层数 - local MAX_FALLBACK_DEPTH = 3 - -- 检查是否会形成回环 - local function will_loop(start_id, target_id, depth) - depth = depth or 0 - -- 超过最大深度后停止递归 - if depth >= MAX_FALLBACK_DEPTH then - return false - end - for _, v in ipairs(fallback_list) do - if v.id == target_id then - local fb = v.fallback - -- 没有 fallback - if not fb or fb == "" or fb == "_direct" then - return false - end - -- 检测到回环 - if fb == start_id then - return true - end - -- 继续递归检查 - return will_loop(start_id, fb, depth + 1) - end - end - return false - end - -- 获取 fallback 链深度 - local function get_fallback_depth(id, depth) - depth = depth or 0 - if depth >= MAX_FALLBACK_DEPTH then - return depth - end - for _, v in ipairs(fallback_list) do - if v.id == id then - local fb = v.fallback - if not fb or fb == "" or fb == "_direct" then - return depth - end - return get_fallback_depth(fb, depth + 1) - end - end - return depth - end - for _, v in ipairs(fallback_list) do - local depth = get_fallback_depth(v.id) - -- 超过最大套娃层数后,不允许继续选择 balancer - if depth < MAX_FALLBACK_DEPTH - and not will_loop(arg[1], v.id) - then - o:value(v.id, v.remark) - o.group[#o.group + 1] = (v.group and v.group ~= "") and v.group or translate("default") - end - end - for k1, v1 in pairs(node_list) do - if k1 == "socks_list" or k1 == "normal_list" or k1 == "urltest_list" then - for i, v in ipairs(v1) do - o:value(v.id, v.remark) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - end - end - - -- 探测地址 - o = s:option(Flag, _n("useCustomProbeUrl"), translate("Use Custom Probe URL"), translate("By default the built-in probe URL will be used, enable this option to use a custom probe URL.")) - o:depends({ [_n("protocol")] = "_balancing" }) - - o = s:option(Value, _n("probeUrl"), translate("Probe URL")) - o:depends({ [_n("useCustomProbeUrl")] = true }) - o:value("https://cp.cloudflare.com/", "Cloudflare") - o:value("https://www.gstatic.com/generate_204", "Gstatic") - o:value("https://www.google.com/generate_204", "Google") - o:value("https://www.youtube.com/generate_204", "YouTube") - o:value("https://connect.rom.miui.com/generate_204", "MIUI (CN)") - o:value("https://connectivitycheck.platform.hicloud.com/generate_204", "HiCloud (CN)") - o:value("https://wifi.vivo.com.cn/generate_204", "VIVO (CN)") - o.default = o.keylist[3] - o.description = translate("The URL used to detect the connection status.") - - -- 探测间隔 - o = s:option(Value, _n("probeInterval"), translate("Probe Interval")) - o:depends({ [_n("protocol")] = "_balancing" }) - o.default = "1m" - o.placeholder = "1m" - o.description = translate("The interval between initiating probes.") .. "
" .. - translate("The time format is numbers + units, such as '10s', '2h45m', and the supported time units are s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "
" .. - translate("When the unit is not filled in, it defaults to seconds.") - - o = s:option(Value, _n("expected"), translate("Preferred Node Count")) - o:depends({ [_n("balancingStrategy")] = "leastLoad" }) - o.datatype = "uinteger" - o.default = "2" - o.placeholder = "2" - o.description = translate("The load balancer selects the optimal number of nodes, and traffic is randomly distributed among them.") - - o = s:option(Value, _n("tolerance"), translate("Failure Tolerance (%)")) - o:depends({ [_n("balancingStrategy")] = "leastLoad" }) - o.datatype = "uinteger" - o.default = "10" - o.placeholder = "10" - o.description = translate("The maximum acceptable speed test failure rate. For example, 1 means allowing a 1% failure rate.") -end -- [[ 负载均衡 End ]] - -if load_iface_options then -- [[ 自定义接口 Start ]] - o = s:option(Value, _n("iface"), translate("Interface")) - o:depends({ [_n("protocol")] = "_iface" }) - for _, d in ipairs(netdev_list) do - o:value(d.name, d.label) - end -end -- [[ 自定义接口 End ]] - - -if load_normal_options then - -o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) - -o = s:option(Value, _n("port"), translate("Port")) -o.datatype = "port" - -o = s:option(Value, _n("uuid"), translate("ID")) -o.password = true -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) - -o = s:option(Value, _n("username"), translate("Username")) -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "socks" }) - -o = s:option(Value, _n("password"), translate("Password")) -o.password = true -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "trojan" }) - -o = s:option(ListValue, _n("security"), translate("Encrypt Method")) -for a, t in ipairs(security_list) do o:value(t) end -o:depends({ [_n("protocol")] = "vmess" }) - -o = s:option(Value, _n("encryption"), translate("Encrypt Method") .. " (encryption)") -o.default = "none" -o.placeholder = "none" -o:depends({ [_n("protocol")] = "vless" }) -o.validate = function(self, value) - value = api.trim(value) - return (value == "" and "none" or value) -end - -o = s:option(ListValue, _n("ss_method"), translate("Encrypt Method")) -o.rewrite_option = "method" -for a, t in ipairs(ss_method_list) do o:value(t) end -o:depends({ [_n("protocol")] = "shadowsocks" }) - -o = s:option(ListValue, _n("flow"), translate("flow")) -o.default = "" -o:value("", translate("Disable")) -o:value("xtls-rprx-vision") -o:value("xtls-rprx-vision-udp443") -o:depends({ [_n("protocol")] = "vless" }) - ----- [[hysteria2]] -o = s:option(Value, _n("hysteria2_hop"), translate("Port hopping range")) -o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).") -o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) - -o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5.")) -o.datatype = "or(uinteger,portrange)" -o.placeholder = "30" -o.default = "30" -o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) - -o = s:option(Flag, _n("hysteria2_realms"), translate("Realms")) -o.default = "0" -if api.compare_versions(xray_version, ">", "26.5.9") then - o:depends({ [_n("protocol")] = "hysteria2"}) -else - o:depends({ [_n("protocol")] = "__hide"}) -end - -o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") -o:depends({ [_n("hysteria2_realms")] = "1" }) -o.validate = function(self, value) - value = api.trim(value) - local realm = api.parse_realm_uri(value) - if realm then return value end - return nil, translate("Invalid Realm URL.") -end - -o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN")) -o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } -o:depends({ [_n("hysteria2_realms")] = "1" }) - -o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password")) -o.password = true -o:depends({ [_n("protocol")] = "hysteria2"}) - -o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) -o:value("", translate("Disable")) -o:value("salamander") -o:value("gecko") -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password")) -o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) -o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - -o = s:option(Value, _n("hysteria2_obfs_MinPacketSize"), translate("Gecko Packet Size (min)")) -o.datatype = "uinteger" -o.placeholder = "512" -o.default = "512" -o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - -o = s:option(Value, _n("hysteria2_obfs_MaxPacketSize"), translate("Gecko Packet Size (max)")) -o.datatype = "uinteger" -o.placeholder = "1200" -o.default = "1200" -o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - -o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps")) -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps")) -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)") -o.datatype = "range(4,120)" -o:depends({ [_n("protocol")] = "hysteria2"}) - -o = s:option(Value, _n("hysteria2_keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)") -o.datatype = "range(2,60)" -o:depends({ [_n("protocol")] = "hysteria2"}) - -o = s:option(Flag, _n("hysteria2_disable_mtu_discovery"), translate("Disable MTU detection")) -o.default = "0" -o:depends({ [_n("protocol")] = "hysteria2"}) ----- [[hysteria2 end]] - -o = s:option(Flag, _n("tls"), translate("TLS")) -o.default = 0 -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) - -o = s:option(Flag, _n("reality"), translate("REALITY"), translate("Only recommend to use with VLESS-TCP-XTLS-Vision.")) -o.default = 0 -o:depends({ [_n("tls")] = true, [_n("transport")] = "raw" }) -o:depends({ [_n("tls")] = true, [_n("transport")] = "ws" }) -o:depends({ [_n("tls")] = true, [_n("transport")] = "grpc" }) -o:depends({ [_n("tls")] = true, [_n("transport")] = "httpupgrade" }) -o:depends({ [_n("tls")] = true, [_n("transport")] = "xhttp" }) - -o = s:option(ListValue, _n("alpn"), translate("alpn")) -o.default = "default" -o:value("default", translate("Default")) -o:value("h3") -o:value("h2") -o:value("h3,h2") -o:value("http/1.1") -o:value("h2,http/1.1") -o:value("h3,h2,http/1.1") -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) - --- o = s:option(Value, _n("minversion"), translate("minversion")) --- o.default = "1.3" --- o:value("1.3") --- o:depends({ [_n("tls")] = true }) - -o = s:option(Value, _n("tls_serverName"), "SNI " .. translate("Domain")) -o:depends({ [_n("tls")] = true }) -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(Value, _n("tls_pinSHA256"), translate("TLS Chain Fingerprint (SHA256)")) -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o.description = translate("Once set, connects only when the server’s chain fingerprint matches.") .. - string.format("%s", "→ " .. translate("Fetch Manually")) - -o = s:option(Value, _n("tls_CertByName"), translate("TLS Certificate Name (CertName)"), translate("TLS is used to verify the leaf certificate name.")) -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(Flag, _n("tls_certificate"), translate("TLS Certificate (PEM)")) -o.default = "0" -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(TextValue, _n("tls_certificate_pem"), " ", translate("Full certificate (chain), PEM format.")) -o.default = "" -o.rows = 5 -o.wrap = "off" -o:depends({ [_n("tls_certificate")] = true }) -o.validate = function(self, value) - value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") - return value -end - -o = s:option(Flag, _n("ech"), translate("ECH")) -o.default = "0" -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) - -o = s:option(TextValue, _n("ech_config"), translate("ECH Config")) -o.default = "" -o.rows = 5 -o.wrap = "soft" -o:depends({ [_n("ech")] = true }) -o.validate = function(self, value) - return api.trim(value:gsub("[\r\n]", "")) -end - --- [[ REALITY部分 ]] -- -o = s:option(Value, _n("reality_publicKey"), translate("Public Key")) -o:depends({ [_n("tls")] = true, [_n("reality")] = true }) - -o = s:option(Value, _n("reality_shortId"), translate("Short Id")) -o:depends({ [_n("tls")] = true, [_n("reality")] = true }) - -o = s:option(Value, _n("reality_spiderX"), translate("Spider X")) -o.placeholder = "/" -o:depends({ [_n("tls")] = true, [_n("reality")] = true }) - -o = s:option(Flag, _n("utls"), translate("uTLS")) -o.default = "0" -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) - -o = s:option(ListValue, _n("fingerprint"), translate("Finger Print")) -o:value("chrome") -o:value("firefox") -o:value("edge") -o:value("safari") -o:value("360") -o:value("qq") -o:value("ios") -o:value("android") -o:value("random") -o:value("randomized") -o:value("unsafe") -o.default = "chrome" -o:depends({ [_n("tls")] = true, [_n("utls")] = true }) -o:depends({ [_n("tls")] = true, [_n("reality")] = true }) - -o = s:option(Value, _n("cipherSuites"), translate("Cipher Suites"), '***' .. " " .. translate("Configures the list of supported cipher suites, separated by :")) -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) - -o = s:option(Flag, _n("use_mldsa65Verify"), translate("ML-DSA-65")) -o.default = "0" -o:depends({ [_n("tls")] = true, [_n("reality")] = true }) - -o = s:option(TextValue, _n("reality_mldsa65Verify"), "ML-DSA-65 " .. translate("Public key")) -o.default = "" -o.rows = 5 -o.wrap = "soft" -o:depends({ [_n("use_mldsa65Verify")] = true }) -o.validate = function(self, value) - return api.trim(value:gsub("[\r\n]", "")) -end - -o = s:option(ListValue, _n("transport"), translate("Transport")) -o:value("raw", "RAW (TCP)") -o:value("mkcp", "mKCP") -o:value("ws", "WebSocket") -o:value("grpc", "gRPC") -o:value("httpupgrade", "HttpUpgrade") -o:value("xhttp", "XHTTP") -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "trojan" }) - -o = s:option(Value, _n("wireguard_public_key"), translate("Public Key")) -o:depends({ [_n("protocol")] = "wireguard" }) - -o = s:option(Value, _n("wireguard_secret_key"), translate("Private Key")) -o:depends({ [_n("protocol")] = "wireguard" }) - -o = s:option(Value, _n("wireguard_preSharedKey"), translate("Pre shared key")) -o:depends({ [_n("protocol")] = "wireguard" }) - -o = s:option(DynamicList, _n("wireguard_local_address"), translate("Local Address")) -o:depends({ [_n("protocol")] = "wireguard" }) - -o = s:option(Value, _n("wireguard_mtu"), translate("MTU")) -o.default = "1420" -o:depends({ [_n("protocol")] = "wireguard" }) - -if api.compare_versions(xray_version, ">=", "1.8.0") then - o = s:option(Value, _n("wireguard_reserved"), translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings.")) - o:depends({ [_n("protocol")] = "wireguard" }) -end - -o = s:option(Value, _n("wireguard_keepAlive"), translate("Keep Alive")) -o.default = "0" -o:depends({ [_n("protocol")] = "wireguard" }) - --- [[ RAW部分 ]]-- - --- TCP伪装 -o = s:option(ListValue, _n("tcp_guise"), translate("Camouflage Type")) -o:value("none", "none") -o:value("http", "http") -o:depends({ [_n("transport")] = "raw" }) - --- HTTP域名 -o = s:option(DynamicList, _n("tcp_guise_http_host"), translate("HTTP Host")) -o:depends({ [_n("tcp_guise")] = "http" }) - --- HTTP路径 -o = s:option(DynamicList, _n("tcp_guise_http_path"), translate("HTTP Path")) -o.placeholder = "/" -o:depends({ [_n("tcp_guise")] = "http" }) - --- [[ mKCP部分 ]]-- - -o = s:option(ListValue, _n("mkcp_guise"), translate("Camouflage Type"), translate('
none: default, no masquerade, data sent is packets with no characteristics.
srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).
utp: packets disguised as uTP will be recognized as bittorrent downloaded data.
wechat-video: packets disguised as WeChat video calls.
dtls: disguised as DTLS 1.2 packet.
wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)
dns: Disguising traffic as DNS requests.')) -for a, t in ipairs(header_type_list) do o:value(t) end -o:depends({ [_n("transport")] = "mkcp" }) - -o = s:option(Value, _n("mkcp_domain"), translate("Camouflage Domain"), translate("Use it together with the DNS disguised type. You can fill in any domain.")) -o:depends({ [_n("mkcp_guise")] = "dns" }) - -o = s:option(Value, _n("mkcp_mtu"), translate("KCP MTU")) -o.datatype = "uinteger" -o.default = 1350 -o:depends({ [_n("transport")] = "mkcp" }) - -o = s:option(Value, _n("mkcp_seed"), translate("KCP Seed")) -o:depends({ [_n("transport")] = "mkcp" }) - --- [[ WebSocket部分 ]]-- -o = s:option(Value, _n("ws_host"), translate("WebSocket Host")) -o:depends({ [_n("transport")] = "ws" }) - -o = s:option(Value, _n("ws_path"), translate("WebSocket Path")) -o.placeholder = "/" -o:depends({ [_n("transport")] = "ws" }) - -o = s:option(Value, _n("ws_heartbeatPeriod"), translate("HeartbeatPeriod(second)")) -o.datatype = "integer" -o:depends({ [_n("transport")] = "ws" }) - --- [[ gRPC部分 ]]-- -o = s:option(Value, _n("grpc_serviceName"), "ServiceName") -o:depends({ [_n("transport")] = "grpc" }) - -o = s:option(ListValue, _n("grpc_mode"), "gRPC " .. translate("Transfer mode")) -o:value("gun") -o:value("multi") -o:depends({ [_n("transport")] = "grpc" }) - -o = s:option(Flag, _n("grpc_health_check"), translate("Health check")) -o:depends({ [_n("transport")] = "grpc" }) - -o = s:option(Value, _n("grpc_idle_timeout"), translate("Idle timeout")) -o.default = "10" -o:depends({ [_n("grpc_health_check")] = true }) - -o = s:option(Value, _n("grpc_health_check_timeout"), translate("Health check timeout")) -o.default = "20" -o:depends({ [_n("grpc_health_check")] = true }) - -o = s:option(Flag, _n("grpc_permit_without_stream"), translate("Permit without stream")) -o.default = "0" -o:depends({ [_n("grpc_health_check")] = true }) - -o = s:option(Value, _n("grpc_initial_windows_size"), translate("Initial Windows Size")) -o.default = "0" -o:depends({ [_n("transport")] = "grpc" }) - --- [[ HttpUpgrade部分 ]]-- -o = s:option(Value, _n("httpupgrade_host"), translate("HttpUpgrade Host")) -o:depends({ [_n("transport")] = "httpupgrade" }) - -o = s:option(Value, _n("httpupgrade_path"), translate("HttpUpgrade Path")) -o.placeholder = "/" -o:depends({ [_n("transport")] = "httpupgrade" }) - --- [[ XHTTP部分 ]]-- -o = s:option(ListValue, _n("xhttp_mode"), "XHTTP " .. translate("Mode")) -o:depends({ [_n("transport")] = "xhttp" }) -o.default = "auto" -o:value("auto") -o:value("packet-up") -o:value("stream-up") -o:value("stream-one") - -o = s:option(Value, _n("xhttp_host"), translate("XHTTP Host")) -o:depends({ [_n("transport")] = "xhttp" }) - -o = s:option(Value, _n("xhttp_path"), translate("XHTTP Path")) -o.placeholder = "/" -o:depends({ [_n("transport")] = "xhttp" }) - -o = s:option(Flag, _n("use_xhttp_extra"), translate("XHTTP Extra")) -o.default = "0" -o:depends({ [_n("transport")] = "xhttp" }) - -o = s:option(TextValue, _n("xhttp_extra"), " ", translate("An XHttpObject in JSON format, used for sharing.")) -o:depends({ [_n("use_xhttp_extra")] = true }) -o.rows = 10 -o.wrap = "off" -o.datatype = "json" -local o_validate = o.validate -o.validate = function(self, value) - value = api.trim(value):gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n") - local v = o_validate(self, value) - if v then return v end - return nil, "XHTTP Extra " .. translate("Must be JSON text!") -end -o.custom_cfgvalue = function(self, section, value) - local raw = m:get(section, "xhttp_extra") - if raw then - return api.base64Decode(raw) - end -end -o.custom_write = function(self, section, value) - m:set(section, "xhttp_extra", api.base64Encode(value) or "") - local success, data = pcall(jsonc.parse, value) - if success and data then - local address = (data.extra and data.extra.downloadSettings and data.extra.downloadSettings.address) - or (data.downloadSettings and data.downloadSettings.address) - if address and address ~= "" then - address = address:gsub("^%[", ""):gsub("%]$", "") - m:set(section, "download_address", address) - else - m:del(section, "download_address") - end - else - m:del(section, "download_address") - end -end -o.custom_remove = function(self, section, value) - m:del(section, "xhttp_extra") - m:del(section, "download_address") -end - --- [[ User-Agent ]]-- -o = s:option(Value, _n("user_agent"), translate("User-Agent")) -o.default = "" -o:value("", translate("default")) -o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36", "chrome") -o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0", "firefox") -o:value("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15", "safari") -o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70", "edge") -o:value("Go-http-client/1.1", "golang") -o:value("curl/7.68.0", "curl") -o:depends({ [_n("tcp_guise")] = "http" }) -o:depends({ [_n("transport")] = "ws" }) -o:depends({ [_n("transport")] = "httpupgrade" }) -o:depends({ [_n("transport")] = "xhttp" }) -o:depends({ [_n("transport")] = "grpc" }) - --- [[ Mux.Cool ]]-- -o = s:option(Flag, _n("mux"), "Mux", translate("Enable Mux.Cool")) -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "raw" }) -o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "ws" }) -o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "grpc" }) -o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "httpupgrade" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "trojan" }) - -o = s:option(Value, _n("mux_concurrency"), translate("Mux concurrency")) -o.default = -1 -o:depends({ [_n("mux")] = true }) - -o = s:option(Value, _n("xudp_concurrency"), translate("XUDP Mux concurrency")) -o.default = 8 -o:depends({ [_n("mux")] = true }) - ---[[FinalMask]] -o = s:option(Flag, _n("use_finalmask"), "FinalMask") -o.default = "0" -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "wireguard" }) -o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) - -o = s:option(TextValue, _n("finalmask"), " ") -o:depends({ [_n("use_finalmask")] = true }) -o.rows = 10 -o.wrap = "off" -o.description = translate("An FinalMaskObject in JSON format, used for sharing.") .. "
" .. - translate("Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related settings.") -o.datatype = "json" -local o_validate = o.validate -o.validate = function(self, value) - value = api.trim(value):gsub("\r\n", "\n"):gsub("^[ \t]*\n", ""):gsub("\n[ \t]*$", ""):gsub("\n[ \t]*\n", "\n") - local v = o_validate(self, value) - if v then return v end - return nil, "FinalMask " .. translate("Must be JSON text!") -end -o.custom_cfgvalue = function(self, section, value) - local raw = m:get(section, "finalmask") - if raw then - return api.base64Decode(raw) - end -end -o.custom_write = function(self, section, value) - m:set(section, "finalmask", api.base64Encode(value) or "") -end - ---[[Fast Open]] -o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required")) -o.default = 0 - ---[[tcpMptcp]] -o = s:option(Flag, _n("tcpMptcp"), "tcpMptcp", translate("Enable Multipath TCP, need to be enabled in both server and client configuration.")) -o.default = 0 - -o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve")) -o.description = translate("If the node address is a domain name, this DNS will be used for resolution.") .. "
" .. string.format('%s', - translate("Note: For node-specific DNS only. Keep Auto to avoid extra overhead.")) -o:value("", translate("Auto")) -o:value("tcp", "TCP") -o:value("udp", "UDP") -o:value("https", "DoH") - -o = s:option(Value, _n("domain_resolver_dns"), "DNS") -o.datatype = "or(ipaddr,ipaddrport)" -o:value("114.114.114.114") -o:value("223.5.5.5:53") -o.default = o.keylist[1] -o:depends({ [_n("domain_resolver")] = "tcp" }) -o:depends({ [_n("domain_resolver")] = "udp" }) - -o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") -o:value("https://120.53.53.53/dns-query", "DNSPod") -o:value("https://223.5.5.5/dns-query", "AliDNS") -o.default = o.keylist[1] -o:depends({ [_n("domain_resolver")] = "https" }) - -o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) -o.default = "" -o:value("", translate("Auto")) -o:value("UseIPv4v6", translate("Prefer IPv4")) -o:value("UseIPv6v4", translate("Prefer IPv6")) -o:value("UseIPv4", translate("IPv4 Only")) -o:value("UseIPv6", translate("IPv6 Only")) - -o = s:option(Flag, _n("happy_eyeballs"), translate("Enable Happy Eyeballs"), translate("Attempts IPv4 and IPv6 simultaneously; automatically uses the faster connection.")) -o.default = 0 - -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for i, v in ipairs(protocols) do - if not v:find("^_") then - local depends_condition = { [_n("protocol")] = v } - if v == "hysteria2" then - depends_condition[_n("hysteria2_realms")] = false - end - s.fields[_n("address")]:depends(depends_condition) - s.fields[_n("port")]:depends(depends_condition) - s.fields[_n("domain_resolver")]:depends(depends_condition) - s.fields[_n("happy_eyeballs")]:depends(depends_condition) - - local strategy_depends = api.clone(depends_condition) - strategy_depends[_n("happy_eyeballs")] = false - s.fields[_n("domain_strategy")]:depends(strategy_depends) - - if v ~= "hysteria2" then - s.fields[_n("tcp_fast_open")]:depends({ [_n("protocol")] = v }) - s.fields[_n("tcpMptcp")]:depends({ [_n("protocol")] = v }) - end - end - end -end -end --- [[ Normal single node End ]] - -if not load_shunt_options then - o = s:option(ListValue, _n("chain_proxy"), translate("Chain Proxy")) - o:value("", translate("Close(Not use)")) - if not (load_iface_options or load_balancing_options) then - -- Special node cannot be use pre-proxy. - o:value("1", translate("Preproxy Node")) - o:value("3", translate("Outbound Interface")) - end - o:value("2", translate("Landing Node")) - - o1 = s:option(ListValue, _n("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy.")) - o1:depends({ [_n("chain_proxy")] = "1", [_n("hysteria2_realms")] = false }) - o1.template = m:template_path("/cbi/nodes_listvalue") - o1.group = {} - - o3 = s:option(Value, _n("outbound_iface"), translate("Outbound Interface")) - o3:depends({ [_n("chain_proxy")] = "3" }) - o3:value("", translate("All")) - for _, d in ipairs(netdev_list) do - o3:value(d.name, d.label) - end - - o2 = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Only support a layer of proxy.")) - o2:depends({ [_n("chain_proxy")] = "2", [_n("hysteria2_realms")] = false }) - o2.template = m:template_path("/cbi/nodes_listvalue") - o2.group = {} - - for k1, v1 in pairs(node_list) do - if k1 ~= "shunt_list" and k1 ~= "iface_list" then - for i, v in ipairs(v1) do - if v.id ~= arg[1] then - o1:value(v.id, v.remark) - o1.group[#o1.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - if k1 == "normal_list" then - -- Landing Node not support use special node. - o2:value(v.id, v.remark) - o2.group[#o2.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - end - end - end - end -end - -api.luci_types(arg[1], m, s, type_name, option_prefix) - -if load_shunt_options then - local current_node = m:get(arg[1]) or {} - local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua") - setfenv(shunt_lua, getfenv(1))(m, s, { - node_id = arg[1], - node = current_node, - node_list = node_list, - }) -end diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua deleted file mode 100644 index b1dec827..00000000 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/sing-box.lua +++ /dev/null @@ -1,921 +0,0 @@ -local m, s = ... - -local singbox_bin = api.finded_com("sing-box") - -if not singbox_bin then - return -end - -type_name = "sing-box" - --- [[ sing-box ]] - -s.fields["type"]:value(type_name, "Sing-Box") -if not s.fields["type"].default then - s.fields["type"].default = type_name -end - -if s.val["type"] ~= type_name then - return -end - -local option_prefix = "singbox_" - -local function _n(name) - return option_prefix .. name -end - -local formvalue_proto = luci.http.formvalue(formvalue_key .. _n("protocol")) - -if formvalue_proto then s.val["protocol"] = formvalue_proto end - -local arg_select_proto = luci.http.formvalue("select_proto") or "" - -local ss_method_new_list = { - "none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" -} - -local ss_method_old_list = { - "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "rc4-md5", "chacha20-ietf", "xchacha20", -} - -local security_list = { "none", "auto", "aes-128-gcm", "chacha20-poly1305", "zero" } - -local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'") - -local singbox_version = api.get_app_version("sing-box"):match("[^v]+") - -o = s:option(ListValue, _n("protocol"), translate("Protocol")) -o:value("socks", "Socks") -o:value("http", "HTTP") -o:value("shadowsocks", "Shadowsocks") -o:value("vmess", "Vmess") -o:value("trojan", "Trojan") -if singbox_tags:find("with_wireguard") then - o:value("wireguard", "WireGuard") -end -if singbox_tags:find("with_quic") then - o:value("hysteria", "Hysteria") -end -o:value("vless", "VLESS") -if singbox_tags:find("with_quic") then - o:value("tuic", "TUIC") -end -if singbox_tags:find("with_quic") then - o:value("hysteria2", "Hysteria2") -end -o:value("anytls", "AnyTLS") -o:value("ssh", "SSH") -if singbox_tags:find("with_naive_outbound") then - o:value("naive", "NaïveProxy") -end -o:value("_urltest", translate("URLTest")) -o:value("_shunt", translate("Shunt")) -o:value("_iface", translate("Custom Interface")) -function o.custom_cfgvalue(self, section) - if arg_select_proto ~= "" then - return arg_select_proto - else - return m:get(section, self.option:sub(1 + #option_prefix)) - end -end - -local load_urltest_options = s.val["protocol"] == "_urltest" or arg_select_proto == "_urltest" -local load_shunt_options = s.val["protocol"] == "_shunt" or arg_select_proto == "_shunt" -local load_iface_options = s.val["protocol"] == "_iface" or arg_select_proto == "_iface" -local load_normal_options = true -if load_urltest_options or load_shunt_options or load_iface_options then - load_normal_options = nil -end -if not arg_select_proto:find("_") then - load_normal_options = true -end - -local netdev_list = api.get_network_devices() -local node_list = api.get_node_list() - -if load_urltest_options then -- [[ URLTest Start ]] - o = s:option(ListValue, _n("node_add_mode"), translate("Node Addition Method")) - o:depends({ [_n("protocol")] = "_urltest" }) - o.default = "manual" - o:value("manual", translate("Manual")) - o:value("batch", translate("Batch")) - - o = s:option(MultiValue, _n("urltest_node"), translate("URLTest node list"), translate("List of nodes to test, document")) - o:depends({ [_n("node_add_mode")] = "manual" }) - o.widget = "checkbox" - o.template = m:template_path("/cbi/nodes_multivalue") - o.group = {} - for k1, v1 in pairs(node_list) do - if k1 == "socks_list" or k1 == "normal_list" then - for i, v in ipairs(v1) do - o:value(v.id, v.remark) - o.group[#o.group+1] = v.group or "" - end - end - end - -- 读取旧 DynamicList - function o.custom_cfgvalue(self, section) - return table.concat(m:get(section, "urltest_node") or {}, " ") - end - -- 写入保持 DynamicList - function o.custom_write(self, section, value) - local old = m:get(section, "urltest_node") or {} - local new, set = {}, {} - for v in value:gmatch("%S+") do - new[#new + 1] = v - set[v] = 1 - end - for _, v in ipairs(old) do - if not set[v] then - m:set(section, "urltest_node", new) - return - end - set[v] = nil - end - for _ in pairs(set) do - m:set(section, "urltest_node", new) - return - end - end - - o = s:option(MultiValue, _n("node_group"), translate("Select Group")) - o:depends({ [_n("node_add_mode")] = "batch" }) - o.widget = "checkbox" - o:value("default", translate("default")) - for k, v in pairs(groups) do - o:value(api.UrlEncode(k), k) - end - - o = s:option(Value, _n("node_match_rule"), translate("Node Matching Rules")) - o:depends({ [_n("node_add_mode")] = "batch" }) - local descrStr = "Example: ^A && B && !C && D$
" - descrStr = descrStr .. "This means the node remark must start with A (^), include B, exclude C (!), and end with D ($).
" - descrStr = descrStr .. "Conditions are joined by && (AND), and their order does not affect the result.
" - descrStr = descrStr .. "Multiple groups can be separated by || (OR), matching succeeds if any group matches.
" - descrStr = descrStr .. "Example: A && B || C && D means (A AND B) OR (C AND D)." - o.description = translate(descrStr) - - o = s:option(Value, _n("urltest_url"), translate("Probe URL")) - o:depends({ [_n("protocol")] = "_urltest" }) - o:value("https://cp.cloudflare.com/", "Cloudflare") - o:value("https://www.gstatic.com/generate_204", "Gstatic") - o:value("https://www.google.com/generate_204", "Google") - o:value("https://www.youtube.com/generate_204", "YouTube") - o:value("https://connect.rom.miui.com/generate_204", "MIUI (CN)") - o:value("https://connectivitycheck.platform.hicloud.com/generate_204", "HiCloud (CN)") - o:value("https://wifi.vivo.com.cn/generate_204", "VIVO (CN)") - o.default = o.keylist[3] - o.description = translate("The URL used to detect the connection status.") - - o = s:option(Value, _n("urltest_interval"), translate("Test interval")) - o:depends({ [_n("protocol")] = "_urltest" }) - o.default = "3m" - o.placeholder = "3m" - o.description = translate("The interval between initiating probes.") .. "
" .. - translate("The time format is numbers + units, such as '10s', '2h45m', and the supported time units are s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "
" .. - translate("When the unit is not filled in, it defaults to seconds.") .. "
" .. - translate("Test interval must be less or equal than idle timeout.") - - o = s:option(Value, _n("urltest_tolerance"), translate("Test tolerance"), translate("The test tolerance in milliseconds.")) - o:depends({ [_n("protocol")] = "_urltest" }) - o.datatype = "uinteger" - o.placeholder = "50" - o.default = "50" - - o = s:option(Value, _n("urltest_idle_timeout"), translate("Idle timeout")) - o:depends({ [_n("protocol")] = "_urltest" }) - o.placeholder = "30m" - o.default = "30m" - o.description = translate("The idle timeout.") .. "
" .. - translate("The time format is numbers + units, such as '10s', '2h45m', and the supported time units are s, m, h, which correspond to seconds, minutes, and hours, respectively.") .. "
" .. - translate("When the unit is not filled in, it defaults to seconds.") - - o = s:option(Flag, _n("urltest_interrupt_exist_connections"), translate("Interrupt existing connections")) - o:depends({ [_n("protocol")] = "_urltest" }) - o.default = "0" - o.description = translate("Interrupt existing connections when the selected outbound has changed.") -end -- [[ URLTest End ]] - -if load_iface_options then -- [[ 自定义接口 Start ]] - o = s:option(Value, _n("iface"), translate("Interface")) - o:depends({ [_n("protocol")] = "_iface" }) - for _, d in ipairs(netdev_list) do - o:value(d.name, d.label) - end -end - - -if load_normal_options then - -o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) - -o = s:option(Value, _n("port"), translate("Port")) -o.datatype = "port" - -o = s:option(Value, _n("uuid"), translate("ID")) -o.password = true -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "tuic" }) - -o = s:option(Value, _n("username"), translate("Username")) -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "ssh" }) -o:depends({ [_n("protocol")] = "naive" }) - -o = s:option(Value, _n("password"), translate("Password")) -o.password = true -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "anytls" }) -o:depends({ [_n("protocol")] = "ssh" }) -o:depends({ [_n("protocol")] = "naive" }) - -o = s:option(ListValue, _n("security"), translate("Encrypt Method")) -for a, t in ipairs(security_list) do o:value(t) end -o:depends({ [_n("protocol")] = "vmess" }) - -o = s:option(ListValue, _n("ss_method"), translate("Encrypt Method")) -o.rewrite_option = "method" -for a, t in ipairs(ss_method_new_list) do o:value(t) end -for a, t in ipairs(ss_method_old_list) do o:value(t) end -o:depends({ [_n("protocol")] = "shadowsocks" }) - -o = s:option(Flag, _n("uot"), translate("UDP over TCP")) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "naive" }) - -o = s:option(Value, _n("alter_id"), "Alter ID") -o.datatype = "uinteger" -o.default = "0" -o:depends({ [_n("protocol")] = "vmess" }) - -o = s:option(Flag, _n("global_padding"), "global_padding", translate("Protocol parameter. Will waste traffic randomly if enabled.")) -o.default = "0" -o:depends({ [_n("protocol")] = "vmess" }) - -o = s:option(Flag, _n("authenticated_length"), "authenticated_length", translate("Protocol parameter. Enable length block encryption.")) -o.default = "0" -o:depends({ [_n("protocol")] = "vmess" }) - -o = s:option(ListValue, _n("flow"), translate("flow")) -o.default = "" -o:value("", translate("Disable")) -o:value("xtls-rprx-vision") -o:depends({ [_n("protocol")] = "vless", [_n("tls")] = true }) - -if singbox_tags:find("with_quic") then - o = s:option(Value, _n("hysteria_hop"), translate("Port hopping range")) - o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).") - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_hop_interval"), translate("Hop Interval(second)"), translate("Example:") .. "30 (≥5)") - o.datatype = "uinteger" - o.placeholder = "30" - o.default = "30" - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_obfs"), translate("Obfs Password")) - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(ListValue, _n("hysteria_auth_type"), translate("Auth Type")) - o:value("disable", translate("Disable")) - o:value("string", translate("STRING")) - o:value("base64", translate("BASE64")) - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_auth_password"), translate("Auth Password")) - o.password = true - o:depends({ [_n("protocol")] = "hysteria", [_n("hysteria_auth_type")] = "string"}) - o:depends({ [_n("protocol")] = "hysteria", [_n("hysteria_auth_type")] = "base64"}) - - o = s:option(Value, _n("hysteria_up_mbps"), translate("Max upload Mbps")) - o.default = "10" - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_down_mbps"), translate("Max download Mbps")) - o.default = "50" - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_recv_window_conn"), translate("QUIC stream receive window")) - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_recv_window"), translate("QUIC connection receive window")) - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Flag, _n("hysteria_disable_mtu_discovery"), translate("Disable MTU detection")) - o:depends({ [_n("protocol")] = "hysteria" }) -end - -if singbox_tags:find("with_quic") then - o = s:option(ListValue, _n("tuic_congestion_control"), translate("Congestion control algorithm")) - o.default = "cubic" - o:value("bbr", translate("BBR")) - o:value("cubic", translate("CUBIC")) - o:value("new_reno", translate("New Reno")) - o:depends({ [_n("protocol")] = "tuic" }) - - o = s:option(ListValue, _n("tuic_udp_relay_mode"), translate("UDP relay mode")) - o.default = "native" - o:value("native", translate("native")) - o:value("quic", translate("QUIC")) - o:depends({ [_n("protocol")] = "tuic" }) - - --[[ - o = s:option(Flag, _n("tuic_udp_over_stream"), translate("UDP over stream")) - o:depends({ [_n("protocol")] = "tuic" }) - ]]-- - - o = s:option(Flag, _n("tuic_zero_rtt_handshake"), translate("Enable 0-RTT QUIC handshake")) - o.default = 0 - o:depends({ [_n("protocol")] = "tuic" }) - - o = s:option(Value, _n("tuic_heartbeat"), translate("Heartbeat interval(second)")) - o.datatype = "uinteger" - o.default = "3" - o:depends({ [_n("protocol")] = "tuic" }) - - o = s:option(ListValue, _n("tuic_alpn"), translate("QUIC TLS ALPN")) - o.default = "default" - o:value("default", translate("Default")) - o:value("h3") - o:value("h2") - o:value("h3,h2") - o:value("http/1.1") - o:value("h2,http/1.1") - o:value("h3,h2,http/1.1") - o:value("spdy/3.1") - o:value("h3,spdy/3.1") - o:depends({ [_n("protocol")] = "tuic" }) -end - -if singbox_tags:find("with_quic") then - o = s:option(Value, _n("hysteria2_hop"), translate("Port hopping range")) - o.description = translate("Format as 1000:2000 or 1000-2000 Multiple groups are separated by commas (,).") - o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) - - o = s:option(Value, _n("hysteria2_hop_interval"), translate("Hop Interval(second)"), translate("Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5.")) - o.datatype = "or(uinteger,portrange)" - o.placeholder = "30" - o.default = "30" - o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) - - o = s:option(Flag, _n("hysteria2_realms"), translate("Realms")) - o.default = "0" - if api.compare_versions(singbox_version, ">=", "1.14.0") then - o:depends({ [_n("protocol")] = "hysteria2"}) - else - o:depends({ [_n("protocol")] = "__hide"}) - end - - o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") - o:depends({ [_n("hysteria2_realms")] = "1" }) - o.validate = function(self, value) - value = api.trim(value) - local realm = api.parse_realm_uri(value) - if realm then return value end - return nil, translate("Invalid Realm URL.") - end - - o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN")) - o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } - o:depends({ [_n("hysteria2_realms")] = "1" }) - - o = s:option(Value, _n("hysteria2_auth_password"), translate("Auth Password")) - o.password = true - o:depends({ [_n("protocol")] = "hysteria2"}) - - o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) - o:value("", translate("Disable")) - o:value("salamander") - o:value("gecko") - o:depends({ [_n("protocol")] = "hysteria2" }) - - o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password")) - o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) - o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - - o = s:option(Value, _n("hysteria2_obfs_MinPacketSize"), translate("Gecko Packet Size (min)")) - o.datatype = "uinteger" - o.placeholder = "512" - o.default = "512" - o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - - o = s:option(Value, _n("hysteria2_obfs_MaxPacketSize"), translate("Gecko Packet Size (max)")) - o.datatype = "uinteger" - o.placeholder = "1200" - o.default = "1200" - o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - - o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps")) - o:depends({ [_n("protocol")] = "hysteria2" }) - - o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps")) - o:depends({ [_n("protocol")] = "hysteria2" }) - - o = s:option(Value, _n("hysteria2_idle_timeout"), translate("Idle Timeout"), translate("Units:seconds") .. " (4~120)") - o.datatype = "range(4,120)" - o:depends({ [_n("protocol")] = "hysteria2"}) - - o = s:option(Value, _n("hysteria2_keep_alive_period"), translate("QUIC KeepAlive interval"), translate("Units:seconds") .. " (2~60)") - o.datatype = "range(2,60)" - o:depends({ [_n("protocol")] = "hysteria2"}) - - o = s:option(Flag, _n("hysteria2_disable_mtu_discovery"), translate("Disable MTU detection")) - o.default = "0" - o:depends({ [_n("protocol")] = "hysteria2"}) -end - --- [[ SSH config start ]] -- -o = s:option(TextValue, _n("ssh_priv_key"), translate("Private Key")) -o.rows = 5 -o.wrap = "off" -o:depends({ [_n("protocol")] = "ssh" }) -o.validate = function(self, value) - value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") - return value -end - -o = s:option(Value, _n("ssh_priv_key_pp"), translate("Private Key Passphrase")) -o.password = true -o:depends({ [_n("protocol")] = "ssh" }) - -o = s:option(DynamicList, _n("ssh_host_key"), translate("Host Key"), translate("Accept any if empty.")) -o:depends({ [_n("protocol")] = "ssh" }) - -o = s:option(DynamicList, _n("ssh_host_key_algo"), translate("Host Key Algorithms")) -o:depends({ [_n("protocol")] = "ssh" }) - -o = s:option(Value, _n("ssh_client_version"), translate("Client Version"), translate("Random version will be used if empty.")) -o:depends({ [_n("protocol")] = "ssh" }) --- [[ SSH config end ]] -- - --- [[ naive start ]] -- -o = s:option(Value, _n("naive_insecure_concurrency"), translate("Concurrent Tunnels")) -o.datatype = "uinteger" -o.placeholder = "0" -o.default = "0" -o:depends({ [_n("protocol")] = "naive" }) - -o = s:option(Flag, _n("naive_quic"), translate("QUIC")) -o.default = 0 -o:depends({ [_n("protocol")] = "naive" }) - -o = s:option(ListValue, _n("naive_congestion_control"), translate("Congestion control algorithm")) -o.default = "bbr" -o:value("bbr", translate("BBR")) -o:value("bbr2", translate("BBRv2")) -o:value("cubic", translate("CUBIC")) -o:value("reno", translate("New Reno")) -o:depends({ [_n("naive_quic")] = "1" }) --- [[ naive end ]] -- - -o = s:option(Flag, _n("tls"), translate("TLS")) -o.default = 0 -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "anytls" }) - -o = s:option(ListValue, _n("alpn"), translate("ALPN")) -o.default = "default" -o:value("default", translate("Default")) -o:value("h3") -o:value("h2") -o:value("h3,h2") -o:value("http/1.1") -o:value("h2,http/1.1") -o:value("h3,h2,http/1.1") -o:depends({ [_n("tls")] = true }) -o:depends({ [_n("protocol")] = "hysteria" }) - -o = s:option(Flag, _n("tls_disable_sni"), translate("Disable SNI"), translate("Do not send server name in ClientHello.")) -o.default = "0" -o:depends({ [_n("tls")] = true }) -o:depends({ [_n("protocol")] = "hysteria"}) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(Value, _n("tls_serverName"), "SNI " .. translate("Domain")) -o:depends({ [_n("tls")] = true }) -o:depends({ [_n("protocol")] = "hysteria"}) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o:depends({ [_n("protocol")] = "naive" }) - -o = s:option(Flag, _n("tls_allowInsecure"), translate("allowInsecure"), translate("Whether unsafe connections are allowed. When checked, Certificate validation will be skipped.")) -o.default = "0" -o:depends({ [_n("tls")] = true }) -o:depends({ [_n("protocol")] = "hysteria"}) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(Flag, _n("tls_certificate"), translate("TLS Certificate (PEM)")) -o.default = "0" -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "hysteria"}) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o:depends({ [_n("protocol")] = "naive" }) - -o = s:option(TextValue, _n("tls_certificate_pem"), " ", translate("Full certificate (chain), PEM format.")) -o.default = "" -o.rows = 5 -o.wrap = "off" -o:depends({ [_n("tls_certificate")] = true }) -o.validate = function(self, value) - value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") - return value -end - -o = s:option(Value, _n("cipherSuites"), translate("Cipher Suites"), '***' .. " " .. translate("Configures the list of supported cipher suites, separated by :")) -o:depends({ [_n("tls")] = true }) - -o = s:option(Flag, _n("ech"), translate("ECH")) -o.default = "0" -o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria" }) -o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) -o:depends({ [_n("protocol")] = "naive" }) - -o = s:option(TextValue, _n("ech_config"), translate("ECH Config")) -o.default = "" -o.rows = 5 -o.wrap = "off" -o:depends({ [_n("ech")] = true }) -o.validate = function(self, value) - value = api.trim(value):gsub("\r\n", "\n"):gsub("[ \t]*\n[ \t]*", "\n"):gsub("\n+", "\n") - return value -end - -o = s:option(Value, _n("ech_query_server_name"), translate("ECH Query Domain"), translate("Overrides the domain name used for ECH HTTPS record queries.")) -o:depends({ [_n("ech")] = true }) - -if singbox_tags:find("with_utls") then - o = s:option(Flag, _n("utls"), translate("uTLS")) - o.default = "0" - o:depends({ [_n("tls")] = true }) - - o = s:option(ListValue, _n("fingerprint"), translate("Finger Print")) - o:value("chrome") - o:value("firefox") - o:value("edge") - o:value("safari") - o:value("360") - o:value("qq") - o:value("ios") - o:value("android") - o:value("random") - o:value("randomized") - o.default = "chrome" - o:depends({ [_n("utls")] = true }) - - -- [[ REALITY部分 ]] -- - o = s:option(Flag, _n("reality"), translate("REALITY")) - o.default = 0 - o:depends({ [_n("protocol")] = "vless", [_n("tls")] = true }) - o:depends({ [_n("protocol")] = "vmess", [_n("tls")] = true }) - o:depends({ [_n("protocol")] = "shadowsocks", [_n("tls")] = true }) - o:depends({ [_n("protocol")] = "trojan", [_n("tls")] = true }) - o:depends({ [_n("protocol")] = "anytls", [_n("tls")] = true }) - - o = s:option(Value, _n("reality_publicKey"), translate("Public Key")) - o:depends({ [_n("reality")] = true }) - - o = s:option(Value, _n("reality_shortId"), translate("Short Id")) - o:depends({ [_n("reality")] = true }) -end - -o = s:option(ListValue, _n("transport"), translate("Transport")) -o:value("tcp", "TCP") -o:value("http", "HTTP") -o:value("ws", "WebSocket") -o:value("httpupgrade", "HTTPUpgrade") -if singbox_tags:find("with_quic") then - o:value("quic", "QUIC") -end -if singbox_tags:find("with_grpc") then - o:value("grpc", "gRPC") -else o:value("grpc", "gRPC-lite") -end -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "trojan" }) - -if singbox_tags:find("with_wireguard") then - o = s:option(Value, _n("wireguard_public_key"), translate("Public Key")) - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(Value, _n("wireguard_secret_key"), translate("Private Key")) - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(Value, _n("wireguard_preSharedKey"), translate("Pre shared key")) - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(DynamicList, _n("wireguard_local_address"), translate("Local Address")) - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(Value, _n("wireguard_mtu"), translate("MTU")) - o.default = "1420" - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(Value, _n("wireguard_reserved"), translate("Reserved"), translate("Decimal numbers separated by \",\" or Base64-encoded strings.")) - o:depends({ [_n("protocol")] = "wireguard" }) -end - --- [[ TCP部分(模拟) ]]-- -o = s:option(ListValue, _n("tcp_guise"), translate("Camouflage Type")) -o:value("none", "none") -o:value("http", "http") -o:depends({ [_n("transport")] = "tcp" }) - -o = s:option(DynamicList, _n("tcp_guise_http_host"), translate("HTTP Host")) -o:depends({ [_n("tcp_guise")] = "http" }) - -o = s:option(DynamicList, _n("tcp_guise_http_path"), translate("HTTP Path")) -o.placeholder = "/" -o:depends({ [_n("tcp_guise")] = "http" }) - --- [[ HTTP部分 ]]-- -o = s:option(DynamicList, _n("http_host"), translate("HTTP Host")) -o:depends({ [_n("transport")] = "http" }) - -o = s:option(Value, _n("http_path"), translate("HTTP Path")) -o.placeholder = "/" -o:depends({ [_n("transport")] = "http" }) - -o = s:option(Flag, _n("http_h2_health_check"), translate("Health check")) -o:depends({ [_n("tls")] = true, [_n("transport")] = "http" }) - -o = s:option(Value, _n("http_h2_read_idle_timeout"), translate("Idle timeout")) -o.default = "15" -o:depends({ [_n("http_h2_health_check")] = true }) - -o = s:option(Value, _n("http_h2_health_check_timeout"), translate("Health check timeout")) -o.default = "15" -o:depends({ [_n("http_h2_health_check")] = true }) - --- [[ WebSocket部分 ]]-- -o = s:option(Value, _n("ws_host"), translate("WebSocket Host")) -o:depends({ [_n("transport")] = "ws" }) - -o = s:option(Value, _n("ws_path"), translate("WebSocket Path")) -o.placeholder = "/" -o:depends({ [_n("transport")] = "ws" }) - -o = s:option(Flag, _n("ws_enableEarlyData"), translate("Enable early data")) -o:depends({ [_n("transport")] = "ws" }) - -o = s:option(Value, _n("ws_maxEarlyData"), translate("Early data length")) -o.default = "1024" -o:depends({ [_n("ws_enableEarlyData")] = true }) - -o = s:option(Value, _n("ws_earlyDataHeaderName"), translate("Early data header name"), translate("Recommended value: Sec-WebSocket-Protocol")) -o:depends({ [_n("ws_enableEarlyData")] = true }) - --- [[ HTTPUpgrade部分 ]]-- -o = s:option(Value, _n("httpupgrade_host"), translate("HTTPUpgrade Host")) -o:depends({ [_n("transport")] = "httpupgrade" }) - -o = s:option(Value, _n("httpupgrade_path"), translate("HTTPUpgrade Path")) -o.placeholder = "/" -o:depends({ [_n("transport")] = "httpupgrade" }) - --- [[ gRPC部分 ]]-- -o = s:option(Value, _n("grpc_serviceName"), "ServiceName") -o:depends({ [_n("transport")] = "grpc" }) - -o = s:option(Flag, _n("grpc_health_check"), translate("Health check")) -o:depends({ [_n("transport")] = "grpc" }) - -o = s:option(Value, _n("grpc_idle_timeout"), translate("Idle timeout")) -o.default = "15" -o:depends({ [_n("grpc_health_check")] = true }) - -o = s:option(Value, _n("grpc_health_check_timeout"), translate("Health check timeout")) -o.default = "15" -o:depends({ [_n("grpc_health_check")] = true }) - -o = s:option(Flag, _n("grpc_permit_without_stream"), translate("Permit without stream")) -o.default = "0" -o:depends({ [_n("grpc_health_check")] = true }) - --- [[ User-Agent ]]-- -o = s:option(Value, _n("user_agent"), translate("User-Agent")) -o.default = "" -o:value("", translate("default")) -o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36", "chrome") -o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0", "firefox") -o:value("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15", "safari") -o:value("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.70", "edge") -o:value("Go-http-client/1.1", "golang") -o:value("curl/7.68.0", "curl") -o:depends({ [_n("tcp_guise")] = "http" }) -o:depends({ [_n("transport")] = "http" }) -o:depends({ [_n("transport")] = "ws" }) -o:depends({ [_n("transport")] = "httpupgrade" }) -o:depends({ [_n("protocol")] = "naive" }) - --- [[ Mux ]]-- -o = s:option(Flag, _n("mux"), translate("Mux")) -o.rmempty = false -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless", [_n("flow")] = "" }) -o:depends({ [_n("protocol")] = "shadowsocks", [_n("uot")] = "" }) -o:depends({ [_n("protocol")] = "trojan" }) - -o = s:option(ListValue, _n("mux_type"), translate("Mux")) -o:value("smux") -o:value("yamux") -o:value("h2mux") -o:depends({ [_n("mux")] = true }) - -o = s:option(Value, _n("mux_concurrency"), translate("Mux concurrency")) -o.default = 4 -o:depends({ [_n("mux")] = true, [_n("tcpbrutal")] = false }) - -o = s:option(Flag, _n("mux_padding"), translate("Padding")) -o.default = 0 -o:depends({ [_n("mux")] = true }) - --- [[ TCP Brutal ]]-- -o = s:option(Flag, _n("tcpbrutal"), translate("TCP Brutal")) -o.default = 0 -o:depends({ [_n("mux")] = true }) - -o = s:option(Value, _n("tcpbrutal_up_mbps"), translate("Max upload Mbps")) -o.default = "10" -o:depends({ [_n("tcpbrutal")] = true }) - -o = s:option(Value, _n("tcpbrutal_down_mbps"), translate("Max download Mbps")) -o.default = "50" -o:depends({ [_n("tcpbrutal")] = true }) - -o = s:option(Flag, _n("shadowtls"), "ShadowTLS") -o.default = 0 -o:depends({ [_n("protocol")] = "vmess", [_n("tls")] = false }) -o:depends({ [_n("protocol")] = "shadowsocks", [_n("tls")] = false }) - -o = s:option(ListValue, _n("shadowtls_version"), "ShadowTLS " .. translate("Version")) -o.default = "1" -o:value("1", "ShadowTLS v1") -o:value("2", "ShadowTLS v2") -o:value("3", "ShadowTLS v3") -o:depends({ [_n("shadowtls")] = true }) - -o = s:option(Value, _n("shadowtls_password"), "ShadowTLS " .. translate("Password")) -o.password = true -o:depends({ [_n("shadowtls")] = true, [_n("shadowtls_version")] = "2" }) -o:depends({ [_n("shadowtls")] = true, [_n("shadowtls_version")] = "3" }) - -o = s:option(Value, _n("shadowtls_serverName"), "ShadowTLS " .. translate("Domain")) -o:depends({ [_n("shadowtls")] = true }) - -if singbox_tags:find("with_utls") then - o = s:option(Flag, _n("shadowtls_utls"), "ShadowTLS " .. translate("uTLS")) - o.default = "0" - o:depends({ [_n("shadowtls")] = true }) - - o = s:option(ListValue, _n("shadowtls_fingerprint"), "ShadowTLS " .. translate("Finger Print")) - o:value("chrome") - o:value("firefox") - o:value("edge") - o:value("safari") - -- o:value("360") - o:value("qq") - o:value("ios") - -- o:value("android") - o:value("random") - -- o:value("randomized") - o.default = "chrome" - o:depends({ [_n("shadowtls")] = true, [_n("shadowtls_utls")] = true }) -end - --- [[ SIP003 plugin ]]-- -o = s:option(Flag, _n("plugin_enabled"), translate("plugin")) -o.default = 0 -o:depends({ [_n("protocol")] = "shadowsocks" }) - -o = s:option(ListValue, _n("plugin"), "SIP003 " .. translate("plugin")) -o.default = "obfs-local" -o:depends({ [_n("plugin_enabled")] = true }) -o:value("obfs-local") -o:value("v2ray-plugin") - -o = s:option(Value, _n("plugin_opts"), translate("opts")) -o:depends({ [_n("plugin_enabled")] = true }) - -o = s:option(ListValue, _n("domain_resolver"), translate("Domain DNS Resolve")) -o.description = translate("If the node address is a domain name, this DNS will be used for resolution.") .. "
" .. string.format('%s', - translate("Note: For node-specific DNS only. Keep Auto to avoid extra overhead.")) -o:value("", translate("Auto")) -o:value("tcp", "TCP") -o:value("udp", "UDP") -o:value("https", "DoH") - -o = s:option(Value, _n("domain_resolver_dns"), "DNS") -o.datatype = "or(ipaddr,ipaddrport)" -o:value("114.114.114.114") -o:value("223.5.5.5:53") -o.default = o.keylist[1] -o:depends({ [_n("domain_resolver")] = "tcp" }) -o:depends({ [_n("domain_resolver")] = "udp" }) - -o = s:option(Value, _n("domain_resolver_dns_https"), "DNS") -o:value("https://120.53.53.53/dns-query", "DNSPod") -o:value("https://223.5.5.5/dns-query", "AliDNS") -o.default = o.keylist[1] -o:depends({ [_n("domain_resolver")] = "https" }) - -o = s:option(ListValue, _n("domain_strategy"), translate("Domain Strategy"), translate("If is domain name, The requested domain name will be resolved to IP before connect.")) -o.default = "" -o:value("", translate("Auto")) -o:value("prefer_ipv4", translate("Prefer IPv4")) -o:value("prefer_ipv6", translate("Prefer IPv6")) -o:value("ipv4_only", translate("IPv4 Only")) -o:value("ipv6_only", translate("IPv6 Only")) - - -local protocols = s.fields[_n("protocol")].keylist -if #protocols > 0 then - for i, v in ipairs(protocols) do - if not v:find("^_") then - local depends_condition = { [_n("protocol")] = v } - if v == "hysteria2" then - depends_condition[_n("hysteria2_realms")] = false - end - s.fields[_n("address")]:depends(depends_condition) - s.fields[_n("port")]:depends(depends_condition) - s.fields[_n("domain_resolver")]:depends(depends_condition) - s.fields[_n("domain_strategy")]:depends(depends_condition) - end - end -end -end --- [[ Normal single node End ]] - -if not load_shunt_options then - o = s:option(ListValue, _n("chain_proxy"), translate("Chain Proxy")) - o:value("", translate("Close(Not use)")) - if not (load_iface_options or load_urltest_options) then - -- Special node cannot be use pre-proxy. - o:value("1", translate("Preproxy Node")) - o:value("3", translate("Outbound Interface")) - end - o:value("2", translate("Landing Node")) - - o1 = s:option(ListValue, _n("preproxy_node"), translate("Preproxy Node"), translate("Only support a layer of proxy.")) - o1:depends({ [_n("chain_proxy")] = "1", [_n("hysteria2_realms")] = false }) - o1.template = m:template_path("/cbi/nodes_listvalue") - o1.group = {} - - o3 = s:option(Value, _n("outbound_iface"), translate("Outbound Interface")) - o3:depends({ [_n("chain_proxy")] = "3" }) - o3:value("", translate("All")) - for _, d in ipairs(netdev_list) do - o3:value(d.name, d.label) - end - - o2 = s:option(ListValue, _n("to_node"), translate("Landing Node"), translate("Only support a layer of proxy.")) - o2:depends({ [_n("chain_proxy")] = "2", [_n("hysteria2_realms")] = false }) - o2.template = m:template_path("/cbi/nodes_listvalue") - o2.group = {} - - for k1, v1 in pairs(node_list) do - if k1 ~= "shunt_list" and k1 ~= "iface_list" then - for i, v in ipairs(v1) do - if v.id ~= arg[1] then - o1:value(v.id, v.remark) - o1.group[#o1.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - if k1 == "normal_list" then - -- Landing Node not support use special node. - o2:value(v.id, v.remark) - o2.group[#o2.group+1] = (v.group and v.group ~= "") and v.group or translate("default") - end - end - end - end - end -end - -api.luci_types(arg[1], m, s, type_name, option_prefix) - -if load_shunt_options then - local current_node = m:get(arg[1]) or {} - local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua") - setfenv(shunt_lua, getfenv(1))(m, s, { - node_id = arg[1], - node = current_node, - node_list = node_list, - }) -end diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss-rust.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss-rust.lua deleted file mode 100644 index 36cd9bca..00000000 --- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/ss-rust.lua +++ /dev/null @@ -1,76 +0,0 @@ -local m, s = ... - -if not api.is_finded("sslocal") then - return -end - -type_name = "SS-Rust" - --- [[ Shadowsocks Rust ]] - -s.fields["type"]:value(type_name, "Shadowsocks Rust") - -if s.val["type"] ~= type_name then - return -end - -local option_prefix = "ssrust_" - -local function _n(name) - return option_prefix .. name -end - -local ssrust_encrypt_method_list = { - "none", "plain", - "aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", - "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" -} - -o = s:option(ListValue, _n("del_protocol")) --始终隐藏,用于删除 protocol -o:depends({ [_n("__hide")] = "1" }) -o.rewrite_option = "protocol" - -o = s:option(Value, _n("address"), translate("Address (Support Domain Name)")) - -o = s:option(Value, _n("port"), translate("Port")) -o.datatype = "port" - -o = s:option(Value, _n("password"), translate("Password")) -o.password = true - -o = s:option(Value, _n("method"), translate("Encrypt Method")) -for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end - -o = s:option(Value, _n("timeout"), translate("Connection Timeout")) -o.datatype = "uinteger" -o.default = 300 - -o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open"), translate("Need node support required")) -o.default = 0 - -o = s:option(Flag, _n("plugin_enabled"), translate("plugin")) -o.default = 0 - -o = s:option(Value, _n("plugin"), "SIP003 " .. translate("plugin"), translate("Supports custom SIP003 plugins, Make sure the plugin is installed.")) -o.default = "none" -o:value("none", translate("none")) -if api.is_finded("xray-plugin") then o:value("xray-plugin") end -if api.is_finded("v2ray-plugin") then o:value("v2ray-plugin") end -if api.is_finded("obfs-local") then o:value("obfs-local") end -if api.is_finded("shadow-tls") then o:value("shadow-tls") end -o:depends({ [_n("plugin_enabled")] = true }) -o.validate = function(self, value, t) - if value and value ~= "" and value ~= "none" then - if not api.is_finded(value) then - return nil, value .. ": " .. translate("Can't find this file!") - else - return value - end - end - return nil -end - -o = s:option(Value, _n("plugin_opts"), translate("opts")) -o:depends({ [_n("plugin_enabled")] = true }) - -api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/server_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/server_config.lua index bb556c6b..bd7d2e48 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/server_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/server_config.lua @@ -17,7 +17,7 @@ m:foreach("user", function(s) user_list[#user_list + 1] = s end) -s = m:section(NamedSection, arg[1], "server", translate("Server Config")) +local s = m:section(NamedSection, arg[1], "server", translate("Server Config")) s.addremove = false s.dynamic = false @@ -39,8 +39,6 @@ for filename in api.fs.dir(types_dir) do table.insert(type_table, filename) end table.sort(type_table, function(a, b) - if a == "socks.lua" then return true end - if b == "socks.lua" then return false end return a < b end) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/0_socks.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/0_socks.lua new file mode 100644 index 00000000..eb32702a --- /dev/null +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/0_socks.lua @@ -0,0 +1,36 @@ +if not api.is_finded("microsocks") then + return +end + +-- [[ microsocks ]] +local m, s1 = ... +local type_name = "Socks" + +s1.fields["type"]:value(type_name, "Socks") +if not s1.fields["type"].default then + s1.fields["type"].default = type_name +end + +if s1.val["type"] and s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "socks_" + +o = s:option(Value, "port", translate("Listen Port")) +o.datatype = "port" + +o = s:option(Flag, "auth", translate("Auth")) + +o = s:option(ListValue, "user", translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) +end +o:depends({ auth = true }) + +o = s:option(Flag, "log", translate("Log")) +o.default = "1" + +api.luci_types(s1, s) 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 new file mode 100644 index 00000000..47a4a249 --- /dev/null +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua @@ -0,0 +1,522 @@ +local singbox_bin = api.finded_com("sing-box") + +if not singbox_bin then + return +end + +-- [[ Sing-Box ]] +local m, s1 = ... +local type_name = "sing-box" + +s1.fields["type"]:value(type_name, "Sing-Box") +if not s1.fields["type"].default then + s1.fields["type"].default = type_name +end + +if not s1.val["type"] then + s1.val["type"] = type_name +end + +if s1.val["type"] and s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "singbox_" + +local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'") + +local ss_method_list = { + "none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", + "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" +} + +o = s:option(Flag, "custom", translate("Use Custom Config")) + +o = s:option(TextValue, "custom_config", translate("Custom Config") .. " (JSON)") +o.rows = 10 +o.wrap = "off" +o:depends({ custom = true }) +o.datatype = "json" +local o_validate = o.validate +o.validate = function(self, value) + local v = o_validate(self, value) + if v then return v end + return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value) or "") +end + +o = s:option(ListValue, "protocol", translate("Protocol")) +o:value("mixed", "Mixed") +o:value("socks", "Socks") +o:value("http", "HTTP") +o:value("shadowsocks", "Shadowsocks") +o:value("vmess", "Vmess") +o:value("vless", "VLESS") +o:value("trojan", "Trojan") +o:value("naive", "Naive") +if singbox_tags:find("with_quic") then + o:value("hysteria", "Hysteria") +end +if singbox_tags:find("with_quic") then + o:value("tuic", "TUIC") +end +if singbox_tags:find("with_quic") then + o:value("hysteria2", "Hysteria2") +end +o:value("anytls", "AnyTLS") +if singbox_tags:find("with_wireguard") then + o:value("wireguard", "WireGuard") +end +o:value("direct", "Direct") +o:depends({ custom = false }) + +o = s:option(Value, "port", translate("Listen Port")) +o.datatype = "port" +o:depends({ custom = false }) + +o = s:option(DynamicList, "users", translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) +end +o:depends({ protocol = "mixed" }) +o:depends({ protocol = "socks" }) +o:depends({ protocol = "http" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "trojan" }) +o:depends({ protocol = "naive" }) +o:depends({ protocol = "hysteria" }) +o:depends({ protocol = "tuic" }) +o:depends({ protocol = "hysteria2" }) +o:depends({ protocol = "anytls" }) +o:depends({ protocol = "wireguard" }) + +if singbox_tags:find("with_quic") then + o = s:option(Value, "hysteria_obfs", translate("Obfs Password")) + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_up_mbps", translate("Max upload Mbps")) + o.default = "100" + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_down_mbps", translate("Max download Mbps")) + o.default = "100" + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_recv_window_conn", translate("QUIC stream receive window")) + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_recv_window_client", translate("QUIC connection receive window")) + o:depends({ protocol = "hysteria" }) + + o = s:option(Value, "hysteria_max_conn_client", translate("QUIC concurrent bidirectional streams")) + o.default = "1024" + o:depends({ protocol = "hysteria" }) + + o = s:option(Flag, "hysteria_disable_mtu_discovery", translate("Disable MTU detection")) + o:depends({ protocol = "hysteria" }) +end + +if singbox_tags:find("with_quic") then + o = s:option(ListValue, "tuic_congestion_control", translate("Congestion control algorithm")) + o.default = "cubic" + o:value("bbr", translate("BBR")) + o:value("cubic", translate("CUBIC")) + o:value("new_reno", translate("New Reno")) + o:depends({ protocol = "tuic" }) + + o = s:option(Flag, "tuic_zero_rtt_handshake", translate("Enable 0-RTT QUIC handshake")) + o.default = 0 + o:depends({ protocol = "tuic" }) + + o = s:option(Value, "tuic_heartbeat", translate("Heartbeat interval(second)")) + o.datatype = "uinteger" + o.default = "3" + o:depends({ protocol = "tuic" }) + + o = s:option(ListValue, "tuic_alpn", translate("QUIC TLS ALPN")) + o.default = "default" + o:value("default", translate("Default")) + o:value("h3") + o:value("h2") + o:value("h3,h2") + o:value("http/1.1") + o:value("h2,http/1.1") + o:value("h3,h2,http/1.1") + o:value("spdy/3.1") + o:value("h3,spdy/3.1") + o:depends({ protocol = "tuic" }) +end + +if singbox_tags:find("with_quic") then + o = s:option(Flag, "hysteria2_realms", translate("Realms")) + o.default = "0" + o:depends({ protocol = "hysteria2"}) + + o = s:option(Value, "hysteria2_realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") + o:depends({ hysteria2_realms = "1" }) + o.validate = function(self, value) + value = api.trim(value) + local realm = api.parse_realm_uri(value) + if realm then return value end + return nil, translate("Invalid Realm URL.") + end + + o = s:option(DynamicList, "hysteria2_realm_stun", translate("Realm STUN")) + o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } + o:depends({ hysteria2_realms = "1" }) + + o = s:option(ListValue, "hysteria2_obfs_type", translate("Obfs Type")) + o:value("", translate("Disable")) + o:value("salamander") + o:value("gecko") + o:depends({ protocol = "hysteria2" }) + + o = s:option(Value, "hysteria2_obfs_password", translate("Obfs Password")) + o:depends({ hysteria2_obfs_type = "salamander" }) + o:depends({ hysteria2_obfs_type = "gecko" }) + + o = s:option(Value, "hysteria2_obfs_MinPacketSize", translate("Gecko Packet Size (min)")) + o.datatype = "uinteger" + o.placeholder = "512" + o.default = "512" + o:depends({ hysteria2_obfs_type = "gecko" }) + + o = s:option(Value, "hysteria2_obfs_MaxPacketSize", translate("Gecko Packet Size (max)")) + o.datatype = "uinteger" + o.placeholder = "1200" + o.default = "1200" + o:depends({ hysteria2_obfs_type = "gecko" }) + + o = s:option(Flag, "hysteria2_ignore_client_bandwidth", translate("Client BBR Flow Control"), translate("Commands the client to use the BBR flow control algorithm")) + o.default = 0 + o:depends({ protocol = "hysteria2" }) + + o = s:option(Value, "hysteria2_up_mbps", translate("Max upload Mbps")) + o:depends({ protocol = "hysteria2", hysteria2_ignore_client_bandwidth = false }) + + o = s:option(Value, "hysteria2_down_mbps", translate("Max download Mbps")) + o:depends({ protocol = "hysteria2", hysteria2_ignore_client_bandwidth = false }) +end + +o = s:option(ListValue, "d_protocol", translate("Destination protocol")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("tcp,udp", "TCP,UDP") +o:depends({ protocol = "direct" }) + +o = s:option(Value, "d_address", translate("Destination address")) +o:depends({ protocol = "direct" }) + +o = s:option(Value, "d_port", translate("Destination port")) +o.datatype = "port" +o:depends({ protocol = "direct" }) + +o = s:option(Value, "decryption", translate("Encrypt Method")) +o.default = "none" +o:depends({ protocol = "vless" }) + +o = s:option(ListValue, "ss_method", translate("Encrypt Method")) +o.rewrite_option = "method" +for a, t in ipairs(ss_method_list) do o:value(t) end +o:depends({ protocol = "shadowsocks" }) + +o = s:option(Value, "ss_password", translate("Password")) +o:depends({ protocol = "shadowsocks" }) + +o = s:option(ListValue, "flow", translate("flow")) +o.default = "" +o:value("", translate("Disable")) +o:value("xtls-rprx-vision") +o:depends({ protocol = "vless" , tls = true }) + +o = s:option(Flag, "tls", translate("TLS")) +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 + if reality and reality == "1" then return value end + if value == "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!") + end + end + return value + end +end +o:depends({ protocol = "http" }) +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "trojan" }) +o:depends({ protocol = "anytls" }) + +-- https://github.com/SagerNet/sing-box/commit/d2a04c4e41e6cef0937331cb6d10211f431caaab +if singbox_tags:find("with_utls") then + -- [[ REALITY部分 ]] -- + o = s:option(Flag, "reality", translate("REALITY")) + o.default = 0 + o:depends({ protocol = "http", tls = true }) + o:depends({ protocol = "vmess", tls = true }) + o:depends({ protocol = "vless", tls = true }) + o:depends({ protocol = "trojan", tls = true }) + o:depends({ protocol = "anytls", tls = true }) + + o = s:option(Value, "reality_private_key", translate("Private Key")) + o:depends({ reality = true }) + + o = s:option(Value, "reality_shortId", translate("Short Id")) + o:depends({ reality = true }) + + o = s:option(Value, "reality_handshake_server", translate("Handshake Server")) + o.default = "google.com" + o:depends({ reality = true }) + + o = s:option(Value, "reality_handshake_server_port", translate("Handshake Server Port")) + o.datatype = "port" + o.default = "443" + o:depends({ reality = true }) +end + +o = s:option(ListValue, "alpn", translate("ALPN")) +o.default = "default" +o:value("default", translate("Default")) +o:value("h3") +o:value("h2") +o:value("h3,h2") +o:value("http/1.1") +o:value("h2,http/1.1") +o:value("h3,h2,http/1.1") +o:depends({ tls = true, reality = false }) +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/" .. arg[1] .. ".pem" +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.validate = function(self, value, t) + if value and value ~= "" then + if not fs.access(value) then + return nil, translate("Can't find this file!") + else + return value + end + end + return nil +end + +o = s:option(FileUpload, "tls_keyFile", translate("Private key absolute path"), 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.validate = function(self, value, t) + if value and value ~= "" then + if not fs.access(value) then + return nil, translate("Can't find this file!") + else + return value + end + end + return nil +end + +o = s:option(Flag, "ech", translate("ECH")) +o.default = "0" +o:depends({ tls = true, flow = "", reality = false }) +o:depends({ protocol = "naive" }) +o:depends({ protocol = "hysteria" }) +o:depends({ protocol = "tuic" }) +o:depends({ protocol = "hysteria2", hysteria2_realms = false }) + +o = s:option(TextValue, "ech_key", translate("ECH Key")) +o.default = "" +o.rows = 5 +o.wrap = "off" +o:depends({ ech = true }) +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 +end + +o = s:option(ListValue, "transport", translate("Transport")) +o:value("tcp", "TCP") +o:value("http", "HTTP") +o:value("ws", "WebSocket") +o:value("httpupgrade", "HTTPUpgrade") +o:value("quic", "QUIC") +o:value("grpc", "gRPC") +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "trojan" }) + +-- [[ HTTP部分 ]]-- + +o = s:option(DynamicList, "http_host", translate("HTTP Host")) +o:depends({ transport = "http" }) + +o = s:option(Value, "http_path", translate("HTTP Path")) +o:depends({ transport = "http" }) + +-- [[ WebSocket部分 ]]-- + +o = s:option(Value, "ws_host", translate("WebSocket Host")) +o:depends({ transport = "ws" }) + +o = s:option(Value, "ws_path", translate("WebSocket Path")) +o:depends({ transport = "ws" }) + +-- [[ HTTPUpgrade部分 ]]-- + +o = s:option(Value, "httpupgrade_host", translate("HTTPUpgrade Host")) +o:depends({ transport = "httpupgrade" }) + +o = s:option(Value, "httpupgrade_path", translate("HTTPUpgrade Path")) +o:depends({ transport = "httpupgrade" }) + +-- [[ gRPC部分 ]]-- +o = s:option(Value, "grpc_serviceName", "ServiceName") +o:depends({ transport = "grpc" }) + +-- [[ Mux ]]-- +o = s:option(Flag, "mux", translate("Mux")) +o.rmempty = false +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless", flow = "" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "trojan" }) + +-- [[ TCP Brutal ]]-- +o = s:option(Flag, "tcpbrutal", translate("TCP Brutal")) +o.default = 0 +o:depends({ mux = true }) + +o = s:option(Value, "tcpbrutal_up_mbps", translate("Max upload Mbps")) +o.default = "10" +o:depends({ tcpbrutal = true }) + +o = s:option(Value, "tcpbrutal_down_mbps", translate("Max download Mbps")) +o.default = "50" +o:depends({ tcpbrutal = true }) + +if singbox_tags:find("with_wireguard") then + o = s:option(Flag, "wireguard_system_interface", translate("System interface")) + o.default = 0 + o:depends({ protocol = "wireguard" }) + + o = s:option(Value, "wireguard_mtu", "MTU") + o.default = "1408" + o:depends({ protocol = "wireguard" }) + + o = s:option(DynamicList, "wireguard_local_address", translate("Local Address")) + o:depends({ protocol = "wireguard" }) + + o = s:option(Value, "wireguard_private_key", translate("Private Key")) + o.datatype = "base64" + o:depends({ protocol = "wireguard" }) + + o = s:option(Value, "wireguard_public_key", translate("Public Key")) + o.datatype = "base64" + o:depends({ protocol = "wireguard" }) + + o = s:option(DummyValue, "gen_wireguard_key") + o.template = m:template_path("/server/gen_wireguard_key") + o:depends({ protocol = "wireguard" }) +end + +o = s:option(Flag, "bind_local", translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) +o.default = "0" +o:depends({ custom = false }) + +o = s:option(Flag, "accept_lan", translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) +o.default = "0" +o:depends({ custom = false }) + +local nodes_table = {} +for k, e in ipairs(api.get_valid_nodes()) do + if e.node_type == "normal" and e.type == type_name then + nodes_table[#nodes_table + 1] = { + id = e[".name"], + remarks = e["remark"], + group = e["group"] + } + end +end + +o = s:option(ListValue, "outbound_node", translate("outbound node")) +o:value("", translate("Close")) +o:value("_socks", translate("Custom Socks")) +o:value("_http", translate("Custom HTTP")) +o:value("_iface", translate("Custom Interface")) +o.template = m:template_path("/cbi/nodes_listvalue") +o.group = {"","","",""} +for k, v in pairs(nodes_table) do + o:value(v.id, v.remarks) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") +end +o:depends({ custom = false }) + +o = s:option(Value, "outbound_node_address", translate("Address (Support Domain Name)")) +o:depends({ outbound_node = "_socks" }) +o:depends({ outbound_node = "_http" }) + +o = s:option(Value, "outbound_node_port", translate("Port")) +o.datatype = "port" +o:depends({ outbound_node = "_socks" }) +o:depends({ outbound_node = "_http" }) + +o = s:option(Value, "outbound_node_username", translate("Username")) +o:depends({ outbound_node = "_socks" }) +o:depends({ outbound_node = "_http" }) + +o = s:option(Value, "outbound_node_password", translate("Password")) +o.password = true +o:depends({ outbound_node = "_socks" }) +o:depends({ outbound_node = "_http" }) + +o = s:option(Value, "outbound_node_iface", translate("Interface")) +o:depends({ outbound_node = "_iface" }) +local netdev_list = api.get_network_devices() +for _, d in ipairs(netdev_list) do + o:value(d.name, d.label) +end + +o = s:option(Flag, "log", translate("Log")) +o.default = "1" +o.rmempty = false + +o = s:option(ListValue, "loglevel", translate("Log Level")) +o.default = "info" +o:value("debug") +o:value("info") +o:value("warn") +o:value("error") +o:depends({ log = true }) + +api.luci_types(s1, s) 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 new file mode 100644 index 00000000..89363d00 --- /dev/null +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua @@ -0,0 +1,536 @@ +if not api.finded_com("xray") then + return +end + +-- [[ Xray ]] +local m, s1 = ... +local type_name = "Xray" + +s1.fields["type"]:value(type_name, "Xray") +if not s1.fields["type"].default then + s1.fields["type"].default = type_name +end + +if s1.val["type"] and s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "xray_" + +local ss_method_list = { + "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" +} + +local header_type_list = { + "none", "srtp", "utp", "wechat-video", "dtls", "wireguard", "dns" +} + +o = s:option(Flag, "custom", translate("Use Custom Config")) + +o = s:option(TextValue, "custom_config", translate("Custom Config") .. " (JSON)") +o.rows = 10 +o.wrap = "off" +o:depends({ custom = true }) +o.datatype = "json" +local o_validate = o.validate +o.validate = function(self, value) + local v = o_validate(self, value) + if v then return v end + return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value) or "") +end + +o = s:option(ListValue, "protocol", translate("Protocol")) +o:value("socks", "Socks") +o:value("http", "HTTP") +o:value("vmess", "Vmess") +o:value("vless", "VLESS") +o:value("shadowsocks", "Shadowsocks") +o:value("trojan", "Trojan") +o:value("hysteria2", "Hysteria2") +o:value("wireguard", "WireGuard") +o:value("dokodemo-door", "dokodemo-door") +o:depends({ custom = false }) + +o = s:option(Value, "port", translate("Listen Port")) +o.datatype = "port" +o:depends({ custom = false }) + + +o = s:option(DynamicList, "users", translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) +end +o:depends({ protocol = "http" }) +o:depends({ protocol = "socks" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "trojan" }) +o:depends({ protocol = "hysteria2" }) +o:depends({ protocol = "wireguard" }) + +o = s:option(ListValue, "d_protocol", translate("Destination protocol")) +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("tcp,udp", "TCP,UDP") +o:depends({ protocol = "dokodemo-door" }) + +o = s:option(Value, "d_address", translate("Destination address")) +o:depends({ protocol = "dokodemo-door" }) + +o = s:option(Value, "d_port", translate("Destination port")) +o.datatype = "port" +o:depends({ protocol = "dokodemo-door" }) + +o = s:option(Value, "decryption", translate("Encrypt Method") .. " (decryption)") +o.default = "none" +o.placeholder = "none" +o:depends({ protocol = "vless" }) +o.validate = function(self, value) + value = api.trim(value) + return (value == "" and "none" or value) +end + +o = s:option(ListValue, "ss_method", translate("Encrypt Method")) +o.rewrite_option = "method" +for a, t in ipairs(ss_method_list) do o:value(t) end +o:depends({ protocol = "shadowsocks" }) + +o = s:option(Value, "ss_password", translate("Password")) +o:depends({ protocol = "shadowsocks" }) + +o = s:option(ListValue, "ss_network", translate("Transport")) +o.default = "tcp,udp" +o:value("tcp", "TCP") +o:value("udp", "UDP") +o:value("tcp,udp", "TCP,UDP") +o:depends({ protocol = "shadowsocks" }) + +o = s:option(Flag, "udp_forward", translate("UDP Forward")) +o.default = "1" +o.rmempty = false +o:depends({ protocol = "socks" }) + +o = s:option(ListValue, "flow", translate("flow")) +o.default = "" +o:value("", translate("Disable")) +o:value("xtls-rprx-vision") +o:depends({ protocol = "vless" }) + +---- [[ hysteria2 ]] +o = s:option(Flag, "hysteria2_realms", translate("Realms")) +o.default = "0" +o:depends({ protocol = "hysteria2"}) + +o = s:option(Value, "hysteria2_realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") +o:depends({ hysteria2_realms = "1" }) +o.validate = function(self, value) + value = api.trim(value) + local realm = api.parse_realm_uri(value) + if realm then return value end + return nil, translate("Invalid Realm URL.") +end + +o = s:option(DynamicList, "hysteria2_realm_stun", translate("Realm STUN")) +o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } +o:depends({ hysteria2_realms = "1" }) + +o = s:option(ListValue, "hysteria2_obfs_type", translate("Obfs Type")) +o:value("", translate("Disable")) +o:value("salamander") +o:value("gecko") +o:depends({ protocol = "hysteria2" }) + +o = s:option(Value, "hysteria2_obfs_password", translate("Obfs Password")) +o:depends({ hysteria2_obfs_type = "salamander" }) +o:depends({ hysteria2_obfs_type = "gecko" }) + +o = s:option(Value, "hysteria2_obfs_MinPacketSize", translate("Gecko Packet Size (min)")) +o.datatype = "uinteger" +o.placeholder = "512" +o.default = "512" +o:depends({ hysteria2_obfs_type = "gecko" }) + +o = s:option(Value, "hysteria2_obfs_MaxPacketSize", translate("Gecko Packet Size (max)")) +o.datatype = "uinteger" +o.placeholder = "1200" +o.default = "1200" +o:depends({ hysteria2_obfs_type = "gecko" }) + +o = s:option(Flag, "hysteria2_ignore_client_bandwidth", translate("Client BBR Flow Control")) +o.default = 0 +o:depends({ protocol = "hysteria2" }) + +o = s:option(Value, "hysteria2_up_mbps", translate("Max upload Mbps")) +o:depends({ protocol = "hysteria2", hysteria2_ignore_client_bandwidth = false }) + +o = s:option(Value, "hysteria2_down_mbps", translate("Max download Mbps")) +o:depends({ protocol = "hysteria2", hysteria2_ignore_client_bandwidth = false }) + +---- [[ TLS ]] +o = s:option(Flag, "tls", translate("TLS")) +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 + if reality and reality == "1" then return value end + if value == "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!") + end + end + return value + end +end +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "trojan" }) + +-- [[ REALITY部分 ]] -- +o = s:option(Flag, "reality", translate("REALITY")) +o.default = 0 +o:depends({ tls = true }) + +o = s:option(Value, "reality_private_key", translate("Private Key")) +o:depends({ reality = true }) + +o = s:option(DynamicList, "reality_shortId", translate("Short Id")) +o:depends({ reality = true }) + +o = s:option(Value, "reality_dest", translate("Dest")) +o.default = "google.com:443" +o:depends({ reality = true }) + +o = s:option(DynamicList, "reality_serverNames", translate("serverNames")) +o:depends({ reality = true }) + +o = s:option(ListValue, "alpn", translate("alpn")) +o.default = "default" +o:value("default", translate("Default")) +o:value("h3") +o:value("h2") +o:value("h3,h2") +o:value("http/1.1") +o:value("h2,http/1.1") +o:value("h3,h2,http/1.1") +o:depends({ tls = true, reality = false }) + +o = s:option(Flag, "use_mldsa65Seed", translate("ML-DSA-65")) +o.default = "0" +o:depends({ reality = true }) + +o = s:option(TextValue, "reality_mldsa65Seed", "ML-DSA-65 " .. translate("Private Key")) +o.default = "" +o.rows = 5 +o.wrap = "soft" +o:depends({ use_mldsa65Seed = true }) +o.validate = function(self, value) + return api.trim(value:gsub("[\r\n]", "")) +end + +-- o = s:option(Value, "minversion", translate("minversion")) +-- o.default = "1.3" +-- o:value("1.3") +--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/" .. arg[1] .. ".pem" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end +o:depends({ tls = true, reality = false }) +o:depends({ protocol = "hysteria2"}) +o.validate = function(self, value, t) + if value and value ~= "" then + if not fs.access(value) then + return nil, translate("Can't find this file!") + else + return value + end + end + return nil +end + +o = s:option(FileUpload, "tls_keyFile", translate("Private key absolute path"), 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 = "hysteria2"}) +o.validate = function(self, value, t) + if value and value ~= "" then + if not fs.access(value) then + return nil, translate("Can't find this file!") + else + return value + end + end + return nil +end + +o = s:option(Flag, "ech", translate("ECH")) +o.default = "0" +o:depends({ tls = true, reality = false }) + +o = s:option(TextValue, "ech_key", translate("ECH Key")) +o.default = "" +o.rows = 5 +o.wrap = "soft" +o:depends({ ech = true }) +o.validate = function(self, value) + return api.trim(value:gsub("[\r\n]", "")) +end + +o = s:option(ListValue, "transport", translate("Transport")) +o:value("raw", "RAW") +o:value("mkcp", "mKCP") +o:value("ws", "WebSocket") +o:value("grpc", "gRPC") +o:value("httpupgrade", "HttpUpgrade") +o:value("xhttp", "XHTTP") +o:depends({ protocol = "vmess" }) +o:depends({ protocol = "vless" }) +o:depends({ protocol = "shadowsocks" }) +o:depends({ protocol = "trojan" }) + +-- [[ WebSocket部分 ]]-- + +o = s:option(Value, "ws_host", translate("WebSocket Host")) +o:depends({ transport = "ws" }) + +o = s:option(Value, "ws_path", translate("WebSocket Path")) +o:depends({ transport = "ws" }) + +-- [[ HttpUpgrade部分 ]]-- +o = s:option(Value, "httpupgrade_host", translate("HttpUpgrade Host")) +o:depends({ transport = "httpupgrade" }) + +o = s:option(Value, "httpupgrade_path", translate("HttpUpgrade Path")) +o.placeholder = "/" +o:depends({ transport = "httpupgrade" }) + +-- [[ XHTTP部分 ]]-- +o = s:option(Value, "xhttp_host", translate("XHTTP Host")) +o:depends({ transport = "xhttp" }) + +o = s:option(Value, "xhttp_path", translate("XHTTP Path")) +o.placeholder = "/" +o:depends({ transport = "xhttp" }) + +o = s:option(Value, "xhttp_maxuploadsize", translate("maxUploadSize")) +o.default = "1000000" +o:depends({ transport = "xhttp" }) + +o = s:option(Value, "xhttp_maxconcurrentuploads", translate("maxConcurrentUploads")) +o.default = "10" +o:depends({ transport = "xhttp" }) + +-- [[ TCP部分 ]]-- + +-- TCP伪装 +o = s:option(ListValue, "tcp_guise", translate("Camouflage Type")) +o:value("none", "none") +o:value("http", "http") +o:depends({ transport = "raw" }) + +-- HTTP域名 +o = s:option(DynamicList, "tcp_guise_http_host", translate("HTTP Host")) +o:depends({ tcp_guise = "http" }) + +-- HTTP路径 +o = s:option(DynamicList, "tcp_guise_http_path", translate("HTTP Path")) +o:depends({ tcp_guise = "http" }) + +-- [[ mKCP部分 ]]-- + +o = s:option(ListValue, "mkcp_guise", translate("Camouflage Type"), translate('
none: default, no masquerade, data sent is packets with no characteristics.
srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).
utp: packets disguised as uTP will be recognized as bittorrent downloaded data.
wechat-video: packets disguised as WeChat video calls.
dtls: disguised as DTLS 1.2 packet.
wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)
dns: Disguising traffic as DNS requests.')) +for a, t in ipairs(header_type_list) do o:value(t) end +o:depends({ transport = "mkcp" }) + +o = s:option(Value, "mkcp_domain", translate("Camouflage Domain"), translate("Use it together with the DNS disguised type. You can fill in any domain.")) +o:depends({ mkcp_guise = "dns" }) + +o = s:option(Value, "mkcp_mtu", translate("KCP MTU")) +o.datatype = "uinteger" +o.default = 1350 +o:depends({ transport = "mkcp" }) + +o = s:option(Value, "mkcp_seed", translate("KCP Seed")) +o:depends({ transport = "mkcp" }) + +-- [[ gRPC部分 ]]-- +o = s:option(Value, "grpc_serviceName", "ServiceName") +o:depends({ transport = "grpc" }) + +--[[FinalMask]] +o = s:option(Flag, "use_finalmask", "FinalMask") +o.default = "0" +o:depends({ custom = false, protocol = "vmess" }) +o:depends({ custom = false, protocol = "vless" }) +o:depends({ custom = false, protocol = "trojan" }) +o:depends({ custom = false, protocol = "shadowsocks" }) +o:depends({ custom = false, protocol = "hysteria2", hysteria2_realms = false }) + +o = s:option(TextValue, "finalmask", "FinalMask JSON") +o:depends({ use_finalmask = true }) +o.rows = 10 +o.wrap = "off" +o.datatype = "json" +o.custom_cfgvalue = function(self, section, value) + local raw = m:get(section, "finalmask") + if raw then + return api.base64Decode(raw) + end +end +o.custom_write = function(self, section, value) + m:set(section, "finalmask", api.base64Encode(value) or "") +end + +--[[acceptProxyProtocol]] +o = s:option(Flag, "acceptProxyProtocol", translate("acceptProxyProtocol"), translate("Whether to receive PROXY protocol, when this node want to be fallback or forwarded by proxy, it must be enable, otherwise it cannot be used.")) +o.default = "0" +o:depends({ custom = false }) + +--[[Fast Open]] +o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open")) +o.default = "0" +o:depends({ protocol = "vmess", custom = false }) +o:depends({ protocol = "vless", custom = false }) +o:depends({ protocol = "shadowsocks", custom = false }) +o:depends({ protocol = "trojan", custom = false }) + +-- [[ Fallback部分 ]]-- +o = s:option(Flag, "fallback", translate("Fallback")) +o:depends({ protocol = "vless", transport = "raw" }) +o:depends({ protocol = "trojan", transport = "raw" }) + +--[[ +o = s:option(Value, "fallback_alpn", "Fallback alpn") +o:depends({ fallback = true }) + +o = s:option(Value, "fallback_path", "Fallback path") +o:depends({ fallback = true }) + +o = s:option(Value, "fallback_dest", "Fallback dest") +o:depends({ fallback = true }) + +o = s:option(Value, "fallback_xver", "Fallback xver") +o.default = 0 +o:depends({ fallback = true }) +]]-- + +o = s:option(DynamicList, "fallback_list", "Fallback", translate("format: dest,path,xver")) +o:depends({ fallback = true }) + +-- Not supported at present +--[[ +o = s:option(Flag, "wireguard_system_interface", translate("System interface")) +o.default = 0 +o:depends({ protocol = "wireguard" }) +]]-- + +o = s:option(Value, "wireguard_mtu", "MTU") +o.default = "1420" +o:depends({ protocol = "wireguard" }) + +-- Not supported at present +--[[ +o = s:option(DynamicList, "wireguard_local_address", translate("Local Address")) +o:depends({ protocol = "wireguard" }) +]]-- + +o = s:option(Value, "wireguard_private_key", translate("Private Key")) +o.datatype = "base64" +o:depends({ protocol = "wireguard" }) + +o = s:option(Value, "wireguard_public_key", translate("Public Key")) +o.datatype = "base64" +o:depends({ protocol = "wireguard" }) + +o = s:option(DummyValue, "gen_wireguard_key") +o.template = m:template_path("/server/gen_wireguard_key") +o:depends({ protocol = "wireguard" }) + +o = s:option(Flag, "bind_local", translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) +o.default = "0" +o:depends({ custom = false }) + +o = s:option(Flag, "accept_lan", translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) +o.default = "0" +o:depends({ custom = false }) + +local nodes_table = {} +for k, e in ipairs(api.get_valid_nodes()) do + if e.node_type == "normal" and e.type == type_name then + nodes_table[#nodes_table + 1] = { + id = e[".name"], + remarks = e["remark"], + group = e["group"] + } + end +end + +o = s:option(ListValue, "outbound_node", translate("outbound node")) +o:value("", translate("Close")) +o:value("_socks", translate("Custom Socks")) +o:value("_http", translate("Custom HTTP")) +o:value("_iface", translate("Custom Interface")) +o.template = m:template_path("/cbi/nodes_listvalue") +o.group = {"","","",""} +for k, v in pairs(nodes_table) do + o:value(v.id, v.remarks) + o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") +end +o:depends({ custom = false }) + +o = s:option(Value, "outbound_node_address", translate("Address (Support Domain Name)")) +o:depends({ outbound_node = "_socks"}) +o:depends({ outbound_node = "_http"}) + +o = s:option(Value, "outbound_node_port", translate("Port")) +o.datatype = "port" +o:depends({ outbound_node = "_socks"}) +o:depends({ outbound_node = "_http"}) + +o = s:option(Value, "outbound_node_username", translate("Username")) +o:depends({ outbound_node = "_socks"}) +o:depends({ outbound_node = "_http"}) + +o = s:option(Value, "outbound_node_password", translate("Password")) +o.password = true +o:depends({ outbound_node = "_socks"}) +o:depends({ outbound_node = "_http"}) + +o = s:option(Value, "outbound_node_iface", translate("Interface")) +o:depends({ outbound_node = "_iface"}) +local netdev_list = api.get_network_devices() +for _, d in ipairs(netdev_list) do + o:value(d.name, d.label) +end + +o = s:option(Flag, "log", translate("Log")) +o.default = "1" +o.rmempty = false + +o = s:option(ListValue, "loglevel", translate("Log Level")) +o.default = "warning" +o:value("debug") +o:value("info") +o:value("warning") +o:value("error") +o:depends({ log = true }) + +api.luci_types(s1, s) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/3_ss-rust.lua similarity index 50% rename from luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua rename to luci-app-passwall/luasrc/model/cbi/passwall/server/type/3_ss-rust.lua index 7ac9f03c..40af02de 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ss-rust.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/3_ss-rust.lua @@ -1,79 +1,79 @@ -local m, s = ... - -if not api.is_finded("ssserver") then - return -end - -local type_name = "SS-Rust" - --- [[ Shadowsocks Rust ]] - -s.fields["type"]:value(type_name, translate("Shadowsocks Rust")) - -if s.val["type"] and s.val["type"] ~= type_name then - return -end - -local option_prefix = "ssrust_" - -local function _n(name) - return option_prefix .. name -end - -local ssrust_encrypt_method_list = { - "plain", "none", - "aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", - "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" -} - -o = s:option(Flag, _n("custom"), translate("Use Custom Config")) - -o = s:option(Value, _n("port"), translate("Listen Port")) -o.datatype = "port" -o:depends({ [_n("custom")] = false }) - -o = s:option(ListValue, _n("user"), translate("User")) -for i, v in ipairs(user_list) do - o:value(v[".name"], v.username) -end -o:depends({ [_n("custom")] = false }) - -o = s:option(ListValue, _n("method"), translate("Encrypt Method")) -for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("timeout"), translate("Connection Timeout")) -o.datatype = "uinteger" -o.default = 300 -o:depends({ [_n("custom")] = false }) - -o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open")) -o.default = "0" -o:depends({ [_n("custom")] = false }) - -o = s:option(TextValue, _n("custom_config"), translate("Custom Config") .. " (JSON)") -o.rows = 10 -o.wrap = "off" -o:depends({ [_n("custom")] = true }) -o.datatype = "json" -local o_validate = o.validate -o.validate = function(self, value) - local v = o_validate(self, value) - if v then return v end - return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") -end -o.custom_cfgvalue = function(self, section, value) - local config_str = m:get(section, "config_str") - if config_str then - return api.base64Decode(config_str) - end -end -o.custom_write = function(self, section, value) - m:set(section, "config_str", api.base64Encode(value) or "") -end - -o = s:option(Flag, _n("log"), translate("Log")) -o.default = "1" -o.rmempty = false - -api.luci_types(arg[1], m, s, type_name, option_prefix) +if not api.is_finded("ssserver") then + return +end + +-- [[ Shadowsocks Rust ]] +local m, s1 = ... +local type_name = "SS-Rust" + +s1.fields["type"]:value(type_name, translate("Shadowsocks Rust")) + +if not s1.val["type"] then + s1.val["type"] = type_name +end + +if s1.val["type"] and s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "ssrust_" + +local ssrust_encrypt_method_list = { + "plain", "none", + "aes-128-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", + "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" +} + +o = s:option(Flag, "custom", translate("Use Custom Config")) + +o = s:option(TextValue, "custom_config", translate("Custom Config") .. " (JSON)") +o.rows = 10 +o.wrap = "off" +o:depends({ custom = true }) +o.datatype = "json" +local o_validate = o.validate +o.validate = function(self, value) + local v = o_validate(self, value) + if v then return v end + return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value) or "") +end + +o = s:option(Value, "port", translate("Listen Port")) +o.datatype = "port" +o:depends({ custom = false }) + +o = s:option(ListValue, "user", translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) +end +o:depends({ custom = false }) + +o = s:option(ListValue, "method", translate("Encrypt Method")) +for a, t in ipairs(ssrust_encrypt_method_list) do o:value(t) end +o:depends({ custom = false }) + +o = s:option(Value, "timeout", translate("Connection Timeout")) +o.datatype = "uinteger" +o.default = 300 +o:depends({ custom = false }) + +o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open")) +o.default = "0" +o:depends({ custom = false }) + +o = s:option(Flag, "log", translate("Log")) +o.default = "1" +o.rmempty = false + +api.luci_types(s1, s) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/4_ssr.lua similarity index 53% rename from luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua rename to luci-app-passwall/luasrc/model/cbi/passwall/server/type/4_ssr.lua index d1db102f..f7409233 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ssr.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/4_ssr.lua @@ -1,110 +1,110 @@ -local m, s = ... - -if not api.is_finded("ssr-server") then - return -end - -local type_name = "SSR" - --- [[ ShadowsocksR ]] - -s.fields["type"]:value(type_name, translate("ShadowsocksR")) - -if s.val["type"] and s.val["type"] ~= type_name then - return -end - -local option_prefix = "ssr_" - -local function _n(name) - return option_prefix .. name -end - -local ssr_encrypt_method_list = { - "none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb", - "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", - "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", - "cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20", - "chacha20-ietf" -} - -local ssr_protocol_list = { - "origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple", - "auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5", - "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", - "auth_chain_d", "auth_chain_e", "auth_chain_f" -} -local ssr_obfs_list = { - "plain", "http_simple", "http_post", "random_head", "tls_simple", - "tls1.0_session_auth", "tls1.2_ticket_auth" -} - -o = s:option(Flag, _n("custom"), translate("Use Custom Config")) - -o = s:option(Value, _n("port"), translate("Listen Port")) -o.datatype = "port" -o:depends({ [_n("custom")] = false }) - -o = s:option(ListValue, _n("user"), translate("User")) -for i, v in ipairs(user_list) do - o:value(v[".name"], v.username) -end -o:depends({ [_n("custom")] = false }) - -o = s:option(ListValue, _n("method"), translate("Encrypt Method")) -for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end -o:depends({ [_n("custom")] = false }) - -o = s:option(ListValue, _n("protocol"), translate("Protocol")) -for a, t in ipairs(ssr_protocol_list) do o:value(t) end -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("protocol_param"), translate("Protocol_param")) -o:depends({ [_n("custom")] = false }) - -o = s:option(ListValue, _n("obfs"), translate("Obfs")) -for a, t in ipairs(ssr_obfs_list) do o:value(t) end -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("obfs_param"), translate("Obfs_param")) -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("timeout"), translate("Connection Timeout")) -o.datatype = "uinteger" -o.default = 300 -o:depends({ [_n("custom")] = false }) - -o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open")) -o.default = "0" -o:depends({ [_n("custom")] = false }) - -o = s:option(TextValue, _n("custom_config"), translate("Custom Config") .. " (JSON)") -o.rows = 10 -o.wrap = "off" -o:depends({ [_n("custom")] = true }) -o.datatype = "json" -local o_validate = o.validate -o.validate = function(self, value) - local v = o_validate(self, value) - if v then return v end - return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") -end -o.custom_cfgvalue = function(self, section, value) - local config_str = m:get(section, "config_str") - if config_str then - return api.base64Decode(config_str) - end -end -o.custom_write = function(self, section, value) - m:set(section, "config_str", api.base64Encode(value) or "") -end - -o = s:option(Flag, _n("udp_forward"), translate("UDP Forward")) -o.default = "1" -o.rmempty = false - -o = s:option(Flag, _n("log"), translate("Log")) -o.default = "1" -o.rmempty = false - -api.luci_types(arg[1], m, s, type_name, option_prefix) +if not api.is_finded("ssr-server") then + return +end + +-- [[ ShadowsocksR ]] +local m, s1 = ... +local type_name = "SSR" + +s1.fields["type"]:value(type_name, translate("ShadowsocksR")) + +if not s1.val["type"] then + s1.val["type"] = type_name +end + +if s1.val["type"] and s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "ssr_" + +local ssr_encrypt_method_list = { + "none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb", + "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", + "bf-cfb", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", + "cast5-cfb", "des-cfb", "idea-cfb", "seed-cfb", "salsa20", "chacha20", + "chacha20-ietf" +} + +local ssr_protocol_list = { + "origin", "verify_simple", "verify_deflate", "verify_sha1", "auth_simple", + "auth_sha1", "auth_sha1_v2", "auth_sha1_v4", "auth_aes128_md5", + "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", + "auth_chain_d", "auth_chain_e", "auth_chain_f" +} +local ssr_obfs_list = { + "plain", "http_simple", "http_post", "random_head", "tls_simple", + "tls1.0_session_auth", "tls1.2_ticket_auth" +} + +o = s:option(Flag, "custom", translate("Use Custom Config")) + +o = s:option(TextValue, "custom_config", translate("Custom Config") .. " (JSON)") +o.rows = 10 +o.wrap = "off" +o:depends({ custom = true }) +o.datatype = "json" +local o_validate = o.validate +o.validate = function(self, value) + local v = o_validate(self, value) + if v then return v end + return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value) or "") +end + +o = s:option(Value, "port", translate("Listen Port")) +o.datatype = "port" +o:depends({ custom = false }) + +o = s:option(ListValue, "user", translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) +end +o:depends({ custom = false }) + +o = s:option(ListValue, "method", translate("Encrypt Method")) +for a, t in ipairs(ssr_encrypt_method_list) do o:value(t) end +o:depends({ custom = false }) + +o = s:option(ListValue, "protocol", translate("Protocol")) +for a, t in ipairs(ssr_protocol_list) do o:value(t) end +o:depends({ custom = false }) + +o = s:option(Value, "protocol_param", translate("Protocol_param")) +o:depends({ custom = false }) + +o = s:option(ListValue, "obfs", translate("Obfs")) +for a, t in ipairs(ssr_obfs_list) do o:value(t) end +o:depends({ custom = false }) + +o = s:option(Value, "obfs_param", translate("Obfs_param")) +o:depends({ custom = false }) + +o = s:option(Value, "timeout", translate("Connection Timeout")) +o.datatype = "uinteger" +o.default = 300 +o:depends({ custom = false }) + +o = s:option(Flag, "tcp_fast_open", "TCP " .. translate("Fast Open")) +o.default = "0" +o:depends({ custom = false }) + +o = s:option(Flag, "udp_forward", translate("UDP Forward")) +o.default = "1" +o.rmempty = false + +o = s:option(Flag, "log", translate("Log")) +o.default = "1" +o.rmempty = false + +api.luci_types(s1, s) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/5_hysteria2.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/5_hysteria2.lua new file mode 100644 index 00000000..3ba46043 --- /dev/null +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/5_hysteria2.lua @@ -0,0 +1,154 @@ +if not api.finded_com("hysteria") then + return +end + +-- [[ Hysteria2 ]] +local m, s1 = ... +local type_name = "Hysteria2" + +s1.fields["type"]:value(type_name, "Hysteria2") + +if s1.val["type"] and s1.val["type"] ~= type_name then + return +end + +local s = NamedSection(m, arg[1], "server") +s.type_name = type_name +s.option_prefix = "hysteria2_" + +local function _n(name) + return s.option_prefix .. name +end + +o = s:option(Flag, "custom", translate("Use Custom Config")) + +o = s:option(TextValue, "custom_config", translate("Custom Config")) +o.rows = 10 +o.wrap = "off" +o:depends({ custom = true }) +o.datatype = "json" +local o_validate = o.validate +o.validate = function(self, value) + local v = o_validate(self, value) + if v then return v end + return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") +end +o.custom_cfgvalue = function(self, section, value) + local config_str = m:get(section, "config_str") + if config_str then + return api.base64Decode(config_str) + end +end +o.custom_write = function(self, section, value) + m:set(section, "config_str", api.base64Encode(value) or "") +end + +o = s:option(Value, "port", translate("Listen Port")) +o.datatype = "port" +o:depends({ custom = false }) + +o = s:option(DynamicList, "users", translate("User")) +for i, v in ipairs(user_list) do + o:value(v[".name"], v.username) +end +o:depends({ custom = false }) + +o = s:option(Flag, "realms", translate("Realms")) +o.default = "0" +o.rewrite_option = _n(o.option) +o:depends({ custom = false }) + +o = s:option(Value, "realm_url", translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") +o.rewrite_option = _n(o.option) +o:depends({ realms = "1" }) +o.validate = function(self, value) + value = api.trim(value) + local realm = api.parse_realm_uri(value) + if realm then return value end + return nil, translate("Invalid Realm URL.") +end + +o = s:option(DynamicList, "realm_stun", translate("Realm STUN")) +o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } +o.rewrite_option = _n(o.option) +o:depends({ realms = "1" }) + +o = s:option(ListValue, "obfs_type", translate("Obfs Type")) +o:value("", translate("Disable")) +o:value("salamander") +o:value("gecko") +o.rewrite_option = _n(o.option) +o:depends({ custom = false }) + +o = s:option(Value, "obfs_password", translate("Obfs Password")) +o.rewrite_option = _n(o.option) +o:depends({ obfs_type = "salamander" }) +o:depends({ obfs_type = "gecko" }) + +o = s:option(Value, "obfs_MinPacketSize", translate("Gecko Packet Size (min)")) +o.datatype = "uinteger" +o.placeholder = "512" +o.default = "512" +o:depends({ obfs_type = "gecko" }) +o.rewrite_option = _n(o.option) + +o = s:option(Value, "obfs_MaxPacketSize", translate("Gecko Packet Size (max)")) +o.datatype = "uinteger" +o.placeholder = "1200" +o.default = "1200" +o:depends({ obfs_type = "gecko" }) +o.rewrite_option = _n(o.option) + +o = s:option(Flag, "udp", translate("UDP")) +o.default = "1" +o.rewrite_option = _n(o.option) +o:depends({ custom = false }) + +o = s:option(Value, "up_mbps", translate("Max upload Mbps")) +o.rewrite_option = _n(o.option) +o:depends({ custom = false }) + +o = s:option(Value, "down_mbps", translate("Max download Mbps")) +o.rewrite_option = _n(o.option) +o:depends({ custom = false }) + +o = s:option(Flag, "ignoreClientBandwidth", translate("ignoreClientBandwidth")) +o.default = "0" +o.rewrite_option = _n(o.option) +o:depends({ custom = false }) + +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/" .. arg[1] .. ".pem" +if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end +o.validate = function(self, value, t) + if value and value ~= "" then + if not api.fs.access(value) then + return nil, translate("Can't find this file!") + else + return value + end + end + return nil +end +o:depends({ custom = false }) + +o = s:option(FileUpload, "tls_keyFile", translate("Private key absolute path"), 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.validate = function(self, value, t) + if value and value ~= "" then + if not api.fs.access(value) then + return nil, translate("Can't find this file!") + else + return value + end + end + return nil +end +o:depends({ custom = false }) + +o = s:option(Flag, "log", translate("Log")) +o.default = "1" +o.rmempty = false + +api.luci_types(s1, s) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua deleted file mode 100644 index 7e02c51b..00000000 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/hysteria2.lua +++ /dev/null @@ -1,156 +0,0 @@ -local m, s = ... - -if not api.finded_com("hysteria") then - return -end - -local fs = api.fs - -local type_name = "Hysteria2" - --- [[ Hysteria2 ]] - -s.fields["type"]:value(type_name, "Hysteria2") - -if s.val["type"] and s.val["type"] ~= type_name then - return -end - -local option_prefix = "hysteria2_" - -local function _n(name) - return option_prefix .. name -end - -o = s:option(Flag, _n("custom"), translate("Use Custom Config")) - -o = s:option(Value, _n("port"), translate("Listen Port")) -o.datatype = "port" -o:depends({ [_n("custom")] = false }) - -o = s:option(DynamicList, _n("users"), translate("User")) -for i, v in ipairs(user_list) do - o:value(v[".name"], v.username) -end -o:depends({ [_n("custom")] = false }) - -o = s:option(Flag, _n("realms"), translate("Realms")) -o.default = "0" -o.rewrite_option = o.option -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") -o.rewrite_option = o.option -o:depends({ [_n("realms")] = "1" }) -o.validate = function(self, value) - value = api.trim(value) - local realm = api.parse_realm_uri(value) - if realm then return value end - return nil, translate("Invalid Realm URL.") -end - -o = s:option(DynamicList, _n("realm_stun"), translate("Realm STUN")) -o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } -o.rewrite_option = o.option -o:depends({ [_n("realms")] = "1" }) - -o = s:option(ListValue, _n("obfs_type"), translate("Obfs Type")) -o:value("", translate("Disable")) -o:value("salamander") -o:value("gecko") -o.rewrite_option = o.option -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("obfs_password"), translate("Obfs Password")) -o.rewrite_option = o.option -o:depends({ [_n("obfs_type")] = "salamander" }) -o:depends({ [_n("obfs_type")] = "gecko" }) - -o = s:option(Value, _n("obfs_MinPacketSize"), translate("Gecko Packet Size (min)")) -o.datatype = "uinteger" -o.placeholder = "512" -o.default = "512" -o:depends({ [_n("obfs_type")] = "gecko" }) -o.rewrite_option = o.option - -o = s:option(Value, _n("obfs_MaxPacketSize"), translate("Gecko Packet Size (max)")) -o.datatype = "uinteger" -o.placeholder = "1200" -o.default = "1200" -o:depends({ [_n("obfs_type")] = "gecko" }) -o.rewrite_option = o.option - -o = s:option(Flag, _n("udp"), translate("UDP")) -o.default = "1" -o.rewrite_option = o.option -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("up_mbps"), translate("Max upload Mbps")) -o.rewrite_option = o.option -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("down_mbps"), translate("Max download Mbps")) -o.rewrite_option = o.option -o:depends({ [_n("custom")] = false }) - -o = s:option(Flag, _n("ignoreClientBandwidth"), translate("ignoreClientBandwidth")) -o.default = "0" -o.rewrite_option = o.option -o:depends({ [_n("custom")] = false }) - -o = s:option(FileUpload, _n("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/" .. arg[1] .. ".pem" -if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end -o.validate = function(self, value, t) - if value and value ~= "" then - if not fs.access(value) then - return nil, translate("Can't find this file!") - else - return value - end - end - return nil -end -o:depends({ [_n("custom")] = false }) - -o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), 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.validate = function(self, value, t) - if value and value ~= "" then - if not fs.access(value) then - return nil, translate("Can't find this file!") - else - return value - end - end - return nil -end -o:depends({ [_n("custom")] = false }) - -o = s:option(TextValue, _n("custom_config"), translate("Custom Config")) -o.rows = 10 -o.wrap = "off" -o:depends({ [_n("custom")] = true }) -o.datatype = "json" -local o_validate = o.validate -o.validate = function(self, value) - local v = o_validate(self, value) - if v then return v end - return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") -end -o.custom_cfgvalue = function(self, section, value) - local config_str = m:get(section, "config_str") - if config_str then - return api.base64Decode(config_str) - end -end -o.custom_write = function(self, section, value) - m:set(section, "config_str", api.base64Encode(value) or "") -end - -o = s:option(Flag, _n("log"), translate("Log")) -o.default = "1" -o.rmempty = false - -api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua deleted file mode 100644 index 124a048f..00000000 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/ray.lua +++ /dev/null @@ -1,541 +0,0 @@ -local m, s = ... - -if not api.finded_com("xray") then - return -end - -local type_name = "Xray" - --- [[ Xray ]] - -s.fields["type"]:value(type_name, "Xray") -if not s.fields["type"].default then - s.fields["type"].default = type_name -end - -if s.val["type"] and s.val["type"] ~= type_name then - return -end - -local option_prefix = "xray_" - -local function _n(name) - return option_prefix .. name -end - -local x_ss_method_list = { - "aes-128-gcm", "aes-256-gcm", "chacha20-poly1305", "xchacha20-poly1305", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" -} - -local header_type_list = { - "none", "srtp", "utp", "wechat-video", "dtls", "wireguard", "dns" -} - -o = s:option(Flag, _n("custom"), translate("Use Custom Config")) - -o = s:option(ListValue, _n("protocol"), translate("Protocol")) -o:value("socks", "Socks") -o:value("http", "HTTP") -o:value("vmess", "Vmess") -o:value("vless", "VLESS") -o:value("shadowsocks", "Shadowsocks") -o:value("trojan", "Trojan") -o:value("hysteria2", "Hysteria2") -o:value("wireguard", "WireGuard") -o:value("dokodemo-door", "dokodemo-door") -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("port"), translate("Listen Port")) -o.datatype = "port" -o:depends({ [_n("custom")] = false }) - - -o = s:option(DynamicList, _n("users"), translate("User")) -for i, v in ipairs(user_list) do - o:value(v[".name"], v.username) -end -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o:depends({ [_n("protocol")] = "wireguard" }) - -o = s:option(ListValue, _n("d_protocol"), translate("Destination protocol")) -o:value("tcp", "TCP") -o:value("udp", "UDP") -o:value("tcp,udp", "TCP,UDP") -o:depends({ [_n("protocol")] = "dokodemo-door" }) - -o = s:option(Value, _n("d_address"), translate("Destination address")) -o:depends({ [_n("protocol")] = "dokodemo-door" }) - -o = s:option(Value, _n("d_port"), translate("Destination port")) -o.datatype = "port" -o:depends({ [_n("protocol")] = "dokodemo-door" }) - -o = s:option(Value, _n("decryption"), translate("Encrypt Method") .. " (decryption)") -o.default = "none" -o.placeholder = "none" -o:depends({ [_n("protocol")] = "vless" }) -o.validate = function(self, value) - value = api.trim(value) - return (value == "" and "none" or value) -end - -o = s:option(ListValue, _n("x_ss_method"), translate("Encrypt Method")) -o.rewrite_option = "method" -for a, t in ipairs(x_ss_method_list) do o:value(t) end -o:depends({ [_n("protocol")] = "shadowsocks" }) - -o = s:option(Value, _n("ss_password"), translate("Password")) -o:depends({ [_n("protocol")] = "shadowsocks" }) - -o = s:option(ListValue, _n("ss_network"), translate("Transport")) -o.default = "tcp,udp" -o:value("tcp", "TCP") -o:value("udp", "UDP") -o:value("tcp,udp", "TCP,UDP") -o:depends({ [_n("protocol")] = "shadowsocks" }) - -o = s:option(Flag, _n("udp_forward"), translate("UDP Forward")) -o.default = "1" -o.rmempty = false -o:depends({ [_n("protocol")] = "socks" }) - -o = s:option(ListValue, _n("flow"), translate("flow")) -o.default = "" -o:value("", translate("Disable")) -o:value("xtls-rprx-vision") -o:depends({ [_n("protocol")] = "vless" }) - ----- [[ hysteria2 ]] -o = s:option(Flag, _n("hysteria2_realms"), translate("Realms")) -o.default = "0" -o:depends({ [_n("protocol")] = "hysteria2"}) - -o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") -o:depends({ [_n("hysteria2_realms")] = "1" }) -o.validate = function(self, value) - value = api.trim(value) - local realm = api.parse_realm_uri(value) - if realm then return value end - return nil, translate("Invalid Realm URL.") -end - -o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN")) -o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } -o:depends({ [_n("hysteria2_realms")] = "1" }) - -o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) -o:value("", translate("Disable")) -o:value("salamander") -o:value("gecko") -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password")) -o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) -o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - -o = s:option(Value, _n("hysteria2_obfs_MinPacketSize"), translate("Gecko Packet Size (min)")) -o.datatype = "uinteger" -o.placeholder = "512" -o.default = "512" -o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - -o = s:option(Value, _n("hysteria2_obfs_MaxPacketSize"), translate("Gecko Packet Size (max)")) -o.datatype = "uinteger" -o.placeholder = "1200" -o.default = "1200" -o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - -o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control")) -o.default = 0 -o:depends({ [_n("protocol")] = "hysteria2" }) - -o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps")) -o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_ignore_client_bandwidth")] = false }) - -o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps")) -o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_ignore_client_bandwidth")] = false }) - ----- [[ TLS ]] -o = s:option(Flag, _n("tls"), translate("TLS")) -o.default = 0 -o.validate = function(self, value, t) - if value then - local reality = s.fields[_n("reality")] and s.fields[_n("reality")]:formvalue(t) or nil - if reality and reality == "1" then return value end - if value == "1" then - local ca = s.fields[_n("tls_certificateFile")] and s.fields[_n("tls_certificateFile")]:formvalue(t) or "" - local key = s.fields[_n("tls_keyFile")] and s.fields[_n("tls_keyFile")]:formvalue(t) or "" - if ca == "" or key == "" then - return nil, translate("Public key and Private key path can not be empty!") - end - end - return value - end -end -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "trojan" }) - --- [[ REALITY部分 ]] -- -o = s:option(Flag, _n("reality"), translate("REALITY")) -o.default = 0 -o:depends({ [_n("tls")] = true }) - -o = s:option(Value, _n("reality_private_key"), translate("Private Key")) -o:depends({ [_n("reality")] = true }) - -o = s:option(DynamicList, _n("reality_shortId"), translate("Short Id")) -o:depends({ [_n("reality")] = true }) - -o = s:option(Value, _n("reality_dest"), translate("Dest")) -o.default = "google.com:443" -o:depends({ [_n("reality")] = true }) - -o = s:option(DynamicList, _n("reality_serverNames"), translate("serverNames")) -o:depends({ [_n("reality")] = true }) - -o = s:option(ListValue, _n("alpn"), translate("alpn")) -o.default = "default" -o:value("default", translate("Default")) -o:value("h3") -o:value("h2") -o:value("h3,h2") -o:value("http/1.1") -o:value("h2,http/1.1") -o:value("h3,h2,http/1.1") -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) - -o = s:option(Flag, _n("use_mldsa65Seed"), translate("ML-DSA-65")) -o.default = "0" -o:depends({ [_n("reality")] = true }) - -o = s:option(TextValue, _n("reality_mldsa65Seed"), "ML-DSA-65 " .. translate("Private Key")) -o.default = "" -o.rows = 5 -o.wrap = "soft" -o:depends({ [_n("use_mldsa65Seed")] = true }) -o.validate = function(self, value) - return api.trim(value:gsub("[\r\n]", "")) -end - --- o = s:option(Value, _n("minversion"), translate("minversion")) --- o.default = "1.3" --- o:value("1.3") ---o:depends({ [_n("tls")] = true }) - --- [[ TLS部分 ]] -- - -o = s:option(FileUpload, _n("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/" .. arg[1] .. ".pem" -if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "hysteria2"}) -o.validate = function(self, value, t) - if value and value ~= "" then - if not fs.access(value) then - return nil, translate("Can't find this file!") - else - return value - end - end - return nil -end - -o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), 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({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "hysteria2"}) -o.validate = function(self, value, t) - if value and value ~= "" then - if not fs.access(value) then - return nil, translate("Can't find this file!") - else - return value - end - end - return nil -end - -o = s:option(Flag, _n("ech"), translate("ECH")) -o.default = "0" -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) - -o = s:option(TextValue, _n("ech_key"), translate("ECH Key")) -o.default = "" -o.rows = 5 -o.wrap = "soft" -o:depends({ [_n("ech")] = true }) -o.validate = function(self, value) - return api.trim(value:gsub("[\r\n]", "")) -end - -o = s:option(ListValue, _n("transport"), translate("Transport")) -o:value("raw", "RAW") -o:value("mkcp", "mKCP") -o:value("ws", "WebSocket") -o:value("grpc", "gRPC") -o:value("httpupgrade", "HttpUpgrade") -o:value("xhttp", "XHTTP") -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "trojan" }) - --- [[ WebSocket部分 ]]-- - -o = s:option(Value, _n("ws_host"), translate("WebSocket Host")) -o:depends({ [_n("transport")] = "ws" }) - -o = s:option(Value, _n("ws_path"), translate("WebSocket Path")) -o:depends({ [_n("transport")] = "ws" }) - --- [[ HttpUpgrade部分 ]]-- -o = s:option(Value, _n("httpupgrade_host"), translate("HttpUpgrade Host")) -o:depends({ [_n("transport")] = "httpupgrade" }) - -o = s:option(Value, _n("httpupgrade_path"), translate("HttpUpgrade Path")) -o.placeholder = "/" -o:depends({ [_n("transport")] = "httpupgrade" }) - --- [[ XHTTP部分 ]]-- -o = s:option(Value, _n("xhttp_host"), translate("XHTTP Host")) -o:depends({ [_n("transport")] = "xhttp" }) - -o = s:option(Value, _n("xhttp_path"), translate("XHTTP Path")) -o.placeholder = "/" -o:depends({ [_n("transport")] = "xhttp" }) - -o = s:option(Value, _n("xhttp_maxuploadsize"), translate("maxUploadSize")) -o.default = "1000000" -o:depends({ [_n("transport")] = "xhttp" }) - -o = s:option(Value, _n("xhttp_maxconcurrentuploads"), translate("maxConcurrentUploads")) -o.default = "10" -o:depends({ [_n("transport")] = "xhttp" }) - --- [[ TCP部分 ]]-- - --- TCP伪装 -o = s:option(ListValue, _n("tcp_guise"), translate("Camouflage Type")) -o:value("none", "none") -o:value("http", "http") -o:depends({ [_n("transport")] = "raw" }) - --- HTTP域名 -o = s:option(DynamicList, _n("tcp_guise_http_host"), translate("HTTP Host")) -o:depends({ [_n("tcp_guise")] = "http" }) - --- HTTP路径 -o = s:option(DynamicList, _n("tcp_guise_http_path"), translate("HTTP Path")) -o:depends({ [_n("tcp_guise")] = "http" }) - --- [[ mKCP部分 ]]-- - -o = s:option(ListValue, _n("mkcp_guise"), translate("Camouflage Type"), translate('
none: default, no masquerade, data sent is packets with no characteristics.
srtp: disguised as an SRTP packet, it will be recognized as video call data (such as FaceTime).
utp: packets disguised as uTP will be recognized as bittorrent downloaded data.
wechat-video: packets disguised as WeChat video calls.
dtls: disguised as DTLS 1.2 packet.
wireguard: disguised as a WireGuard packet. (not really WireGuard protocol)
dns: Disguising traffic as DNS requests.')) -for a, t in ipairs(header_type_list) do o:value(t) end -o:depends({ [_n("transport")] = "mkcp" }) - -o = s:option(Value, _n("mkcp_domain"), translate("Camouflage Domain"), translate("Use it together with the DNS disguised type. You can fill in any domain.")) -o:depends({ [_n("mkcp_guise")] = "dns" }) - -o = s:option(Value, _n("mkcp_mtu"), translate("KCP MTU")) -o.datatype = "uinteger" -o.default = 1350 -o:depends({ [_n("transport")] = "mkcp" }) - -o = s:option(Value, _n("mkcp_seed"), translate("KCP Seed")) -o:depends({ [_n("transport")] = "mkcp" }) - --- [[ gRPC部分 ]]-- -o = s:option(Value, _n("grpc_serviceName"), "ServiceName") -o:depends({ [_n("transport")] = "grpc" }) - ---[[FinalMask]] -o = s:option(Flag, _n("use_finalmask"), "FinalMask") -o.default = "0" -o:depends({ [_n("custom")] = false, [_n("protocol")] = "vmess" }) -o:depends({ [_n("custom")] = false, [_n("protocol")] = "vless" }) -o:depends({ [_n("custom")] = false, [_n("protocol")] = "trojan" }) -o:depends({ [_n("custom")] = false, [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("custom")] = false, [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) - -o = s:option(TextValue, _n("finalmask"), "FinalMask JSON") -o:depends({ [_n("use_finalmask")] = true }) -o.rows = 10 -o.wrap = "off" -o.datatype = "json" -o.custom_cfgvalue = function(self, section, value) - local raw = m:get(section, "finalmask") - if raw then - return api.base64Decode(raw) - end -end -o.custom_write = function(self, section, value) - m:set(section, "finalmask", api.base64Encode(value) or "") -end - ---[[acceptProxyProtocol]] -o = s:option(Flag, _n("acceptProxyProtocol"), translate("acceptProxyProtocol"), translate("Whether to receive PROXY protocol, when this node want to be fallback or forwarded by proxy, it must be enable, otherwise it cannot be used.")) -o.default = "0" -o:depends({ [_n("custom")] = false }) - ---[[Fast Open]] -o = s:option(Flag, _n("tcp_fast_open"), "TCP " .. translate("Fast Open")) -o.default = "0" -o:depends({ [_n("protocol")] = "vmess", [_n("custom")] = false }) -o:depends({ [_n("protocol")] = "vless", [_n("custom")] = false }) -o:depends({ [_n("protocol")] = "shadowsocks", [_n("custom")] = false }) -o:depends({ [_n("protocol")] = "trojan", [_n("custom")] = false }) - --- [[ Fallback部分 ]]-- -o = s:option(Flag, _n("fallback"), translate("Fallback")) -o:depends({ [_n("protocol")] = "vless", [_n("transport")] = "raw" }) -o:depends({ [_n("protocol")] = "trojan", [_n("transport")] = "raw" }) - ---[[ -o = s:option(Value, _n("fallback_alpn"), "Fallback alpn") -o:depends({ [_n("fallback")] = true }) - -o = s:option(Value, _n("fallback_path"), "Fallback path") -o:depends({ [_n("fallback")] = true }) - -o = s:option(Value, _n("fallback_dest"), "Fallback dest") -o:depends({ [_n("fallback")] = true }) - -o = s:option(Value, _n("fallback_xver"), "Fallback xver") -o.default = 0 -o:depends({ [_n("fallback")] = true }) -]]-- - -o = s:option(DynamicList, _n("fallback_list"), "Fallback", translate("format: dest,path,xver")) -o:depends({ [_n("fallback")] = true }) - --- Not supported at present ---[[ -o = s:option(Flag, _n("wireguard_system_interface"), translate("System interface")) -o.default = 0 -o:depends({ [_n("protocol")] = "wireguard" }) -]]-- - -o = s:option(Value, _n("wireguard_mtu"), "MTU") -o.default = "1420" -o:depends({ [_n("protocol")] = "wireguard" }) - --- Not supported at present ---[[ -o = s:option(DynamicList, _n("wireguard_local_address"), translate("Local Address")) -o:depends({ [_n("protocol")] = "wireguard" }) -]]-- - -o = s:option(Value, _n("wireguard_private_key"), translate("Private Key")) -o.datatype = "base64" -o:depends({ [_n("protocol")] = "wireguard" }) - -o = s:option(Value, _n("wireguard_public_key"), translate("Public Key")) -o.datatype = "base64" -o:depends({ [_n("protocol")] = "wireguard" }) - -o = s:option(DummyValue, _n("gen_wireguard_key")) -o.prefix = option_prefix -o.template = m:template_path("/server/server_wireguard") -o:depends({ [_n("protocol")] = "wireguard" }) - -o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) -o.default = "0" -o:depends({ [_n("custom")] = false }) - -o = s:option(Flag, _n("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) -o.default = "0" -o:depends({ [_n("custom")] = false }) - -local nodes_table = {} -for k, e in ipairs(api.get_valid_nodes()) do - if e.node_type == "normal" and e.type == type_name then - nodes_table[#nodes_table + 1] = { - id = e[".name"], - remarks = e["remark"], - group = e["group"] - } - end -end - -o = s:option(ListValue, _n("outbound_node"), translate("outbound node")) -o:value("", translate("Close")) -o:value("_socks", translate("Custom Socks")) -o:value("_http", translate("Custom HTTP")) -o:value("_iface", translate("Custom Interface")) -o.template = m:template_path("/cbi/nodes_listvalue") -o.group = {"","","",""} -for k, v in pairs(nodes_table) do - o:value(v.id, v.remarks) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") -end -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("outbound_node_address"), translate("Address (Support Domain Name)")) -o:depends({ [_n("outbound_node")] = "_socks"}) -o:depends({ [_n("outbound_node")] = "_http"}) - -o = s:option(Value, _n("outbound_node_port"), translate("Port")) -o.datatype = "port" -o:depends({ [_n("outbound_node")] = "_socks"}) -o:depends({ [_n("outbound_node")] = "_http"}) - -o = s:option(Value, _n("outbound_node_username"), translate("Username")) -o:depends({ [_n("outbound_node")] = "_socks"}) -o:depends({ [_n("outbound_node")] = "_http"}) - -o = s:option(Value, _n("outbound_node_password"), translate("Password")) -o.password = true -o:depends({ [_n("outbound_node")] = "_socks"}) -o:depends({ [_n("outbound_node")] = "_http"}) - -o = s:option(Value, _n("outbound_node_iface"), translate("Interface")) -o:depends({ [_n("outbound_node")] = "_iface"}) -local netdev_list = api.get_network_devices() -for _, d in ipairs(netdev_list) do - o:value(d.name, d.label) -end - -o = s:option(TextValue, _n("custom_config"), translate("Custom Config") .. " (JSON)") -o.rows = 10 -o.wrap = "off" -o:depends({ [_n("custom")] = true }) -o.datatype = "json" -local o_validate = o.validate -o.validate = function(self, value) - local v = o_validate(self, value) - if v then return v end - return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") -end -o.custom_cfgvalue = function(self, section, value) - local config_str = m:get(section, "config_str") - if config_str then - return api.base64Decode(config_str) - end -end -o.custom_write = function(self, section, value) - m:set(section, "config_str", api.base64Encode(value) or "") -end - -o = s:option(Flag, _n("log"), translate("Log")) -o.default = "1" -o.rmempty = false - -o = s:option(ListValue, _n("loglevel"), translate("Log Level")) -o.default = "warning" -o:value("debug") -o:value("info") -o:value("warning") -o:value("error") -o:depends({ [_n("log")] = true }) - -api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua deleted file mode 100644 index a092af7c..00000000 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/sing-box.lua +++ /dev/null @@ -1,523 +0,0 @@ -local m, s = ... - -local singbox_bin = api.finded_com("sing-box") - -if not singbox_bin then - return -end - -local type_name = "sing-box" - --- [[ Sing-Box ]] - -s.fields["type"]:value(type_name, "Sing-Box") -if not s.fields["type"].default then - s.fields["type"].default = type_name -end - -if s.val["type"] and s.val["type"] ~= type_name then - return -end - -local option_prefix = "singbox_" - -local function _n(name) - return option_prefix .. name -end - -local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'") - -local ss_method_list = { - "none", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", - "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305" -} - -o = s:option(Flag, _n("custom"), translate("Use Custom Config")) - -o = s:option(ListValue, _n("protocol"), translate("Protocol")) -o:value("mixed", "Mixed") -o:value("socks", "Socks") -o:value("http", "HTTP") -o:value("shadowsocks", "Shadowsocks") -o:value("vmess", "Vmess") -o:value("vless", "VLESS") -o:value("trojan", "Trojan") -o:value("naive", "Naive") -if singbox_tags:find("with_quic") then - o:value("hysteria", "Hysteria") -end -if singbox_tags:find("with_quic") then - o:value("tuic", "TUIC") -end -if singbox_tags:find("with_quic") then - o:value("hysteria2", "Hysteria2") -end -o:value("anytls", "AnyTLS") -if singbox_tags:find("with_wireguard") then - o:value("wireguard", "WireGuard") -end -o:value("direct", "Direct") -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("port"), translate("Listen Port")) -o.datatype = "port" -o:depends({ [_n("custom")] = false }) - -o = s:option(DynamicList, _n("users"), translate("User")) -for i, v in ipairs(user_list) do - o:value(v[".name"], v.username) -end -o:depends({ [_n("protocol")] = "mixed" }) -o:depends({ [_n("protocol")] = "socks" }) -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "naive" }) -o:depends({ [_n("protocol")] = "hysteria" }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o:depends({ [_n("protocol")] = "anytls" }) -o:depends({ [_n("protocol")] = "wireguard" }) - -if singbox_tags:find("with_quic") then - o = s:option(Value, _n("hysteria_obfs"), translate("Obfs Password")) - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_up_mbps"), translate("Max upload Mbps")) - o.default = "100" - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_down_mbps"), translate("Max download Mbps")) - o.default = "100" - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_recv_window_conn"), translate("QUIC stream receive window")) - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_recv_window_client"), translate("QUIC connection receive window")) - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Value, _n("hysteria_max_conn_client"), translate("QUIC concurrent bidirectional streams")) - o.default = "1024" - o:depends({ [_n("protocol")] = "hysteria" }) - - o = s:option(Flag, _n("hysteria_disable_mtu_discovery"), translate("Disable MTU detection")) - o:depends({ [_n("protocol")] = "hysteria" }) -end - -if singbox_tags:find("with_quic") then - o = s:option(ListValue, _n("tuic_congestion_control"), translate("Congestion control algorithm")) - o.default = "cubic" - o:value("bbr", translate("BBR")) - o:value("cubic", translate("CUBIC")) - o:value("new_reno", translate("New Reno")) - o:depends({ [_n("protocol")] = "tuic" }) - - o = s:option(Flag, _n("tuic_zero_rtt_handshake"), translate("Enable 0-RTT QUIC handshake")) - o.default = 0 - o:depends({ [_n("protocol")] = "tuic" }) - - o = s:option(Value, _n("tuic_heartbeat"), translate("Heartbeat interval(second)")) - o.datatype = "uinteger" - o.default = "3" - o:depends({ [_n("protocol")] = "tuic" }) - - o = s:option(ListValue, _n("tuic_alpn"), translate("QUIC TLS ALPN")) - o.default = "default" - o:value("default", translate("Default")) - o:value("h3") - o:value("h2") - o:value("h3,h2") - o:value("http/1.1") - o:value("h2,http/1.1") - o:value("h3,h2,http/1.1") - o:value("spdy/3.1") - o:value("h3,spdy/3.1") - o:depends({ [_n("protocol")] = "tuic" }) -end - -if singbox_tags:find("with_quic") then - o = s:option(Flag, _n("hysteria2_realms"), translate("Realms")) - o.default = "0" - o:depends({ [_n("protocol")] = "hysteria2"}) - - o = s:option(Value, _n("hysteria2_realm_url"), translate("Realm URL"), translate("Example:") .. "realm://public@realm.hy2.io/your-realm-name") - o:depends({ [_n("hysteria2_realms")] = "1" }) - o.validate = function(self, value) - value = api.trim(value) - local realm = api.parse_realm_uri(value) - if realm then return value end - return nil, translate("Invalid Realm URL.") - end - - o = s:option(DynamicList, _n("hysteria2_realm_stun"), translate("Realm STUN")) - o.default = { "stun.sip.us:3478", "stun.nextcloud.com:3478", "global.stun.twilio.com:3478" } - o:depends({ [_n("hysteria2_realms")] = "1" }) - - o = s:option(ListValue, _n("hysteria2_obfs_type"), translate("Obfs Type")) - o:value("", translate("Disable")) - o:value("salamander") - o:value("gecko") - o:depends({ [_n("protocol")] = "hysteria2" }) - - o = s:option(Value, _n("hysteria2_obfs_password"), translate("Obfs Password")) - o:depends({ [_n("hysteria2_obfs_type")] = "salamander" }) - o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - - o = s:option(Value, _n("hysteria2_obfs_MinPacketSize"), translate("Gecko Packet Size (min)")) - o.datatype = "uinteger" - o.placeholder = "512" - o.default = "512" - o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - - o = s:option(Value, _n("hysteria2_obfs_MaxPacketSize"), translate("Gecko Packet Size (max)")) - o.datatype = "uinteger" - o.placeholder = "1200" - o.default = "1200" - o:depends({ [_n("hysteria2_obfs_type")] = "gecko" }) - - o = s:option(Flag, _n("hysteria2_ignore_client_bandwidth"), translate("Client BBR Flow Control"), translate("Commands the client to use the BBR flow control algorithm")) - o.default = 0 - o:depends({ [_n("protocol")] = "hysteria2" }) - - o = s:option(Value, _n("hysteria2_up_mbps"), translate("Max upload Mbps")) - o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_ignore_client_bandwidth")] = false }) - - o = s:option(Value, _n("hysteria2_down_mbps"), translate("Max download Mbps")) - o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_ignore_client_bandwidth")] = false }) -end - -o = s:option(ListValue, _n("d_protocol"), translate("Destination protocol")) -o:value("tcp", "TCP") -o:value("udp", "UDP") -o:value("tcp,udp", "TCP,UDP") -o:depends({ [_n("protocol")] = "direct" }) - -o = s:option(Value, _n("d_address"), translate("Destination address")) -o:depends({ [_n("protocol")] = "direct" }) - -o = s:option(Value, _n("d_port"), translate("Destination port")) -o.datatype = "port" -o:depends({ [_n("protocol")] = "direct" }) - -o = s:option(Value, _n("decryption"), translate("Encrypt Method")) -o.default = "none" -o:depends({ [_n("protocol")] = "vless" }) - -o = s:option(ListValue, _n("ss_method"), translate("Encrypt Method")) -o.rewrite_option = "method" -for a, t in ipairs(ss_method_list) do o:value(t) end -o:depends({ [_n("protocol")] = "shadowsocks" }) - -o = s:option(Value, _n("ss_password"), translate("Password")) -o:depends({ [_n("protocol")] = "shadowsocks" }) - -o = s:option(ListValue, _n("flow"), translate("flow")) -o.default = "" -o:value("", translate("Disable")) -o:value("xtls-rprx-vision") -o:depends({ [_n("protocol")] = "vless" , [_n("tls")] = true }) - -o = s:option(Flag, _n("tls"), translate("TLS")) -o.default = 0 -o.validate = function(self, value, t) - if value then - local reality = s.fields[_n("reality")] and s.fields[_n("reality")]:formvalue(t) or nil - if reality and reality == "1" then return value end - if value == "1" then - local ca = s.fields[_n("tls_certificateFile")] and s.fields[_n("tls_certificateFile")]:formvalue(t) or "" - local key = s.fields[_n("tls_keyFile")] and s.fields[_n("tls_keyFile")]:formvalue(t) or "" - if ca == "" or key == "" then - return nil, translate("Public key and Private key path can not be empty!") - end - end - return value - end -end -o:depends({ [_n("protocol")] = "http" }) -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "trojan" }) -o:depends({ [_n("protocol")] = "anytls" }) - --- https://github.com/SagerNet/sing-box/commit/d2a04c4e41e6cef0937331cb6d10211f431caaab -if singbox_tags:find("with_utls") then - -- [[ REALITY部分 ]] -- - o = s:option(Flag, _n("reality"), translate("REALITY")) - o.default = 0 - o:depends({ [_n("protocol")] = "http", [_n("tls")] = true }) - o:depends({ [_n("protocol")] = "vmess", [_n("tls")] = true }) - o:depends({ [_n("protocol")] = "vless", [_n("tls")] = true }) - o:depends({ [_n("protocol")] = "trojan", [_n("tls")] = true }) - o:depends({ [_n("protocol")] = "anytls", [_n("tls")] = true }) - - o = s:option(Value, _n("reality_private_key"), translate("Private Key")) - o:depends({ [_n("reality")] = true }) - - o = s:option(Value, _n("reality_shortId"), translate("Short Id")) - o:depends({ [_n("reality")] = true }) - - o = s:option(Value, _n("reality_handshake_server"), translate("Handshake Server")) - o.default = "google.com" - o:depends({ [_n("reality")] = true }) - - o = s:option(Value, _n("reality_handshake_server_port"), translate("Handshake Server Port")) - o.datatype = "port" - o.default = "443" - o:depends({ [_n("reality")] = true }) -end - -o = s:option(ListValue, _n("alpn"), translate("ALPN")) -o.default = "default" -o:value("default", translate("Default")) -o:value("h3") -o:value("h2") -o:value("h3,h2") -o:value("http/1.1") -o:value("h2,http/1.1") -o:value("h3,h2,http/1.1") -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "hysteria" }) - --- [[ TLS部分 ]] -- - -o = s:option(FileUpload, _n("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/" .. arg[1] .. ".pem" -if o and o:formvalue(arg[1]) then o.default = o:formvalue(arg[1]) end -o:depends({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "naive" }) -o:depends({ [_n("protocol")] = "hysteria" }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o.validate = function(self, value, t) - if value and value ~= "" then - if not fs.access(value) then - return nil, translate("Can't find this file!") - else - return value - end - end - return nil -end - -o = s:option(FileUpload, _n("tls_keyFile"), translate("Private key absolute path"), 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({ [_n("tls")] = true, [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "naive" }) -o:depends({ [_n("protocol")] = "hysteria" }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2" }) -o.validate = function(self, value, t) - if value and value ~= "" then - if not fs.access(value) then - return nil, translate("Can't find this file!") - else - return value - end - end - return nil -end - -o = s:option(Flag, _n("ech"), translate("ECH")) -o.default = "0" -o:depends({ [_n("tls")] = true, [_n("flow")] = "", [_n("reality")] = false }) -o:depends({ [_n("protocol")] = "naive" }) -o:depends({ [_n("protocol")] = "hysteria" }) -o:depends({ [_n("protocol")] = "tuic" }) -o:depends({ [_n("protocol")] = "hysteria2", [_n("hysteria2_realms")] = false }) - -o = s:option(TextValue, _n("ech_key"), translate("ECH Key")) -o.default = "" -o.rows = 5 -o.wrap = "off" -o:depends({ [_n("ech")] = true }) -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 -end - -o = s:option(ListValue, _n("transport"), translate("Transport")) -o:value("tcp", "TCP") -o:value("http", "HTTP") -o:value("ws", "WebSocket") -o:value("httpupgrade", "HTTPUpgrade") -o:value("quic", "QUIC") -o:value("grpc", "gRPC") -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless" }) -o:depends({ [_n("protocol")] = "trojan" }) - --- [[ HTTP部分 ]]-- - -o = s:option(DynamicList, _n("http_host"), translate("HTTP Host")) -o:depends({ [_n("transport")] = "http" }) - -o = s:option(Value, _n("http_path"), translate("HTTP Path")) -o:depends({ [_n("transport")] = "http" }) - --- [[ WebSocket部分 ]]-- - -o = s:option(Value, _n("ws_host"), translate("WebSocket Host")) -o:depends({ [_n("transport")] = "ws" }) - -o = s:option(Value, _n("ws_path"), translate("WebSocket Path")) -o:depends({ [_n("transport")] = "ws" }) - --- [[ HTTPUpgrade部分 ]]-- - -o = s:option(Value, _n("httpupgrade_host"), translate("HTTPUpgrade Host")) -o:depends({ [_n("transport")] = "httpupgrade" }) - -o = s:option(Value, _n("httpupgrade_path"), translate("HTTPUpgrade Path")) -o:depends({ [_n("transport")] = "httpupgrade" }) - --- [[ gRPC部分 ]]-- -o = s:option(Value, _n("grpc_serviceName"), "ServiceName") -o:depends({ [_n("transport")] = "grpc" }) - --- [[ Mux ]]-- -o = s:option(Flag, _n("mux"), translate("Mux")) -o.rmempty = false -o:depends({ [_n("protocol")] = "vmess" }) -o:depends({ [_n("protocol")] = "vless", [_n("flow")] = "" }) -o:depends({ [_n("protocol")] = "shadowsocks" }) -o:depends({ [_n("protocol")] = "trojan" }) - --- [[ TCP Brutal ]]-- -o = s:option(Flag, _n("tcpbrutal"), translate("TCP Brutal")) -o.default = 0 -o:depends({ [_n("mux")] = true }) - -o = s:option(Value, _n("tcpbrutal_up_mbps"), translate("Max upload Mbps")) -o.default = "10" -o:depends({ [_n("tcpbrutal")] = true }) - -o = s:option(Value, _n("tcpbrutal_down_mbps"), translate("Max download Mbps")) -o.default = "50" -o:depends({ [_n("tcpbrutal")] = true }) - -if singbox_tags:find("with_wireguard") then - o = s:option(Flag, _n("wireguard_system_interface"), translate("System interface")) - o.default = 0 - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(Value, _n("wireguard_mtu"), "MTU") - o.default = "1408" - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(DynamicList, _n("wireguard_local_address"), translate("Local Address")) - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(Value, _n("wireguard_private_key"), translate("Private Key")) - o.datatype = "base64" - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(Value, _n("wireguard_public_key"), translate("Public Key")) - o.datatype = "base64" - o:depends({ [_n("protocol")] = "wireguard" }) - - o = s:option(DummyValue, _n("gen_wireguard_key")) - o.prefix = option_prefix - o.template = m:template_path("/server/server_wireguard") - o:depends({ [_n("protocol")] = "wireguard" }) -end - -o = s:option(Flag, _n("bind_local"), translate("Bind Local"), translate("When selected, it can only be accessed localhost.")) -o.default = "0" -o:depends({ [_n("custom")] = false }) - -o = s:option(Flag, _n("accept_lan"), translate("Accept LAN Access"), translate("When selected, it can accessed lan , this will not be safe!")) -o.default = "0" -o:depends({ [_n("custom")] = false }) - -local nodes_table = {} -for k, e in ipairs(api.get_valid_nodes()) do - if e.node_type == "normal" and e.type == type_name then - nodes_table[#nodes_table + 1] = { - id = e[".name"], - remarks = e["remark"], - group = e["group"] - } - end -end - -o = s:option(ListValue, _n("outbound_node"), translate("outbound node")) -o:value("", translate("Close")) -o:value("_socks", translate("Custom Socks")) -o:value("_http", translate("Custom HTTP")) -o:value("_iface", translate("Custom Interface")) -o.template = m:template_path("/cbi/nodes_listvalue") -o.group = {"","","",""} -for k, v in pairs(nodes_table) do - o:value(v.id, v.remarks) - o.group[#o.group+1] = (v.group and v.group ~= "") and v.group or translate("default") -end -o:depends({ [_n("custom")] = false }) - -o = s:option(Value, _n("outbound_node_address"), translate("Address (Support Domain Name)")) -o:depends({ [_n("outbound_node")] = "_socks" }) -o:depends({ [_n("outbound_node")] = "_http" }) - -o = s:option(Value, _n("outbound_node_port"), translate("Port")) -o.datatype = "port" -o:depends({ [_n("outbound_node")] = "_socks" }) -o:depends({ [_n("outbound_node")] = "_http" }) - -o = s:option(Value, _n("outbound_node_username"), translate("Username")) -o:depends({ [_n("outbound_node")] = "_socks" }) -o:depends({ [_n("outbound_node")] = "_http" }) - -o = s:option(Value, _n("outbound_node_password"), translate("Password")) -o.password = true -o:depends({ [_n("outbound_node")] = "_socks" }) -o:depends({ [_n("outbound_node")] = "_http" }) - -o = s:option(Value, _n("outbound_node_iface"), translate("Interface")) -o:depends({ [_n("outbound_node")] = "_iface" }) -local netdev_list = api.get_network_devices() -for _, d in ipairs(netdev_list) do - o:value(d.name, d.label) -end - -o = s:option(TextValue, _n("custom_config"), translate("Custom Config") .. " (JSON)") -o.rows = 10 -o.wrap = "off" -o:depends({ [_n("custom")] = true }) -o.datatype = "json" -local o_validate = o.validate -o.validate = function(self, value) - local v = o_validate(self, value) - if v then return v end - return nil, translate("Custom Config") .. " " .. translate("Must be JSON text!") -end -o.custom_cfgvalue = function(self, section, value) - local config_str = m:get(section, "config_str") - if config_str then - return api.base64Decode(config_str) - end -end -o.custom_write = function(self, section, value) - m:set(section, "config_str", api.base64Encode(value) or "") -end - -o = s:option(Flag, _n("log"), translate("Log")) -o.default = "1" -o.rmempty = false - -o = s:option(ListValue, _n("loglevel"), translate("Log Level")) -o.default = "info" -o:value("debug") -o:value("info") -o:value("warn") -o:value("error") -o:depends({ [_n("log")] = true }) - -api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua deleted file mode 100644 index 0e8632fc..00000000 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/socks.lua +++ /dev/null @@ -1,40 +0,0 @@ -local m, s = ... - -if not api.is_finded("microsocks") then - return -end - -local type_name = "Socks" - -local option_prefix = "socks_" - -local function _n(name) - return option_prefix .. name -end - --- [[ microsocks ]] - -s.fields["type"]:value(type_name, "Socks") -if not s.fields["type"].default then - s.fields["type"].default = type_name -end - -if s.val["type"] and s.val["type"] ~= type_name then - return -end - -o = s:option(Value, _n("port"), translate("Listen Port")) -o.datatype = "port" - -o = s:option(Flag, _n("auth"), translate("Auth")) - -o = s:option(ListValue, _n("user"), translate("User")) -for i, v in ipairs(user_list) do - o:value(v[".name"], v.username) -end -o:depends({ [_n("auth")] = true }) - -o = s:option(Flag, _n("log"), translate("Log")) -o.default = "1" - -api.luci_types(arg[1], m, s, type_name, option_prefix) diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua index ee2ce355..b544dc54 100644 --- a/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua +++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/user_config.lua @@ -44,7 +44,7 @@ o = s:option(Value, "wireguard_private_key", "Wireguard " .. translate("Private o.datatype = "base64" o = s:option(DummyValue, "gen_wireguard_key") -o.template = m:template_path("/server/server_wireguard") +o.template = m:template_path("/server/gen_wireguard_key") o = s:option(Value, "wireguard_pre_shared_key", "Wireguard " .. translate("Pre shared key")) o.datatype = "base64" diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua index 2bd6d741..d77c229f 100644 --- a/luci-app-passwall/luasrc/passwall/api.lua +++ b/luci-app-passwall/luasrc/passwall/api.lua @@ -1534,102 +1534,110 @@ function return_map(map) return map end -function luci_types(id, m, s, type_name, option_prefix) +function luci_types(s, s2) local cbi = require "luci.cbi" + local m = s.map + local id = s2.section + local type_name = s2.type_name + local option_prefix = s2.option_prefix local fv_type local field_type = s.fields["type"] if field_type then fv_type = field_type:formvalue(id) end - local rewrite_option_table = {} - for key, value in pairs(s.fields) do - if key:find(option_prefix) == 1 then - if not s.fields[key].not_rewrite then - if s.fields[key].rewrite_option then - if not rewrite_option_table[s.fields[key].rewrite_option] then - rewrite_option_table[s.fields[key].rewrite_option] = 1 + for i, v in ipairs(s2.children) do + local o = s2.children[i] + o.config_option = o.option + o.option_prefix = option_prefix + o.option = option_prefix .. o.option + if not o.not_rewrite then + o.cfgvalue = function(self, section) + -- Add a custom `custom_cfgvalue` attribute. If a custom `custom_cfgvalue` function exists, the custom `cfgvalue` logic will be used. + if self.custom_cfgvalue then + return self:custom_cfgvalue(section) + else + if self.rewrite_option then + return m:get(section, self.rewrite_option) else - rewrite_option_table[s.fields[key].rewrite_option] = rewrite_option_table[s.fields[key].rewrite_option] + 1 + return m:get(section, self.config_option) end end - - s.fields[key].cfgvalue = function(self, section) - -- 添加自定义 custom_cfgvalue 属性,如果有自定义的 custom_cfgvalue 函数,则使用自定义的 cfgvalue 逻辑 - if self.custom_cfgvalue then - return self:custom_cfgvalue(section) + end + o.write = function(self, section, value) + if s.fields["type"]:formvalue(id) == type_name then + -- Add a custom `custom_write` attribute; if a custom `custom_write` function exists, then use the custom write logic. + if self.custom_write then + self:custom_write(section, value) + else + local new_val = value + if util.instanceof(self, cbi.DynamicList) then + local new_t = {} + if type(value) == "table" then + new_t = table_remove_duplicates(value) + else + new_t = { value } + end + if self.cast == "string" then + new_val = table.concat(new_t, " ") + else + new_val = new_t + end + end + if self.rewrite_option then + m:set(section, self.rewrite_option, new_val) + else + m:set(section, self.config_option, new_val) + end + end + end + end + o.remove = function(self, section) + if s.fields["type"]:formvalue(id) == type_name then + -- Add a custom `custom_remove` attribute; if a custom `custom_remove` function exists, use the custom remove logic. + if self.custom_remove then + self:custom_remove(section) else if self.rewrite_option then - return m:get(section, self.rewrite_option) + m:del(section, self.rewrite_option) else - if self.option:find(option_prefix) == 1 then - return m:get(section, self.option:sub(1 + #option_prefix)) - end + m:del(section, self.config_option) end end end - s.fields[key].write = function(self, section, value) - if s.fields["type"]:formvalue(id) == type_name then - -- 添加自定义 custom_write 属性,如果有自定义的 custom_write 函数,则使用自定义的 write 逻辑 - if self.custom_write then - self:custom_write(section, value) - else - local new_val = value - if util.instanceof(self, cbi.DynamicList) then - local new_t = {} - if type(value) == "table" then - new_t = table_remove_duplicates(value) - else - new_t = { value } - end - if self.cast == "string" then - new_val = table.concat(new_t, " ") - else - new_val = new_t - end - end - if self.rewrite_option then - m:set(section, self.rewrite_option, new_val) - else - if self.option:find(option_prefix) == 1 then - m:set(section, self.option:sub(1 + #option_prefix), new_val) - end - end - end - end - end - s.fields[key].remove = function(self, section) - if s.fields["type"]:formvalue(id) == type_name then - -- 添加自定义 custom_remove 属性,如果有自定义的 custom_remove 函数,则使用自定义的 remove 逻辑 - if self.custom_remove then - self:custom_remove(section) - else - if self.rewrite_option and rewrite_option_table[self.rewrite_option] == 1 then - m:del(section, self.rewrite_option) - else - if self.option:find(option_prefix) == 1 then - m:del(section, self.option:sub(1 + #option_prefix)) - end - end - end - end - end - end - - local deps = s.fields[key].deps - if #deps > 0 then - for index, value in ipairs(deps) do - if not deps[index]['!reverse'] then - deps[index]["type"] = type_name - end - end - else - s.fields[key]:depends({ type = type_name }) - end - - if fv_type and fv_type ~= type_name then - s.fields[key].rmempty = true end end + + local deps = o.deps + if #deps > 0 then + local function process_deps(dep) + local rewrite_deps = {} + for k, v in pairs(dep) do + if k:find("!") then + rewrite_deps[k] = v + else + rewrite_deps[option_prefix .. k] = v + end + end + if not rewrite_deps['!reverse'] then + rewrite_deps["type"] = type_name + end + return rewrite_deps + end + for index, value in ipairs(deps) do + local rewrite_deps = process_deps(value) + if rewrite_deps then + deps[index] = rewrite_deps + end + end + else + o:depends({ type = type_name }) + end + + if fv_type and fv_type ~= type_name then + o.rmempty = true + end + + s:append(o) end end diff --git a/luci-app-passwall/luasrc/view/passwall/server/server_wireguard.htm b/luci-app-passwall/luasrc/view/passwall/server/gen_wireguard_key.htm similarity index 96% rename from luci-app-passwall/luasrc/view/passwall/server/server_wireguard.htm rename to luci-app-passwall/luasrc/view/passwall/server/gen_wireguard_key.htm index ff73bb97..1283e6f7 100644 --- a/luci-app-passwall/luasrc/view/passwall/server/server_wireguard.htm +++ b/luci-app-passwall/luasrc/view/passwall/server/gen_wireguard_key.htm @@ -1,7 +1,7 @@ <% local map = self.map local api = map.api -local prefix = self.prefix +local prefix = self.option_prefix or "" -%>
" data-index="<%=self.index%>" data-depends="<%=pcdata(self:deplist2json(section))%>"> diff --git a/luci-app-passwall/root/usr/share/passwall/subscribe.lua b/luci-app-passwall/root/usr/share/passwall/subscribe.lua index d53dbd3d..64de3fa8 100755 --- a/luci-app-passwall/root/usr/share/passwall/subscribe.lua +++ b/luci-app-passwall/root/usr/share/passwall/subscribe.lua @@ -821,6 +821,7 @@ local function processData(szType, content, add_mode, group, sub_cfg) (_method == "xchacha20-poly1305" and "xchacha20-ietf-poly1305") or _method result.method = method + result.ss_method = method result.password = password result.tcp_fast_open = params.tfo result.use_finalmask = (params.fm and params.fm ~= "") and "1" or nil @@ -1189,6 +1190,7 @@ local function processData(szType, content, add_mode, group, sub_cfg) result.port = content.port result.password = content.password result.method = content.encryption + result.ss_method = content.encryption result.plugin = content.plugin result.plugin_opts = content.plugin_options result.group = content.airport diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua index 2fddbb8f..0a949aff 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua @@ -143,40 +143,54 @@ end -- 默认的保存并应用行为 local function apply_redirect(m) - local tmp_uci_file = "/etc/config/" .. "shadowsocksr" .. "_redirect" + local tmp_uci_file = "/etc/config/shadowsocksr_redirect" if m.redirect and m.redirect ~= "" then + -- 如果存在临时文件,读取 URL 并通过 luci.http.redirect 跳转 if nixio.fs.access(tmp_uci_file) then - local redirect + local redirect_url for line in io.lines(tmp_uci_file) do - redirect = line:match("option%s+url%s+['\"]([^'\"]+)['\"]") - if redirect and redirect ~= "" then break end + redirect_url = line:match("option%s+url%s+['\"]([^'\"]+)['\"]") + if redirect_url and redirect_url ~= "" then break end end - if redirect and redirect ~= "" then - luci.sys.call("/bin/rm -f " .. tmp_uci_file) - luci.http.redirect(redirect) + if redirect_url and redirect_url ~= "" then + -- 使用 nixio 安全删除文件,替代外部 Shell 命令 + nixio.fs.remove(tmp_uci_file) + -- JS 版 LuCI 依赖 luci.http.redirect 向前端重定向 + luci.http.redirect(redirect_url) + return end else + -- 创建标记文件 nixio.fs.writefile(tmp_uci_file, "config redirect\n") end + -- 挂载保存回调 + local old_on_after_save = m.on_after_save m.on_after_save = function(self) - local redirect = self.redirect - if redirect and redirect ~= "" then - m.uci:set("shadowsocksr" .. "_redirect", "@redirect[0]", "url", redirect) + if old_on_after_save then old_on_after_save(self) end + local target = self.redirect + if target and target ~= "" then + -- 使用标准的 nixio.fs 写入文件,保持格式一致 + local content = string.format("config redirect\n\toption url '%s'\n", target) + nixio.fs.writefile(tmp_uci_file, content) end end else - luci.sys.call("/bin/rm -f " .. tmp_uci_file) + -- 不满足重定向条件时清理文件 + if nixio.fs.access(tmp_uci_file) then + nixio.fs.remove(tmp_uci_file) + end end end -local function set_apply_on_parse(map) - if not map then return end - if is_js_luci() then - apply_redirect(map) - local old = map.on_after_save - map.on_after_save = function(self) - if old then old(self) end - --map:set("@global[0]", "timestamp", os.time()) +local function set_apply_on_parse(m) + if not m then return end + -- is_js_luci 保护 + if is_js_luci and is_js_luci() then + apply_redirect(m) + local old_on_after_save = m.on_after_save + m.on_after_save = function(self) + if old_on_after_save then old_on_after_save(self) end + -- m:set("@global[0]", "timestamp", os.time()) end end end @@ -345,15 +359,12 @@ if not sid or m.uci:get("shadowsocksr", sid) ~= "servers" then return end -- 保存&应用成功后跳转到节点列表 -set_apply_on_parse(m) -local old_after_save = m.on_after_save -m.on_after_save = function(self) - if old_after_save then old_after_save(self) end +set_apply_on_parse(m, function(self) local node_type = self.uci:get("shadowsocksr", sid, "type") if node_type == "clash" then luci.sys.call(string.format("/etc/init.d/shadowsocksr clash_cache %s >/dev/null 2>&1 &", sid)) end -end +end) local server_header = Template("/shadowsocksr/server_header") server_header.section = sid diff --git a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua index fe993bf9..e7b13faa 100644 --- a/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua +++ b/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua @@ -29,42 +29,56 @@ local function is_js_luci() return luci.sys.call('[ -f "/www/luci-static/resources/uci.js" ]') == 0 end --- 保存并应用行为 +-- 默认的保存并应用行为 local function apply_redirect(m) - local tmp_uci_file = "/etc/config/" .. "shadowsocksr" .. "_redirect" + local tmp_uci_file = "/etc/config/shadowsocksr_redirect" if m.redirect and m.redirect ~= "" then + -- 如果存在临时文件,读取 URL 并通过 luci.http.redirect 跳转 if nixio.fs.access(tmp_uci_file) then - local redirect + local redirect_url for line in io.lines(tmp_uci_file) do - redirect = line:match("option%s+url%s+['\"]([^'\"]+)['\"]") - if redirect and redirect ~= "" then break end + redirect_url = line:match("option%s+url%s+['\"]([^'\"]+)['\"]") + if redirect_url and redirect_url ~= "" then break end end - if redirect and redirect ~= "" then - luci.sys.call("/bin/rm -f " .. tmp_uci_file) - luci.http.redirect(redirect) + if redirect_url and redirect_url ~= "" then + -- 使用 nixio 安全删除文件,替代外部 Shell 命令 + nixio.fs.remove(tmp_uci_file) + -- JS 版 LuCI 依赖 luci.http.redirect 向前端重定向 + luci.http.redirect(redirect_url) + return end else + -- 创建标记文件 nixio.fs.writefile(tmp_uci_file, "config redirect\n") end + -- 挂载保存回调 + local old_on_after_save = m.on_after_save m.on_after_save = function(self) - local redirect = self.redirect - if redirect and redirect ~= "" then - m.uci:set("shadowsocksr" .. "_redirect", "@redirect[0]", "url", redirect) + if old_on_after_save then old_on_after_save(self) end + local target = self.redirect + if target and target ~= "" then + -- 使用标准的 nixio.fs 写入文件,保持格式一致 + local content = string.format("config redirect\n\toption url '%s'\n", target) + nixio.fs.writefile(tmp_uci_file, content) end end else - luci.sys.call("/bin/rm -f " .. tmp_uci_file) + -- 不满足重定向条件时清理文件 + if nixio.fs.access(tmp_uci_file) then + nixio.fs.remove(tmp_uci_file) + end end end -local function set_apply_on_parse(map) - if not map then return end - if is_js_luci() then - apply_redirect(map) - local old = map.on_after_save - map.on_after_save = function(self) - if old then old(self) end - -- map:set("@global[0]", "timestamp", os.time()) +local function set_apply_on_parse(m) + if not m then return end + -- is_js_luci 保护 + if is_js_luci and is_js_luci() then + apply_redirect(m) + local old_on_after_save = m.on_after_save + m.on_after_save = function(self) + if old_on_after_save then old_on_after_save(self) end + -- m:set("@global[0]", "timestamp", os.time()) end end end diff --git a/luci-app-ssr-plus/po/templates/ssr-plus.pot b/luci-app-ssr-plus/po/templates/ssr-plus.pot index 830e57e6..6bb54013 100644 --- a/luci-app-ssr-plus/po/templates/ssr-plus.pot +++ b/luci-app-ssr-plus/po/templates/ssr-plus.pot @@ -20,7 +20,7 @@ msgstr "" msgid "128 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1663 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1674 msgid "16" msgstr "" @@ -36,7 +36,7 @@ msgstr "" msgid "32 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1478 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1489 msgid "360" msgstr "" @@ -56,7 +56,7 @@ msgstr "" msgid "64 Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1650 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1661 msgid "8" msgstr "" @@ -68,9 +68,9 @@ msgstr "" msgid "" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1149 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1505 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1532 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1516 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1543 msgid "" msgstr "" @@ -82,10 +82,10 @@ msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:269 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:284 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1321 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1643 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1656 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1669 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1332 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1654 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1667 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1680 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 msgid "
  • " msgstr "" @@ -144,13 +144,13 @@ msgstr "" msgid "AliYun Public DNS (223.5.5.5)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:597 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:709 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:611 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:723 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:187 msgid "Alias" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:411 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:422 msgid "Alias(optional)" msgstr "" @@ -182,7 +182,7 @@ msgstr "" msgid "Allow listed only" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:472 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:486 msgid "Allow subscribe Insecure nodes By default" msgstr "" @@ -196,11 +196,11 @@ msgstr "" msgid "Alter ID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:973 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:984 msgid "AlterId" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1395 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1406 msgid "An FinalMaskObject in JSON format, used for sharing." msgstr "" @@ -226,12 +226,12 @@ msgstr "" msgid "Apple domains optimization" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:769 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:775 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:783 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:789 msgid "Apply" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:426 msgid "Appointment Mode" msgstr "" @@ -243,7 +243,7 @@ msgstr "" msgid "Are you sure you want to restore the client to default settings?" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:786 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:800 msgid "Auto Switch" msgstr "" @@ -251,22 +251,22 @@ msgstr "" msgid "Auto Threads" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:407 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:421 msgid "Auto Update" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:423 msgid "Auto Update Server subscription, GFW list and CHN route" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:907 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1709 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1725 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:918 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1720 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1736 msgid "BBR" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1710 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1726 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1721 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1737 msgid "BRUTAL" msgstr "" @@ -294,8 +294,8 @@ msgstr "" msgid "Bind Local Only" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1272 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1282 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1283 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1293 msgid "BitTorrent (uTP)" msgstr "" @@ -303,7 +303,7 @@ msgstr "" msgid "Black Domain List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:576 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:587 msgid "Bloom Filter" msgstr "" @@ -319,18 +319,18 @@ msgstr "" msgid "CNNIC SDNS (1.2.4.8)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:908 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1711 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:919 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1722 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1740 msgid "CUBIC" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1289 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1300 msgid "Camouflage Domain" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1057 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1278 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1068 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1289 msgid "Camouflage Type" msgstr "" @@ -338,7 +338,7 @@ msgstr "" msgid "Certificate File Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1619 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1630 msgid "Certificate fingerprint" msgstr "" @@ -427,19 +427,19 @@ msgstr "" msgid "Clash Panel" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:430 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:441 msgid "Clash Subscription URL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:442 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:453 msgid "Clash User-Agent" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:436 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:447 msgid "Clash YAML Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:390 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:401 msgid "Clash/Mihomo" msgstr "" @@ -456,9 +456,9 @@ msgid "Clear logs" msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:309 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1151 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1507 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1534 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1518 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1545 msgid "Click to the page" msgstr "" @@ -507,11 +507,11 @@ msgstr "" msgid "Component Update" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1149 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1160 msgid "Configure XHTTP Extra Settings (JSON format), see:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:905 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:916 msgid "Congestion control algorithm" msgstr "" @@ -527,16 +527,16 @@ msgstr "" msgid "Connection Timeout" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1518 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1529 msgid "" "Controls the policy used when performing DNS queries for ECH configuration." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:561 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:575 msgid "Convert Address" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:556 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:570 msgid "" "Convert subscriptions to Clash/Mihomo YAML with a subscription template URL." msgstr "" @@ -558,7 +558,7 @@ msgstr "" msgid "Create Backup File" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1757 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1768 msgid "Create upload file error." msgstr "" @@ -566,7 +566,7 @@ msgstr "" msgid "Current ARCH" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1777 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1788 msgid "Current Certificate Path" msgstr "" @@ -574,7 +574,7 @@ msgstr "" msgid "Current Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:610 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:621 msgid "Custom" msgstr "" @@ -598,7 +598,7 @@ msgid "" "(tcp://8.8.8.8 or tls://dns.google:853)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:614 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:625 msgid "Custom Plugin Path" msgstr "" @@ -606,7 +606,7 @@ msgstr "" msgid "Custom Ports" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:269 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:283 msgid "Custom YAML imported successfully: %s" msgstr "" @@ -618,7 +618,7 @@ msgstr "" msgid "Custom client proxy rules saved." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1396 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1407 msgid "" "Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related " "settings." @@ -628,7 +628,7 @@ msgstr "" msgid "DL Backup" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1286 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1297 msgid "DNS" msgstr "" @@ -640,8 +640,8 @@ msgstr "" msgid "DNSPod Public DNS (119.29.29.29)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1274 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1284 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1285 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1295 msgid "DTLS 1.2" msgstr "" @@ -657,10 +657,10 @@ msgstr "" msgid "Decryption" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1364 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1555 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1567 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1581 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1375 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1566 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1578 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1592 msgid "Default" msgstr "" @@ -668,21 +668,21 @@ msgstr "" msgid "Default Node Local Port" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1670 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1681 msgid "Default reject rejects traffic." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:803 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:814 msgid "Default value 0 indicatesno heartbeat." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1644 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1655 msgid "" "Default: disable. When entering a negative number, such as -1, The Mux " "module will not be used to carry TCP traffic." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1657 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1668 msgid "" "Default:16. When entering a negative number, such as -1, The Mux module will " "not be used to carry UDP traffic, Use original UDP transmission method of " @@ -716,7 +716,7 @@ msgstr "" msgid "Delete" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:505 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:519 msgid "Delete All Subscribe Servers" msgstr "" @@ -728,8 +728,8 @@ msgstr "" msgid "Deny Domain List" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:715 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1026 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:726 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1037 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:81 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:33 msgid "Disable" @@ -743,19 +743,19 @@ msgstr "" msgid "Disable IPv6 for Overseas FQDN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:760 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:771 msgid "Disable QUIC path MTU discovery" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:949 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:960 msgid "Disable SNI" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:830 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:841 msgid "Disable TCP No_delay" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:553 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:567 msgid "Disabled means use Xray or ShadowSocks-Rust core." msgstr "" @@ -783,7 +783,7 @@ msgstr "" msgid "Domestic DNS Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1307 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1318 msgid "Downlink Capacity(Default:Mbps)" msgstr "" @@ -795,19 +795,19 @@ msgstr "" msgid "Download failed" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:960 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:971 msgid "Dual-stack Listening Socket" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1503 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1514 msgid "ECH Config" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1517 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1528 msgid "ECH Query Policy" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1099 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1110 msgid "Early Data Header Name" msgstr "" @@ -816,7 +816,7 @@ msgstr "" msgid "Edit" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:341 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:355 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:40 msgid "Edit ShadowSocksR Server" msgstr "" @@ -826,60 +826,60 @@ msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:323 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:54 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:101 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:589 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:603 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1114 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:184 msgid "Enable" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:954 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:965 msgid "Enable 0-RTT QUIC handshake" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:515 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:526 msgid "Enable Authentication" msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:100 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1794 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1805 msgid "Enable Auto Switch" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1487 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1498 msgid "Enable ECH(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:709 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:720 msgid "Enable Lazy Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1525 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1536 msgid "Enable ML-DSA-65(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:550 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:564 msgid "Enable Mihomo core" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1688 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1699 msgid "" "Enable Multipath TCP, need to be enabled in both server and client " "configuration." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1624 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1635 msgid "Enable Mux.Cool" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:703 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:714 msgid "Enable Obfuscation" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:582 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:593 msgid "Enable Plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:671 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:682 msgid "Enable Port Hopping" msgstr "" @@ -887,15 +887,15 @@ msgstr "" msgid "Enable Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:684 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:695 msgid "Enable Transport Protocol Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:816 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:827 msgid "Enable V2 protocol." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:815 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:826 msgid "Enable V3 protocol." msgstr "" @@ -903,15 +903,15 @@ msgstr "" msgid "Enable adblock" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:571 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:582 msgid "Enable the SUoT protocol, requires server support." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1142 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1153 msgid "Enable this option to configure XHTTP Extra (JSON format)." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1319 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1330 msgid "Enabled Kernel virtual NIC TUN(optional)" msgstr "" @@ -919,16 +919,16 @@ msgstr "" msgid "Enabled Mixed" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:825 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1783 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:836 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1794 msgid "Enabling TCP Fast Open Requires Server Support." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:549 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:556 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:857 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:560 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:567 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:868 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:999 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:879 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1010 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:105 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:110 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:173 @@ -945,39 +945,39 @@ msgstr "" msgid "Error" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:433 msgid "Every Day" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:424 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:438 msgid "Every Friday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:420 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:434 msgid "Every Monday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:425 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:439 msgid "Every Saturday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:426 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:440 msgid "Every Sunday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:423 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:437 msgid "Every Thursday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:421 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:435 msgid "Every Tuesday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:422 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:436 msgid "Every Wednesday" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:652 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:663 msgid "Example:" msgstr "" @@ -993,7 +993,7 @@ msgstr "" msgid "Extract failed" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1727 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1738 msgid "FORCE BRUTAL" msgstr "" @@ -1005,7 +1005,7 @@ msgstr "" msgid "Failed to create temp directory" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:230 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:244 msgid "Failed to create temporary YAML upload file." msgstr "" @@ -1031,8 +1031,8 @@ msgstr "" msgid "Fetch Failed" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1608 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1615 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1619 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1626 msgid "Fetch Manually" msgstr "" @@ -1040,19 +1040,19 @@ msgstr "" msgid "File Not Exist" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:462 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:476 msgid "Filter Words splited by /" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1378 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1389 msgid "FinalMask" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1470 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1481 msgid "Finger Print" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1457 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1468 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:214 msgid "Flow" msgstr "" @@ -1067,7 +1067,7 @@ msgstr "" msgid "For specific usage, see:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:678 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:689 msgid "" "Format as 10000:20000 or 10000-20000 Multiple groups are separated by commas " "(,)." @@ -1113,19 +1113,19 @@ msgstr "" msgid "Game Mode UDP Relay" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:925 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:936 msgid "Garbage collection interval(second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:931 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:942 msgid "Garbage collection lifetime(second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:740 msgid "Gecko Packet Size (max)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:722 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:733 msgid "Gecko Packet Size (min)" msgstr "" @@ -1190,20 +1190,20 @@ msgstr "" msgid "Grant UCI access for luci-app-ssr-plus" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1213 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1224 msgid "Gun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1232 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1243 msgid "H2 Read Idle Timeout" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1227 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1238 msgid "H2/gRPC Health Check" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:462 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1060 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:473 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1071 msgid "HTTP" msgstr "" @@ -1211,7 +1211,7 @@ msgstr "" msgid "HTTP Auth Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1064 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1075 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:293 msgid "HTTP Host" msgstr "" @@ -1220,7 +1220,7 @@ msgstr "" msgid "HTTP Password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1069 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1080 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:297 msgid "HTTP Path" msgstr "" @@ -1233,29 +1233,29 @@ msgstr "" msgid "HTTP proxy auth method, default:none." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1206 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:270 msgid "HTTP/2 Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1211 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:276 msgid "HTTP/2 Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1267 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1278 msgid "Header" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1244 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1255 msgid "Health Check Timeout" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:913 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:924 msgid "Heartbeat interval(second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1086 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1097 msgid "HeartbeatPeriod(second)" msgstr "" @@ -1263,24 +1263,24 @@ msgstr "" msgid "Hour" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1119 msgid "Httpupgrade Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1113 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1124 msgid "Httpupgrade Path" msgstr "" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:420 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:456 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:467 msgid "Hysteria2" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:644 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:655 msgid "Hysteria2 Realms" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:754 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:765 msgid "Hysterir QUIC parameters" msgstr "" @@ -1288,7 +1288,7 @@ msgstr "" msgid "IP Route Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1579 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1590 msgid "IP Stack Preference" msgstr "" @@ -1296,23 +1296,23 @@ msgstr "" msgid "If empty, Not change Apple domains parsing DNS (Default is empty)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1505 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1516 msgid "" "If it is not empty, it indicates that the Client has enabled Encrypted " "Client, see:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:961 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:972 msgid "If this option is not set, the socket behavior is platform dependent." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1592 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1603 msgid "" "If true, allowss insecure connection at TLS client, e.g., TLS server uses " "unverifiable certificates." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1741 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1752 msgid "If you have a self-signed certificate,please check the box" msgstr "" @@ -1337,7 +1337,7 @@ msgstr "" msgid "Import configuration information successfully." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1220 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1231 msgid "Initial Windows Size" msgstr "" @@ -1373,7 +1373,7 @@ msgstr "" msgid "Invalid" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:658 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:669 msgid "Invalid Realm URL." msgstr "" @@ -1417,19 +1417,19 @@ msgstr "" msgid "KcpTun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1799 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1810 msgid "KcpTun Enable" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1819 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1830 msgid "KcpTun Param" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1813 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1824 msgid "KcpTun Password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1806 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1817 msgid "KcpTun Port" msgstr "" @@ -1508,7 +1508,7 @@ msgstr "" msgid "Limit the maximum number of splits." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1322 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1333 msgid "" "Linux kernel TUN virtual NIC requires system support and root privileges." msgstr "" @@ -1532,7 +1532,7 @@ msgstr "" msgid "Local Servers" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1330 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1341 msgid "Local addresses" msgstr "" @@ -1540,7 +1540,7 @@ msgstr "" msgid "Log" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:413 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:427 msgid "Loop Mode" msgstr "" @@ -1552,15 +1552,15 @@ msgstr "" msgid "Loyalsoldier/v2ray-rules-dat" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1530 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1541 msgid "ML-DSA-65 Public key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1688 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1699 msgid "MPTCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1293 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1304 msgid "MTU" msgstr "" @@ -1568,7 +1568,7 @@ msgstr "" msgid "Main Server" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:587 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:601 msgid "" "Manage multiple subscribe URLs, including Clash subscriptions. Only enabled " "entries are included when updating all subscriptions." @@ -1579,7 +1579,7 @@ msgstr "" msgid "Matching release asset not found" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1092 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1103 msgid "Max Early Data" msgstr "" @@ -1587,7 +1587,7 @@ msgstr "" msgid "Max Split" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:966 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:977 msgid "Maximum packet size the socks5 server can receive from external" msgstr "" @@ -1610,13 +1610,13 @@ msgstr "" msgid "Min" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1658 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1669 msgid "" "Min value is 1, Max value is 1024. When omitted or set to 0, Will same path " "as TCP traffic." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1645 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1656 msgid "" "Min value is 1, Max value is 128. When omitted or set to 0, it equals 8." msgstr "" @@ -1653,7 +1653,7 @@ msgstr "" msgid "Muitiple DNS server can saperate with ','" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1225 msgid "Multi" msgstr "" @@ -1661,12 +1661,12 @@ msgstr "" msgid "Multi Threads Option" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1184 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1414 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1425 msgid "Must be JSON text!" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1624 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1635 msgid "Mux" msgstr "" @@ -1679,7 +1679,7 @@ msgid "NOT RUNNING" msgstr "" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:414 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:387 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:398 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:17 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:471 msgid "NaiveProxy" @@ -1693,7 +1693,7 @@ msgstr "" msgid "Nanjing Xinfeng 114DNS (114.114.114.114)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:909 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:920 msgid "New Reno" msgstr "" @@ -1729,7 +1729,7 @@ msgstr "" msgid "No available core (Shadowsocks, Mihomo or Xray) to import this node." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:249 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:263 msgid "No custom YAML file was selected." msgstr "" @@ -1741,7 +1741,7 @@ msgstr "" msgid "No new data!" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1773 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1784 msgid "No specify upload file." msgstr "" @@ -1754,7 +1754,7 @@ msgstr "" msgid "No switchable proxy groups found." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:611 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:625 msgid "" "Node order can be dragged with the mouse and takes effect immediately. The " "automatic switch order of server nodes is consistent with the node order in " @@ -1765,13 +1765,13 @@ msgstr "" msgid "Noise" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:590 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1059 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1258 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1270 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1280 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:706 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:711 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:601 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1070 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1269 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1281 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1291 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:720 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:725 msgid "None" msgstr "" @@ -1811,35 +1811,35 @@ msgid "" "saperate with ','." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1699 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1710 msgid "Number of early established connections to reduce latency." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:589 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:632 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:600 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:643 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:120 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:138 msgid "Obfs" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:639 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:650 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:125 msgid "Obfs param (optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1314 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1325 msgid "Obfuscate password (optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:736 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:747 msgid "Obfuscation Password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:714 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:725 msgid "Obfuscation Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1607 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1618 msgid "Once set, connects only when the server’s chain fingerprint matches." msgstr "" @@ -1903,7 +1903,7 @@ msgstr "" msgid "Panel" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:529 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:540 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:95 msgid "Password" msgstr "" @@ -1912,7 +1912,7 @@ msgstr "" msgid "Paste sharing link here" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1345 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1356 msgid "Peer public key" msgstr "" @@ -1925,15 +1925,15 @@ msgstr "" msgid "Perform reset" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1250 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1261 msgid "Permit Without Stream" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:754 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:768 msgid "Ping Latency" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1780 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1791 msgid "Please confirm the current certificate path" msgstr "" @@ -1941,11 +1941,11 @@ msgstr "" msgid "Please fill in reset" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:425 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:436 msgid "Please specify either a Clash subscription URL or a local YAML path." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:618 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:629 msgid "Plugin Opts" msgstr "" @@ -1953,19 +1953,19 @@ msgstr "" msgid "Policy" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:695 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:706 msgid "Port Hopping Interval(Unit:Second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:677 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:688 msgid "Port hopping range" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1699 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1710 msgid "Pre-connections" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1349 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1360 msgid "Pre-shared key" msgstr "" @@ -1981,7 +1981,7 @@ msgstr "" msgid "Private Key File Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1340 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1351 msgid "Private key" msgstr "" @@ -1990,13 +1990,13 @@ msgstr "" msgid "Processing..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:622 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:633 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:115 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:133 msgid "Protocol" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:629 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:640 msgid "Protocol param (optional)" msgstr "" @@ -2004,7 +2004,7 @@ msgstr "" msgid "Proxy Ports" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1444 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1455 msgid "Public key" msgstr "" @@ -2012,33 +2012,33 @@ msgstr "" msgid "QUIC Camouflage Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1263 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1274 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:369 msgid "QUIC Key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1256 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1267 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:361 msgid "QUIC Security" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:781 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:792 msgid "QUIC initConnReceiveWindow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:767 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:778 msgid "QUIC initStreamReceiveWindow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:788 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:799 msgid "QUIC maxConnReceiveWindow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:795 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:806 msgid "QUIC maxIdleTimeout(Unit:second)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:774 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:785 msgid "QUIC maxStreamReceiveWindow" msgstr "" @@ -2046,7 +2046,7 @@ msgstr "" msgid "QUIC protocols such as HY2 also require curl with http3 support." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1439 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1450 msgid "REALITY" msgstr "" @@ -2080,15 +2080,15 @@ msgstr "" msgid "Really reset all changes?" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:661 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:672 msgid "Realm STUN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:652 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:663 msgid "Realm URL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:773 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:787 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:348 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:17 msgid "Reapply" @@ -2122,11 +2122,11 @@ msgstr "" msgid "Refresh..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:431 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:445 msgid "Regular update (Hour)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:439 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:453 msgid "Regular update (Min)" msgstr "" @@ -2150,8 +2150,8 @@ msgstr "" msgid "Remarks" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1712 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1728 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1723 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1739 msgid "Reno" msgstr "" @@ -2163,7 +2163,7 @@ msgstr "" msgid "Requires OpenSSL to retrieve the TLS certificate chain fingerprint." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1335 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1346 msgid "Reserved bytes(optional)" msgstr "" @@ -2262,15 +2262,15 @@ msgstr "" msgid "Save" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:493 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:507 msgid "Save Subscribe Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:468 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:482 msgid "Save Words splited by /" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:495 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:509 msgid "Save current subscribe settings" msgstr "" @@ -2288,15 +2288,15 @@ msgstr "" msgid "Second" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1733 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1744 msgid "Self-signed Certificate" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:465 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:476 msgid "Server Address" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:507 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:521 msgid "Server Count" msgstr "" @@ -2304,11 +2304,11 @@ msgstr "" msgid "Server Name (SNI)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:384 msgid "Server Node Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:490 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:501 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:77 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:117 msgid "Server Port" @@ -2331,37 +2331,37 @@ msgstr "" msgid "Servers Nodes" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:393 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:407 msgid "Servers subscription and manage" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1433 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1444 msgid "Session Ticket" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:396 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:604 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:407 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:615 msgid "Shadow-TLS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:842 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:853 msgid "Shadow-TLS ChainPoxy type" msgstr "" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:377 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:381 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:451 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:392 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:462 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:61 msgid "ShadowSocks" msgstr "" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:389 #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:391 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:384 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:395 msgid "ShadowSocks-Rust" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:845 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:856 msgid "ShadowSocks-rust Version" msgstr "" @@ -2377,18 +2377,18 @@ msgstr "" msgid "ShadowTLS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:853 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:864 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:168 msgid "Shadowsocks Password" msgstr "" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:385 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:378 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:389 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:64 msgid "ShadowsocksR" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1448 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1459 msgid "Short ID" msgstr "" @@ -2396,35 +2396,35 @@ msgstr "" msgid "Showing %d-%d of %d nodes" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:459 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:470 msgid "Snell" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1025 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1036 msgid "Snell Obfs" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1033 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1044 msgid "Snell Obfs Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:544 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:555 msgid "Snell PSK" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1015 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1026 msgid "Snell Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:714 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:728 msgid "Socket Connected" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:461 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:472 msgid "Socks" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1007 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1018 msgid "Socks Version" msgstr "" @@ -2432,7 +2432,7 @@ msgstr "" msgid "Socks protocol auth methods, default:noauth." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:399 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:410 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:59 msgid "Socks5" msgstr "" @@ -2475,19 +2475,19 @@ msgstr "" msgid "Stop Detection" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:453 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:467 msgid "Subscribe Advanced Settings" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:555 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:569 msgid "Subscribe Convert Online" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:479 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:493 msgid "Subscribe Default Auto-Switch" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:459 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:473 msgid "Subscribe Filter Words" msgstr "" @@ -2495,16 +2495,16 @@ msgstr "" msgid "Subscribe Log" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:466 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:480 msgid "Subscribe Save Words" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:569 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:583 msgid "Subscribe Template URL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:580 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:604 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:594 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:618 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:189 msgid "Subscribe URL" msgstr "" @@ -2513,11 +2513,11 @@ msgstr "" msgid "Subscribe failed, refreshing page..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:481 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:495 msgid "Subscribe new add server default Auto-Switch on" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:474 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:488 msgid "Subscribe nodes allows insecure connection as TLS client (insecure)" msgstr "" @@ -2533,11 +2533,11 @@ msgstr "" msgid "Support AdGuardHome and DNSMASQ format list" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:696 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:707 msgid "Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1336 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1347 msgid "" "Supports decimal numbers separated by \",\" or Base64-encoded strings, with " "a maximum length of 3 bytes." @@ -2566,8 +2566,8 @@ msgstr "" msgid "TCP Camouflage Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:825 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1783 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:836 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1794 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:128 msgid "TCP Fast Open" msgstr "" @@ -2582,65 +2582,65 @@ msgstr "" msgid "TCP upstream" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1430 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:201 msgid "TLS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:820 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:831 msgid "TLS 1.3 Strict mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1553 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1564 msgid "TLS ALPN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1611 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1622 msgid "TLS Certificate Name (CertName)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1604 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1615 msgid "TLS Chain Fingerprint (SHA256)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1545 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1556 msgid "TLS Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1614 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1625 msgid "TLS is used to verify the leaf certificate name." msgstr "" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:383 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:393 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:404 msgid "TUIC" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1565 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1576 msgid "TUIC ALPN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:885 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:896 msgid "TUIC Server IP Address" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:892 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:903 msgid "TUIC User Password" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:878 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:889 msgid "TUIC User UUID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:943 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:954 msgid "TUIC receive window" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:937 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:948 msgid "TUIC send window" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1532 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1543 msgid "" "The client has not configured mldsa65Verify, but it will not perform the " "\"additional verification\" step and can still connect normally, see:" @@ -2650,7 +2650,7 @@ msgstr "" msgid "The content entered is incorrect!" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:802 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:813 msgid "The keep-alive period.(Unit:second)" msgstr "" @@ -2698,11 +2698,11 @@ msgstr "" msgid "This section contains no values yet" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:486 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:500 msgid "Through proxy update" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:488 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:502 msgid "Through proxy update list, Not Recommended" msgstr "" @@ -2710,7 +2710,7 @@ msgstr "" msgid "Timeout" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:919 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:930 msgid "Timeout for establishing a connection to server(second)" msgstr "" @@ -2722,18 +2722,18 @@ msgstr "" msgid "Total Records:" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1038 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1049 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:179 msgid "Transport" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:689 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:700 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:240 msgid "Transport Protocol" msgstr "" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:412 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:450 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:461 msgid "Trojan" msgstr "" @@ -2746,11 +2746,11 @@ msgid "Try Count" msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:327 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:703 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:717 msgid "Type" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:691 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:702 msgid "UDP" msgstr "" @@ -2760,11 +2760,11 @@ msgid "" "restrictions." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:570 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:581 msgid "UDP over TCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:898 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:909 msgid "UDP relay mode" msgstr "" @@ -2780,7 +2780,7 @@ msgstr "" msgid "UL Restore" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:525 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:539 msgid "URL Test Address" msgstr "" @@ -2829,19 +2829,19 @@ msgstr "" msgid "Update" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:498 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:512 msgid "Update All Subscribe Servers" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:447 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:461 msgid "Update Interval(min)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:411 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:425 msgid "Update Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:418 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:432 msgid "Update cycle (Day/Week)" msgstr "" @@ -2888,29 +2888,29 @@ msgstr "" msgid "Upgrading..." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1300 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1311 msgid "Uplink Capacity(Default:Mbps)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1743 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1754 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm:3 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm:3 msgid "Upload" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:546 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:560 msgid "Upload Custom YAML File" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:548 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:562 msgid "" "Upload a custom Clash/Mihomo YAML file. The file will be preprocessed and " "saved as a local Clash node." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:263 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:271 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:276 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:277 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:285 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:290 msgid "Uploaded YAML validation or preprocessing failed." msgstr "" @@ -2938,7 +2938,7 @@ msgstr "" msgid "Use MosDNS query" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1290 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1301 msgid "" "Use it together with the DNS disguised type. You can fill in any domain." msgstr "" @@ -2951,8 +2951,8 @@ msgstr "" msgid "User cancelled." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1362 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:536 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:550 msgid "User-Agent" msgstr "" @@ -2961,17 +2961,17 @@ msgstr "" msgid "Userinfo format error." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:522 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:533 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:91 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:122 msgid "Username" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:665 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:676 msgid "Users Authentication" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:420 msgid "Using incorrect encryption mothod may causes service fail to start" msgstr "" @@ -2985,40 +2985,40 @@ msgstr "" msgid "V2Ray GeoSite Databases" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:375 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:386 msgid "V2Ray/XRay" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:447 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:458 msgid "V2Ray/XRay protocol" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:448 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:459 msgid "VLESS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:988 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:999 msgid "VLESS Encryption" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:449 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:460 msgid "VMess" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1271 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1281 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1282 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1292 msgid "VideoCall (SRTP)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:848 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:859 msgid "Vmess Protocol" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:863 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:874 msgid "Vmess UUID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:980 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:991 msgid "Vmess/VLESS ID (UUID)" msgstr "" @@ -3034,22 +3034,22 @@ msgstr "" msgid "WAN White List IP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1075 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1086 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:254 msgid "WebSocket Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1081 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1092 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:261 msgid "WebSocket Path" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1273 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1283 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1284 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1294 msgid "WechatVideo" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1323 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1334 msgid "When enabled, it occupies IPv6 routing table 1023." msgstr "" @@ -3063,29 +3063,29 @@ msgid "" "reverse proxies." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:453 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1275 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1285 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:464 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1286 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1296 msgid "WireGuard" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1355 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1366 msgid "Wireguard allows only traffic from specific source IP." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1141 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1152 msgid "XHTTP Extra" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1129 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1140 msgid "XHTTP Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1120 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1131 msgid "XHTTP Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1135 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1146 msgid "XHTTP Path" msgstr "" @@ -3128,27 +3128,27 @@ msgstr "" msgid "adblock_url" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1259 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1270 msgid "aes-128-gcm" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1677 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1688 msgid "allow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1671 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1682 msgid "allow: Allows use Mux connection." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1587 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1598 msgid "allowInsecure" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1354 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1365 msgid "allowedIPs(optional)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1476 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1487 msgid "android" msgstr "" @@ -3156,7 +3156,7 @@ msgstr "" msgid "anti-AD" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1260 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1271 msgid "chacha20-poly1305" msgstr "" @@ -3164,32 +3164,32 @@ msgstr "" msgid "china-operator-ip" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1365 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1472 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1376 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1483 msgid "chrome" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1708 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1724 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1719 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1735 msgid "comment_tcpcongestion_disable" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1641 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1652 msgid "concurrency" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1370 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1381 msgid "curl" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1705 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1721 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1716 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1732 msgid "custom_tcpcongestion" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1483 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1649 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1662 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1494 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1660 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1673 msgid "disable" msgstr "" @@ -3201,8 +3201,8 @@ msgstr "" msgid "e.g.: /etc/ssl/private.key" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1368 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1477 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1379 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1488 msgid "edge" msgstr "" @@ -3210,20 +3210,20 @@ msgstr "" msgid "felixonmars/dnsmasq-china-list" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1366 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1473 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1377 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1484 msgid "firefox" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1238 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1249 msgid "gRPC Idle Timeout" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1211 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1222 msgid "gRPC Mode" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1216 msgid "gRPC Service Name" msgstr "" @@ -3235,23 +3235,23 @@ msgstr "" msgid "gfwlist/gfwlist" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1369 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1380 msgid "golang" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:598 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:609 msgid "gost-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1475 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1486 msgid "ios" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:608 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:619 msgid "kcptun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:901 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:912 msgid "lossless UDP relay using QUIC streams" msgstr "" @@ -3267,67 +3267,67 @@ msgstr "" msgid "naive binary not found in archive" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:900 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:911 msgid "native UDP characteristics" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:560 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1461 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:571 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1472 msgid "none" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:592 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:603 msgid "obfs-local" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1479 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1490 msgid "qq" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1480 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1491 msgid "random" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1481 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1492 msgid "randomized" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1676 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1687 msgid "reject" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:607 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:618 msgid "restls" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1367 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1474 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1378 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1485 msgid "safari" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:835 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:846 msgid "shadow-TLS SNI" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:813 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:824 msgid "shadowTLS protocol Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1678 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1689 msgid "skip" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1672 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1683 msgid "" "skip: Not use Mux module to carry UDP 443 traffic, Use original UDP " "transmission method of proxy protocol." msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1452 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1463 msgid "spiderX" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1482 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1493 msgid "unsafe" msgstr "" @@ -3335,7 +3335,7 @@ msgstr "" msgid "v2fly/domain-list-community" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:595 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:606 msgid "v2ray-plugin" msgstr "" @@ -3351,14 +3351,14 @@ msgstr "" msgid "xray binary not found in archive" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:601 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:612 msgid "xray-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1654 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1665 msgid "xudpConcurrency" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1667 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1678 msgid "xudpProxyUDP443" msgstr "" diff --git a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po index 5382a3f3..74374ff1 100644 --- a/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po +++ b/luci-app-ssr-plus/po/zh_Hans/ssr-plus.po @@ -22,7 +22,7 @@ msgstr "单线程" msgid "128 Threads" msgstr "128 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1663 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1674 msgid "16" msgstr "" @@ -38,7 +38,7 @@ msgstr "2 线程" msgid "32 Threads" msgstr "32 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1478 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1489 msgid "360" msgstr "" @@ -58,7 +58,7 @@ msgstr "4 线程" msgid "64 Threads" msgstr "64 线程" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1650 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1661 msgid "8" msgstr "" @@ -70,9 +70,9 @@ msgstr "8 线程" msgid "" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1149 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1505 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1532 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1160 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1516 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1543 msgid "" msgstr "" @@ -86,10 +86,10 @@ msgstr "" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:269 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:284 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1321 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1643 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1656 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1669 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1332 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1654 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1667 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1680 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:186 msgid "
    • " msgstr "" @@ -148,13 +148,13 @@ msgstr "【广告屏蔽】数据库" msgid "AliYun Public DNS (223.5.5.5)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:597 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:709 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:611 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:723 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:187 msgid "Alias" msgstr "别名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:411 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:422 msgid "Alias(optional)" msgstr "别名(可选)" @@ -186,7 +186,7 @@ msgstr "除列表外主机皆允许" msgid "Allow listed only" msgstr "仅允许列表内主机" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:472 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:486 msgid "Allow subscribe Insecure nodes By default" msgstr "订阅节点允许不验证 TLS 证书" @@ -200,11 +200,11 @@ msgstr "已是最新版本" msgid "Alter ID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:973 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:984 msgid "AlterId" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1395 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1406 msgid "An FinalMaskObject in JSON format, used for sharing." msgstr "JSON 格式的 FinalMaskObject,用来实现分享。" @@ -230,12 +230,12 @@ msgstr "Apple 域名更新 URL" msgid "Apple domains optimization" msgstr "Apple 域名解析优化" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:769 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:775 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:783 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:789 msgid "Apply" msgstr "应用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:412 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:426 msgid "Appointment Mode" msgstr "定时模式" @@ -247,7 +247,7 @@ msgstr "确定要删除此订阅链接:%s 吗?" msgid "Are you sure you want to restore the client to default settings?" msgstr "是否真的要恢复客户端默认配置?" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:786 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:800 msgid "Auto Switch" msgstr "自动切换" @@ -255,22 +255,22 @@ msgstr "自动切换" msgid "Auto Threads" msgstr "自动(CPU 线程数)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:407 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:421 msgid "Auto Update" msgstr "自动更新" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:423 msgid "Auto Update Server subscription, GFW list and CHN route" msgstr "自动更新服务器订阅、GFW 列表和中国大陆 IP 段" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:907 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1709 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1725 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:918 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1720 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1736 msgid "BBR" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1710 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1726 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1721 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1737 msgid "BRUTAL" msgstr "" @@ -298,8 +298,8 @@ msgstr "Base64 解码失败。" msgid "Bind Local Only" msgstr "仅绑定本地端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1272 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1282 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1283 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1293 msgid "BitTorrent (uTP)" msgstr "BT 下载(uTP)" @@ -307,7 +307,7 @@ msgstr "BT 下载(uTP)" msgid "Black Domain List" msgstr "强制走代理的域名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:576 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:587 msgid "Bloom Filter" msgstr "布隆过滤器" @@ -323,18 +323,18 @@ msgstr "关闭窗口" msgid "CNNIC SDNS (1.2.4.8)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:908 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1711 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:919 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1722 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1740 msgid "CUBIC" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1289 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1300 msgid "Camouflage Domain" msgstr "伪装域名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1057 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1278 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1068 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1289 msgid "Camouflage Type" msgstr "伪装类型" @@ -342,7 +342,7 @@ msgstr "伪装类型" msgid "Certificate File Path" msgstr "证书文件路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1619 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1630 msgid "Certificate fingerprint" msgstr "证书指纹" @@ -431,19 +431,19 @@ msgstr "Clash" msgid "Clash Panel" msgstr "Clash 面板" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:430 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:441 msgid "Clash Subscription URL" msgstr "Clash 订阅链接" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:442 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:453 msgid "Clash User-Agent" msgstr "Clash User-Agent" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:436 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:447 msgid "Clash YAML Path" msgstr "Clash YAML 路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:390 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:401 msgid "Clash/Mihomo" msgstr "Clash/Mihomo" @@ -460,9 +460,9 @@ msgid "Clear logs" msgstr "清空日志" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:309 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1151 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1507 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1534 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1162 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1518 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1545 msgid "Click to the page" msgstr "点击前往" @@ -511,11 +511,11 @@ msgstr "组件" msgid "Component Update" msgstr "组件升级" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1149 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1160 msgid "Configure XHTTP Extra Settings (JSON format), see:" msgstr "配置 XHTTP 额外设置(JSON 格式),具体请参见:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:905 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:916 msgid "Congestion control algorithm" msgstr "拥塞控制算法" @@ -531,16 +531,16 @@ msgstr "连接正常" msgid "Connection Timeout" msgstr "连接超时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1518 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1529 msgid "" "Controls the policy used when performing DNS queries for ECH configuration." msgstr "控制使用 DNS 查询 ECH 配置时的策略。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:561 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:575 msgid "Convert Address" msgstr "转换订阅模板API服务器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:556 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:570 msgid "" "Convert subscriptions to Clash/Mihomo YAML with a subscription template URL." msgstr "使用订阅转换模板 URL 将订阅转换为 Clash/Mihomo YAML。" @@ -562,7 +562,7 @@ msgstr "Country MMDB" msgid "Create Backup File" msgstr "创建备份文件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1757 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1768 msgid "Create upload file error." msgstr "创建上传文件错误。" @@ -570,7 +570,7 @@ msgstr "创建上传文件错误。" msgid "Current ARCH" msgstr "当前架构" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1777 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1788 msgid "Current Certificate Path" msgstr "当前证书路径" @@ -578,7 +578,7 @@ msgstr "当前证书路径" msgid "Current Version" msgstr "当前版本" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:610 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:621 msgid "Custom" msgstr "自定义" @@ -603,7 +603,7 @@ msgid "" msgstr "" "格式为tcp://IP:Port或tls://域名:Port (tcp://8.8.8.8或tls://dns.google:853)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:614 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:625 msgid "Custom Plugin Path" msgstr "自定义插件路径" @@ -611,7 +611,7 @@ msgstr "自定义插件路径" msgid "Custom Ports" msgstr "自定义端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:269 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:283 msgid "Custom YAML imported successfully: %s" msgstr "自定义 YAML 导入成功:%s" @@ -623,7 +623,7 @@ msgstr "自定义客户端代理规则已保存并生效。" msgid "Custom client proxy rules saved." msgstr "自定义客户端代理规则已保存。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1396 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1407 msgid "" "Custom finalmask overrides mkcp, hysteria2, fragment, noise, and related " "settings." @@ -633,7 +633,7 @@ msgstr "自定义 finalmask 将覆盖 mkcp、hysteria2、fragment、noise 等相 msgid "DL Backup" msgstr "下载备份" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1286 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1297 msgid "DNS" msgstr "" @@ -645,8 +645,8 @@ msgstr "DNS 防污染服务" msgid "DNSPod Public DNS (119.29.29.29)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1274 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1284 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1285 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1295 msgid "DTLS 1.2" msgstr "DTLS 1.2 数据包" @@ -662,10 +662,10 @@ msgstr "日/周" msgid "Decryption" msgstr "解密" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1364 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1555 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1567 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1581 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1375 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1566 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1578 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1592 msgid "Default" msgstr "默认" @@ -673,21 +673,21 @@ msgstr "默认" msgid "Default Node Local Port" msgstr "节点默认本地端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1670 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1681 msgid "Default reject rejects traffic." msgstr "默认 reject 拒绝流量。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:803 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:814 msgid "Default value 0 indicatesno heartbeat." msgstr "默认为 0 表示无心跳。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1644 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1655 msgid "" "Default: disable. When entering a negative number, such as -1, The Mux " "module will not be used to carry TCP traffic." msgstr "默认:禁用。填负数时,如 -1,不使用 Mux 模块承载 TCP 流量。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1657 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1668 msgid "" "Default:16. When entering a negative number, such as -1, The Mux module will " "not be used to carry UDP traffic, Use original UDP transmission method of " @@ -725,7 +725,7 @@ msgstr "延迟(ms)" msgid "Delete" msgstr "删除" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:505 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:519 msgid "Delete All Subscribe Servers" msgstr "删除所有订阅节点" @@ -737,8 +737,8 @@ msgstr "删除失败:" msgid "Deny Domain List" msgstr "禁止连接的域名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:715 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1026 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:726 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1037 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client.lua:81 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/control.lua:33 msgid "Disable" @@ -752,19 +752,19 @@ msgstr "直通模式(禁用 ChinaDNS-NG)" msgid "Disable IPv6 for Overseas FQDN" msgstr "禁止海外域名返回 IPv6 记录" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:760 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:771 msgid "Disable QUIC path MTU discovery" msgstr "禁用 QUIC 启用 MTU 探测" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:949 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:960 msgid "Disable SNI" msgstr "关闭 SNI 服务器名称指示" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:830 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:841 msgid "Disable TCP No_delay" msgstr "禁用 TCP 无延迟" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:553 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:567 msgid "Disabled means use Xray or ShadowSocks-Rust core." msgstr "禁用则使用 Xray 或 ShadowSocks-Rust 核心。" @@ -792,7 +792,7 @@ msgstr "域 Socket 路径" msgid "Domestic DNS Server" msgstr "国内 DNS 服务器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1307 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1318 msgid "Downlink Capacity(Default:Mbps)" msgstr "下行链路容量(默认:Mbps)" @@ -804,19 +804,19 @@ msgstr "下载源" msgid "Download failed" msgstr "下载失败" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:960 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:971 msgid "Dual-stack Listening Socket" msgstr "双栈 Socket 监听" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1503 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1514 msgid "ECH Config" msgstr "ECH 配置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1517 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1528 msgid "ECH Query Policy" msgstr "ECH 查询策略" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1099 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1110 msgid "Early Data Header Name" msgstr "前置数据标头" @@ -825,7 +825,7 @@ msgstr "前置数据标头" msgid "Edit" msgstr "编辑" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:341 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:355 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:40 msgid "Edit ShadowSocksR Server" msgstr "编辑服务器配置" @@ -835,60 +835,60 @@ msgstr "编辑服务器配置" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:323 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:54 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:101 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:589 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:603 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:1114 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:184 msgid "Enable" msgstr "启用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:954 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:965 msgid "Enable 0-RTT QUIC handshake" msgstr "客户端启用 0-RTT QUIC 连接握手" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:515 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:526 msgid "Enable Authentication" msgstr "启用用户名/密码认证" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:100 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1794 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1805 msgid "Enable Auto Switch" msgstr "启用自动切换" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1487 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1498 msgid "Enable ECH(optional)" msgstr "启用 ECH (可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:709 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:720 msgid "Enable Lazy Mode" msgstr "启用懒狗模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1525 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1536 msgid "Enable ML-DSA-65(optional)" msgstr "启用 ML-DSA-65 (可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:550 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:564 msgid "Enable Mihomo core" msgstr "启用 Mihomo 核心" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1688 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1699 msgid "" "Enable Multipath TCP, need to be enabled in both server and client " "configuration." msgstr "启用 Multipath TCP,需在服务端和客户端配置中同时启用。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1624 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1635 msgid "Enable Mux.Cool" msgstr "启用 Mux.Cool" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:703 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:714 msgid "Enable Obfuscation" msgstr "启用混淆功能" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:582 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:593 msgid "Enable Plugin" msgstr "启用插件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:671 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:682 msgid "Enable Port Hopping" msgstr "启用端口跳跃" @@ -896,15 +896,15 @@ msgstr "启用端口跳跃" msgid "Enable Server" msgstr "启动服务端" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:684 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:695 msgid "Enable Transport Protocol Settings" msgstr "启用传输协议设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:816 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:827 msgid "Enable V2 protocol." msgstr "开启 V2 协议。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:815 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:826 msgid "Enable V3 protocol." msgstr "开启 V3 协议。" @@ -912,15 +912,15 @@ msgstr "开启 V3 协议。" msgid "Enable adblock" msgstr "启用广告屏蔽" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:571 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:582 msgid "Enable the SUoT protocol, requires server support." msgstr "启用 SUoT 协议,需要服务端支持。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1142 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1153 msgid "Enable this option to configure XHTTP Extra (JSON format)." msgstr "启用此选项配置 XHTTP 附加项(JSON 格式)。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1319 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1330 msgid "Enabled Kernel virtual NIC TUN(optional)" msgstr "启用内核的虚拟网卡 TUN(可选)" @@ -928,16 +928,16 @@ msgstr "启用内核的虚拟网卡 TUN(可选)" msgid "Enabled Mixed" msgstr "启用 Mixed" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:825 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1783 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:836 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1794 msgid "Enabling TCP Fast Open Requires Server Support." msgstr "启用 TCP 快速打开需要服务端支持。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:549 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:556 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:857 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:560 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:567 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:868 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:999 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:879 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1010 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:105 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:110 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:173 @@ -954,39 +954,39 @@ msgstr "输入自定义端口" msgid "Error" msgstr "错误" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:433 msgid "Every Day" msgstr "每天" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:424 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:438 msgid "Every Friday" msgstr "每周五" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:420 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:434 msgid "Every Monday" msgstr "每周一" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:425 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:439 msgid "Every Saturday" msgstr "每周六" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:426 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:440 msgid "Every Sunday" msgstr "每周日" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:423 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:437 msgid "Every Thursday" msgstr "每周四" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:421 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:435 msgid "Every Tuesday" msgstr "每周二" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:422 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:436 msgid "Every Wednesday" msgstr "每周三" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:652 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:663 msgid "Example:" msgstr "示例:" @@ -1002,7 +1002,7 @@ msgstr "批量导出客户端规则" msgid "Extract failed" msgstr "解压失败" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1727 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1738 msgid "FORCE BRUTAL" msgstr "" @@ -1014,7 +1014,7 @@ msgstr "清空所有客户端代理规则失败。" msgid "Failed to create temp directory" msgstr "创建临时目录失败" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:230 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:244 msgid "Failed to create temporary YAML upload file." msgstr "创建临时 YAML 上传文件失败。" @@ -1040,8 +1040,8 @@ msgstr "保存自定义客户端代理规则失败。" msgid "Fetch Failed" msgstr "获取失败" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1608 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1615 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1619 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1626 msgid "Fetch Manually" msgstr "手动获取" @@ -1049,19 +1049,19 @@ msgstr "手动获取" msgid "File Not Exist" msgstr "文件不存在" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:462 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:476 msgid "Filter Words splited by /" msgstr "命中关键字的节点将被丢弃。多个关键字用 / 分隔" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1378 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1389 msgid "FinalMask" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1470 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1481 msgid "Finger Print" msgstr "指纹伪造" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1457 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1468 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:214 msgid "Flow" msgstr "流控(Flow)" @@ -1076,7 +1076,7 @@ msgstr "配备中国大陆 CDN 的 Apple 域名,始终应答中国大陆 CDN msgid "For specific usage, see:" msgstr "具体使用方法,具体请参见:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:678 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:689 msgid "" "Format as 10000:20000 or 10000-20000 Multiple groups are separated by commas " "(,)." @@ -1122,19 +1122,19 @@ msgstr "增强游戏模式客户端 LAN IP" msgid "Game Mode UDP Relay" msgstr "游戏模式 UDP 中继" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:925 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:936 msgid "Garbage collection interval(second)" msgstr "UDP 数据包片残片清理间隔(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:931 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:942 msgid "Garbage collection lifetime(second)" msgstr "UDP 数据包残片在服务器的保留时间(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:729 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:740 msgid "Gecko Packet Size (max)" msgstr "Gecko 包大小(最大)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:722 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:733 msgid "Gecko Packet Size (min)" msgstr "Gecko 包大小(最小)" @@ -1199,20 +1199,20 @@ msgstr "" msgid "Grant UCI access for luci-app-ssr-plus" msgstr "授予访问 luci-app-ssr-plus 配置的权限" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1213 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1224 msgid "Gun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1232 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1243 msgid "H2 Read Idle Timeout" msgstr "H2 读取空闲超时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1227 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1238 msgid "H2/gRPC Health Check" msgstr "H2/gRPC 健康检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:462 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1060 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:473 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1071 msgid "HTTP" msgstr "" @@ -1220,7 +1220,7 @@ msgstr "" msgid "HTTP Auth Mode" msgstr "HTTP 认证模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1064 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1075 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:293 msgid "HTTP Host" msgstr "HTTP 主机名" @@ -1229,7 +1229,7 @@ msgstr "HTTP 主机名" msgid "HTTP Password" msgstr "HTTP 密码" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1069 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1080 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:297 msgid "HTTP Path" msgstr "HTTP 路径" @@ -1242,29 +1242,29 @@ msgstr "HTTP 用户名" msgid "HTTP proxy auth method, default:none." msgstr "HTTP 代理认证方式,默认:none。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1206 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:270 msgid "HTTP/2 Host" msgstr "HTTP/2 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1200 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1211 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:276 msgid "HTTP/2 Path" msgstr "HTTP/2 路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1267 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1278 msgid "Header" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1244 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1255 msgid "Health Check Timeout" msgstr "健康检查超时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:913 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:924 msgid "Heartbeat interval(second)" msgstr "保活心跳包发送间隔(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1086 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1097 msgid "HeartbeatPeriod(second)" msgstr "心跳周期(单位:秒)" @@ -1272,24 +1272,24 @@ msgstr "心跳周期(单位:秒)" msgid "Hour" msgstr "时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1108 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1119 msgid "Httpupgrade Host" msgstr "HTTPUpgrade 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1113 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1124 msgid "Httpupgrade Path" msgstr "HTTPUpgrade 路径" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:420 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:456 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:467 msgid "Hysteria2" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:644 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:655 msgid "Hysteria2 Realms" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:754 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:765 msgid "Hysterir QUIC parameters" msgstr "QUIC 参数" @@ -1297,7 +1297,7 @@ msgstr "QUIC 参数" msgid "IP Route Mode" msgstr "绕过中国大陆 IP 模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1579 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1590 msgid "IP Stack Preference" msgstr "IP 栈优先级" @@ -1305,24 +1305,24 @@ msgstr "IP 栈优先级" msgid "If empty, Not change Apple domains parsing DNS (Default is empty)" msgstr "如果为空,则不更改 Apple 域名解析 DNS(默认为空)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1505 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1516 msgid "" "If it is not empty, it indicates that the Client has enabled Encrypted " "Client, see:" msgstr "如果不为空,表示客户端已启用加密客户端,具体请参见:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:961 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:972 msgid "If this option is not set, the socket behavior is platform dependent." msgstr "如果未设置此选项,则 Socket 行为依赖于平台。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1592 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1603 msgid "" "If true, allowss insecure connection at TLS client, e.g., TLS server uses " "unverifiable certificates." msgstr "" "是否允许不安全连接。当选择时,将不会检查远端主机所提供的 TLS 证书的有效性。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1741 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1752 msgid "If you have a self-signed certificate,please check the box" msgstr "如果你使用自签证书,请选择" @@ -1347,7 +1347,7 @@ msgstr "批量导入客户端规则" msgid "Import configuration information successfully." msgstr "导入配置信息成功。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1220 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1231 msgid "Initial Windows Size" msgstr "初始窗口大小" @@ -1383,7 +1383,7 @@ msgstr "接口控制" msgid "Invalid" msgstr "无效的" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:658 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:669 msgid "Invalid Realm URL." msgstr "Realm URL 不正确。" @@ -1427,19 +1427,19 @@ msgstr "KCP 写缓冲区大小" msgid "KcpTun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1799 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1810 msgid "KcpTun Enable" msgstr "KcpTun 启用" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1819 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1830 msgid "KcpTun Param" msgstr "KcpTun 参数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1813 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1824 msgid "KcpTun Password" msgstr "KcpTun 密码" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1806 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1817 msgid "KcpTun Port" msgstr "KcpTun 端口" @@ -1518,7 +1518,7 @@ msgstr "" msgid "Limit the maximum number of splits." msgstr "限制分片的最大数量。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1322 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1333 msgid "" "Linux kernel TUN virtual NIC requires system support and root privileges." msgstr "Linux 内核 TUN 虚拟网卡需要系统支持和 root 权限。" @@ -1542,7 +1542,7 @@ msgstr "本地端口" msgid "Local Servers" msgstr "本机服务端" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1330 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1341 msgid "Local addresses" msgstr "本地地址" @@ -1550,7 +1550,7 @@ msgstr "本地地址" msgid "Log" msgstr "日志" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:413 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:427 msgid "Loop Mode" msgstr "循环模式" @@ -1562,15 +1562,15 @@ msgstr "" msgid "Loyalsoldier/v2ray-rules-dat" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1530 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1541 msgid "ML-DSA-65 Public key" msgstr "ML-DSA-65 公钥" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1688 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1699 msgid "MPTCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1293 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1304 msgid "MTU" msgstr "最大传输单元" @@ -1578,7 +1578,7 @@ msgstr "最大传输单元" msgid "Main Server" msgstr "主服务器" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:587 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:601 msgid "" "Manage multiple subscribe URLs, including Clash subscriptions. Only enabled " "entries are included when updating all subscriptions." @@ -1591,7 +1591,7 @@ msgstr "" msgid "Matching release asset not found" msgstr "未找到匹配的发布资产" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1092 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1103 msgid "Max Early Data" msgstr "最大前置数据" @@ -1599,7 +1599,7 @@ msgstr "最大前置数据" msgid "Max Split" msgstr "最大分片数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:966 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:977 msgid "Maximum packet size the socks5 server can receive from external" msgstr "socks5 服务器可以从外部接收的最大数据包大小(单位:字节)" @@ -1622,7 +1622,7 @@ msgstr "Mihomo 面板" msgid "Min" msgstr "分" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1658 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1669 msgid "" "Min value is 1, Max value is 1024. When omitted or set to 0, Will same path " "as TCP traffic." @@ -1630,7 +1630,7 @@ msgstr "" "最小值 1,最大值 1024。 省略或者填 0 时,将与 TCP 流量走同一条路,也就是传统" "的行为。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1645 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1656 msgid "" "Min value is 1, Max value is 128. When omitted or set to 0, it equals 8." msgstr "最小值 1,最大值 128。省略或者填 0 时都等于 8。" @@ -1667,7 +1667,7 @@ msgstr "上移" msgid "Muitiple DNS server can saperate with ','" msgstr "多个上游 DNS 服务器请用 ',' 分隔(注意用英文逗号)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1214 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1225 msgid "Multi" msgstr "" @@ -1675,12 +1675,12 @@ msgstr "" msgid "Multi Threads Option" msgstr "多线程并发转发" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1184 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1414 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1195 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1425 msgid "Must be JSON text!" msgstr "必须是 JSON 文本内容!" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1624 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1635 msgid "Mux" msgstr "" @@ -1693,7 +1693,7 @@ msgid "NOT RUNNING" msgstr "未运行" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:414 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:387 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:398 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:17 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/component.htm:471 msgid "NaiveProxy" @@ -1707,7 +1707,7 @@ msgstr "" msgid "Nanjing Xinfeng 114DNS (114.114.114.114)" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:909 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:920 msgid "New Reno" msgstr "" @@ -1743,7 +1743,7 @@ msgstr "没有可用的核心(Mihomo 或 Xray)可以导入此节点。" msgid "No available core (Shadowsocks, Mihomo or Xray) to import this node." msgstr "没有可用的核心(Shadowsocks, Mihomo 或 Xray)可以导入此节点。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:249 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:263 msgid "No custom YAML file was selected." msgstr "没有选择自定义 YAML 文件。" @@ -1755,7 +1755,7 @@ msgstr "暂无自定义客户端代理规则。" msgid "No new data!" msgstr "你已经是最新数据,无需更新!" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1773 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1784 msgid "No specify upload file." msgstr "没有上传证书。" @@ -1768,7 +1768,7 @@ msgstr "没有找到任何订阅项" msgid "No switchable proxy groups found." msgstr "未找到可切换的代理组。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:611 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:625 msgid "" "Node order can be dragged with the mouse and takes effect immediately. The " "automatic switch order of server nodes is consistent with the node order in " @@ -1780,13 +1780,13 @@ msgstr "" msgid "Noise" msgstr "噪声" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:590 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1059 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1258 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1270 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1280 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:706 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:711 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:601 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1070 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1269 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1281 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1291 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:720 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:725 msgid "None" msgstr "" @@ -1826,35 +1826,35 @@ msgid "" "saperate with ','." msgstr "注意:当版本高于 26.6.1 时,可以输入多个分片长度,并用英文 ',' 分隔。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1699 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1710 msgid "Number of early established connections to reduce latency." msgstr "预连接的数量,用于降低延迟。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:589 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:632 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:600 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:643 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:120 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:138 msgid "Obfs" msgstr "混淆插件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:639 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:650 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:125 msgid "Obfs param (optional)" msgstr "混淆参数(可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1314 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1325 msgid "Obfuscate password (optional)" msgstr "混淆密码(可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:736 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:747 msgid "Obfuscation Password" msgstr "混淆密码" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:714 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:725 msgid "Obfuscation Type" msgstr "混淆类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1607 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1618 msgid "Once set, connects only when the server’s chain fingerprint matches." msgstr "设置后,仅在服务器证书链指纹匹配时连接。" @@ -1918,7 +1918,7 @@ msgstr "数据包 | Rand 长度" msgid "Panel" msgstr "面板" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:529 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:540 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:95 msgid "Password" msgstr "密码" @@ -1927,7 +1927,7 @@ msgstr "密码" msgid "Paste sharing link here" msgstr "在此处粘贴分享链接" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1345 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1356 msgid "Peer public key" msgstr "节点公钥" @@ -1940,15 +1940,15 @@ msgstr "每页" msgid "Perform reset" msgstr "执行重置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1250 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1261 msgid "Permit Without Stream" msgstr "允许无数据流" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:754 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:768 msgid "Ping Latency" msgstr "Ping 延迟" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1780 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1791 msgid "Please confirm the current certificate path" msgstr "请选择确认所传证书,证书不正确将无法运行" @@ -1956,11 +1956,11 @@ msgstr "请选择确认所传证书,证书不正确将无法运行" msgid "Please fill in reset" msgstr "请填写 reset" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:425 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:436 msgid "Please specify either a Clash subscription URL or a local YAML path." msgstr "请填写 Clash 订阅 URL 或本地 YAML 路径中的至少一项。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:618 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:629 msgid "Plugin Opts" msgstr "插件参数" @@ -1968,19 +1968,19 @@ msgstr "插件参数" msgid "Policy" msgstr "策略" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:695 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:706 msgid "Port Hopping Interval(Unit:Second)" msgstr "端口跳跃间隔(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:677 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:688 msgid "Port hopping range" msgstr "端口跳跃范围" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1699 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1710 msgid "Pre-connections" msgstr "预连接" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1349 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1360 msgid "Pre-shared key" msgstr "预共享密钥" @@ -1996,7 +1996,7 @@ msgstr "上一页" msgid "Private Key File Path" msgstr "私钥文件路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1340 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1351 msgid "Private key" msgstr "私钥" @@ -2005,13 +2005,13 @@ msgstr "私钥" msgid "Processing..." msgstr "处理中..." -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:622 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:633 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:115 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:133 msgid "Protocol" msgstr "传输协议" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:629 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:640 msgid "Protocol param (optional)" msgstr "传输协议参数(可选)" @@ -2019,7 +2019,7 @@ msgstr "传输协议参数(可选)" msgid "Proxy Ports" msgstr "需要代理的端口" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1444 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1455 msgid "Public key" msgstr "公钥" @@ -2027,33 +2027,33 @@ msgstr "公钥" msgid "QUIC Camouflage Type" msgstr "QUIC 伪装(混淆)类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1263 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1274 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:369 msgid "QUIC Key" msgstr "QUIC 密钥" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1256 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1267 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:361 msgid "QUIC Security" msgstr "QUIC 加密方式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:781 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:792 msgid "QUIC initConnReceiveWindow" msgstr "QUIC 初始的连接接收窗口大小" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:767 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:778 msgid "QUIC initStreamReceiveWindow" msgstr "QUIC 初始流接收窗口大小。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:788 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:799 msgid "QUIC maxConnReceiveWindow" msgstr "QUIC 最大的连接接收窗口大小" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:795 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:806 msgid "QUIC maxIdleTimeout(Unit:second)" msgstr "QUIC 最长空闲超时时间(单位:秒)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:774 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:785 msgid "QUIC maxStreamReceiveWindow" msgstr "QUIC 最大的流接收窗口大小" @@ -2061,7 +2061,7 @@ msgstr "QUIC 最大的流接收窗口大小" msgid "QUIC protocols such as HY2 also require curl with http3 support." msgstr "HY2 等 QUIC 协议还需要 curl 支持 http3。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1439 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1450 msgid "REALITY" msgstr "" @@ -2095,15 +2095,15 @@ msgstr "就绪。" msgid "Really reset all changes?" msgstr "真的重置所有更改吗?" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:661 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:672 msgid "Realm STUN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:652 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:663 msgid "Realm URL" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:773 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:787 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_main_panel.htm:348 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_panel_button.htm:17 msgid "Reapply" @@ -2137,11 +2137,11 @@ msgstr "更新成功!" msgid "Refresh..." msgstr "正在更新,请稍候..." -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:431 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:445 msgid "Regular update (Hour)" msgstr "定时更新(小时)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:439 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:453 msgid "Regular update (Min)" msgstr "定时更新(分钟)" @@ -2165,8 +2165,8 @@ msgstr "正在重载 YAML..." msgid "Remarks" msgstr "备注" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1712 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1728 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1723 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1739 msgid "Reno" msgstr "Reno" @@ -2178,7 +2178,7 @@ msgstr "VMess/VLESS 协议必需,可使用:uuidgen 命令生成。" msgid "Requires OpenSSL to retrieve the TLS certificate chain fingerprint." msgstr "获取 TLS 证书链指纹需要 OpenSSL 支持。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1335 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1346 msgid "Reserved bytes(optional)" msgstr "保留字节(可选)" @@ -2277,16 +2277,16 @@ msgstr "服务端" msgid "Save" msgstr "保存" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:493 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:507 msgid "Save Subscribe Settings" msgstr "保存订阅设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:468 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:482 msgid "Save Words splited by /" msgstr "" "命中关键字的节点将被保留。多个关键字用 / 分隔。此项为空则不启用保留匹配" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:495 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:509 msgid "Save current subscribe settings" msgstr "保存当前订阅设置" @@ -2304,15 +2304,15 @@ msgstr "保存中..." msgid "Second" msgstr "周期" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1733 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1744 msgid "Self-signed Certificate" msgstr "自签证书" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:465 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:476 msgid "Server Address" msgstr "服务器地址" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:507 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:521 msgid "Server Count" msgstr "服务器节点数量" @@ -2320,11 +2320,11 @@ msgstr "服务器节点数量" msgid "Server Name (SNI)" msgstr "服务器名称(SNI)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:384 msgid "Server Node Type" msgstr "服务器节点类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:490 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:501 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:77 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:117 msgid "Server Port" @@ -2347,37 +2347,37 @@ msgstr "服务器节点故障自动切换/广告屏蔽/中国大陆 IP 段数据 msgid "Servers Nodes" msgstr "服务器节点" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:393 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:407 msgid "Servers subscription and manage" msgstr "服务器节点订阅与管理" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1433 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1444 msgid "Session Ticket" msgstr "会话凭据" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:396 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:604 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:407 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:615 msgid "Shadow-TLS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:842 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:853 msgid "Shadow-TLS ChainPoxy type" msgstr "代理链类型" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:377 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:381 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:451 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:392 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:462 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:61 msgid "ShadowSocks" msgstr "" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:389 #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:391 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:384 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:395 msgid "ShadowSocks-Rust" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:845 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:856 msgid "ShadowSocks-rust Version" msgstr "ShadowSocks-rust 版本" @@ -2393,18 +2393,18 @@ msgstr "ShadowSocksR Plus+ 设置" msgid "ShadowTLS" msgstr "ShadowTLS" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:853 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:864 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:168 msgid "Shadowsocks Password" msgstr "" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:385 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:378 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:389 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:64 msgid "ShadowsocksR" msgstr "ShadowsocksR" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1448 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1459 msgid "Short ID" msgstr "" @@ -2412,35 +2412,35 @@ msgstr "" msgid "Showing %d-%d of %d nodes" msgstr "当前显示第 %d-%d 个节点,共 %d 个" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:459 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:470 msgid "Snell" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1025 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1036 msgid "Snell Obfs" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1033 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1044 msgid "Snell Obfs Host" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:544 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:555 msgid "Snell PSK" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1015 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1026 msgid "Snell Version" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:714 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:728 msgid "Socket Connected" msgstr "连接测试" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:461 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:472 msgid "Socks" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1007 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1018 msgid "Socks Version" msgstr "Socks 版本" @@ -2448,7 +2448,7 @@ msgstr "Socks 版本" msgid "Socks protocol auth methods, default:noauth." msgstr "Socks 协议的认证方式,默认值:noauth。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:399 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:410 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:59 msgid "Socks5" msgstr "" @@ -2491,19 +2491,19 @@ msgstr "状态" msgid "Stop Detection" msgstr "停止探测" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:453 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:467 msgid "Subscribe Advanced Settings" msgstr "订阅高级设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:555 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:569 msgid "Subscribe Convert Online" msgstr "在线订阅转换" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:479 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:493 msgid "Subscribe Default Auto-Switch" msgstr "订阅新节点自动切换设置" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:459 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:473 msgid "Subscribe Filter Words" msgstr "订阅节点关键字过滤" @@ -2511,16 +2511,16 @@ msgstr "订阅节点关键字过滤" msgid "Subscribe Log" msgstr "订阅日志" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:466 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:480 msgid "Subscribe Save Words" msgstr "订阅节点关键字保留检查" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:569 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:583 msgid "Subscribe Template URL" msgstr "订阅转换模板 URL" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:580 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:604 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:594 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:618 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/subscribe_actions_footer.htm:189 msgid "Subscribe URL" msgstr "订阅 URL (支持SS/SSR/V2/TROJAN/HY2/TUIC/CLASH等)" @@ -2529,11 +2529,11 @@ msgstr "订阅 URL (支持SS/SSR/V2/TROJAN/HY2/TUIC/CLASH等)" msgid "Subscribe failed, refreshing page..." msgstr "订阅失败,正在刷新页面..." -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:481 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:495 msgid "Subscribe new add server default Auto-Switch on" msgstr "订阅加入的新节点默认开启自动切换" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:474 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:488 msgid "Subscribe nodes allows insecure connection as TLS client (insecure)" msgstr "订阅节点强制开启 不验证TLS客户端证书 (insecure)" @@ -2549,11 +2549,11 @@ msgstr "已成功获取证书名称:" msgid "Support AdGuardHome and DNSMASQ format list" msgstr "同时支持 AdGuard Home 和 DNSMASQ 格式的过滤列表" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:696 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:707 msgid "Supports a fixed value or a random range (e.g., 30, 5-30), minimum 5." msgstr "支持固定值或随机范围(如 30 或 5-30),最小 5 秒。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1336 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1347 msgid "" "Supports decimal numbers separated by \",\" or Base64-encoded strings, with " "a maximum length of 3 bytes." @@ -2584,8 +2584,8 @@ msgstr "正在切换..." msgid "TCP Camouflage Type" msgstr "TCP 伪装类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:825 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1783 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:836 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1794 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:128 msgid "TCP Fast Open" msgstr "TCP 快速打开" @@ -2600,65 +2600,65 @@ msgstr "TCP 分片,在某些情况下可以欺骗审查系统,比如绕过 S msgid "TCP upstream" msgstr "TCP 上游" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1419 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1430 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:201 msgid "TLS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:820 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:831 msgid "TLS 1.3 Strict mode" msgstr "TLS 1.3 限定模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1553 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1564 msgid "TLS ALPN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1611 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1622 msgid "TLS Certificate Name (CertName)" msgstr "TLS 证书名称(CertName)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1604 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1615 msgid "TLS Chain Fingerprint (SHA256)" msgstr "TLS 证书链指纹(SHA256)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1545 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1556 msgid "TLS Host" msgstr "TLS 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1614 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1625 msgid "TLS is used to verify the leaf certificate name." msgstr "TLS 用于验证 leaf 证书的 name。" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:383 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:393 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:404 msgid "TUIC" msgstr "TUIC" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1565 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1576 msgid "TUIC ALPN" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:885 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:896 msgid "TUIC Server IP Address" msgstr "TUIC 服务器 IP 地址" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:892 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:903 msgid "TUIC User Password" msgstr "TUIC 用户密钥" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:878 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:889 msgid "TUIC User UUID" msgstr "TUIC 用户 uuid" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:943 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:954 msgid "TUIC receive window" msgstr "接收窗口(无需确认即可接收的最大字节数:默认8Mb)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:937 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:948 msgid "TUIC send window" msgstr "发送窗口(无需确认即可发送的最大字节数:默认8Mb*2)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1532 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1543 msgid "" "The client has not configured mldsa65Verify, but it will not perform the " "\"additional verification\" step and can still connect normally, see:" @@ -2670,7 +2670,7 @@ msgstr "" msgid "The content entered is incorrect!" msgstr "输入的内容不正确!" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:802 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:813 msgid "The keep-alive period.(Unit:second)" msgstr "心跳包发送间隔(单位:秒)" @@ -2726,11 +2726,11 @@ msgstr "该面板仅在当前 Clash 总节点已启用时可用。" msgid "This section contains no values yet" msgstr "该部分目前无任何内容。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:486 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:500 msgid "Through proxy update" msgstr "通过代理更新" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:488 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:502 msgid "Through proxy update list, Not Recommended" msgstr "通过路由器自身代理更新订阅" @@ -2738,7 +2738,7 @@ msgstr "通过路由器自身代理更新订阅" msgid "Timeout" msgstr "超时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:919 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:930 msgid "Timeout for establishing a connection to server(second)" msgstr "连接超时时间(单位:秒)" @@ -2750,18 +2750,18 @@ msgstr "在 Xray 设置中勾选 “噪声” 以发送噪声包。" msgid "Total Records:" msgstr "新的总记录数:" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1038 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1049 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:179 msgid "Transport" msgstr "传输协议" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:689 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:700 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:240 msgid "Transport Protocol" msgstr "传输协议" #: applications/luci-app-ssr-plus/luasrc/controller/shadowsocksr.lua:412 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:450 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:461 msgid "Trojan" msgstr "Trojan" @@ -2774,11 +2774,11 @@ msgid "Try Count" msgstr "重试次数" #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/advanced.lua:327 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:703 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:717 msgid "Type" msgstr "类型" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:691 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:702 msgid "UDP" msgstr "" @@ -2788,11 +2788,11 @@ msgid "" "restrictions." msgstr "UDP 噪声,在某些情况下可以绕过一些针对 UDP 协议的限制。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:570 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:581 msgid "UDP over TCP" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:898 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:909 msgid "UDP relay mode" msgstr "UDP 中继模式" @@ -2808,7 +2808,7 @@ msgstr "UDP/TCP 上游" msgid "UL Restore" msgstr "上传恢复" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:525 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:539 msgid "URL Test Address" msgstr "URL 测试地址" @@ -2857,19 +2857,19 @@ msgstr "不支持的包管理器" msgid "Update" msgstr "更新" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:498 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:512 msgid "Update All Subscribe Servers" msgstr "更新所有订阅节点" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:447 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:461 msgid "Update Interval(min)" msgstr "更新间隔(分钟)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:411 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:425 msgid "Update Mode" msgstr "更新模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:418 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:432 msgid "Update cycle (Day/Week)" msgstr "更新周期(天/周)" @@ -2916,21 +2916,21 @@ msgstr "升级完成" msgid "Upgrading..." msgstr "升级中..." -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1300 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1311 msgid "Uplink Capacity(Default:Mbps)" msgstr "上行链路容量(默认:Mbps)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1743 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1754 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/certupload.htm:3 #: applications/luci-app-ssr-plus/luasrc/view/shadowsocksr/clash_yaml_upload.htm:3 msgid "Upload" msgstr "上传" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:546 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:560 msgid "Upload Custom YAML File" msgstr "上传自定义 YAML 文件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:548 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:562 msgid "" "Upload a custom Clash/Mihomo YAML file. The file will be preprocessed and " "saved as a local Clash node." @@ -2938,9 +2938,9 @@ msgstr "" "上传自定义 Clash/Mihomo YAML 文件。文件会先做预处理,再保存为本地 Clash 节" "点。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:263 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:271 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:276 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:277 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:285 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:290 msgid "Uploaded YAML validation or preprocessing failed." msgstr "上传的 YAML 校验或预处理失败。" @@ -2968,7 +2968,7 @@ msgstr "使用本机端口为 5335 的 DNS 服务" msgid "Use MosDNS query" msgstr "使用 MosDNS 查询" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1290 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1301 msgid "" "Use it together with the DNS disguised type. You can fill in any domain." msgstr "配合伪装类型 DNS 使用,可随便填一个域名。" @@ -2981,8 +2981,8 @@ msgstr "用户等级" msgid "User cancelled." msgstr "用户已取消。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1362 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:536 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1373 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/servers.lua:550 msgid "User-Agent" msgstr "用户代理(User-Agent)" @@ -2991,17 +2991,17 @@ msgstr "用户代理(User-Agent)" msgid "Userinfo format error." msgstr "用户信息格式错误。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:522 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:533 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:91 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server.lua:122 msgid "Username" msgstr "用户名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:665 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:676 msgid "Users Authentication" msgstr "用户验证" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:409 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:420 msgid "Using incorrect encryption mothod may causes service fail to start" msgstr "输入不正确的参数组合可能会导致服务无法启动" @@ -3015,40 +3015,40 @@ msgstr "V2Ray GeoIP 数据库" msgid "V2Ray GeoSite Databases" msgstr "V2Ray GeoSite 数据库" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:375 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:386 msgid "V2Ray/XRay" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:447 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:458 msgid "V2Ray/XRay protocol" msgstr "V2Ray/XRay 协议" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:448 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:459 msgid "VLESS" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:988 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:999 msgid "VLESS Encryption" msgstr "VLESS 加密" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:449 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:460 msgid "VMess" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1271 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1281 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1282 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1292 msgid "VideoCall (SRTP)" msgstr "视频通话(SRTP)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:848 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:859 msgid "Vmess Protocol" msgstr "VMESS 协议" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:863 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:874 msgid "Vmess UUID" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:980 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:991 msgid "Vmess/VLESS ID (UUID)" msgstr "" @@ -3064,22 +3064,22 @@ msgstr "WAN IP 访问控制" msgid "WAN White List IP" msgstr "不走代理的 WAN IP" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1075 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1086 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:254 msgid "WebSocket Host" msgstr "WebSocket 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1081 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1092 #: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/server-config.lua:261 msgid "WebSocket Path" msgstr "WebSocket 路径" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1273 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1283 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1284 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1294 msgid "WechatVideo" msgstr "微信视频通话" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1323 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1334 msgid "When enabled, it occupies IPv6 routing table 1023." msgstr "启用后,将占用 IPv6 路由表 1023。" @@ -3093,29 +3093,29 @@ msgid "" "reverse proxies." msgstr "一旦启用,它只能在本地进行访问。在使用“反向代理”时建议使用此功能。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:453 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1275 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1285 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:464 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1286 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1296 msgid "WireGuard" msgstr "WireGuard 数据包" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1355 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1366 msgid "Wireguard allows only traffic from specific source IP." msgstr "Wireguard 仅允许特定源 IP 的流量。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1141 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1152 msgid "XHTTP Extra" msgstr "XHTTP 附加项" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1129 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1140 msgid "XHTTP Host" msgstr "XHTTP 主机名" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1120 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1131 msgid "XHTTP Mode" msgstr "XHTTP 模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1135 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1146 msgid "XHTTP Path" msgstr "XHTTP 路径" @@ -3158,27 +3158,27 @@ msgstr "是" msgid "adblock_url" msgstr "广告屏蔽更新 URL" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1259 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1270 msgid "aes-128-gcm" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1677 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1688 msgid "allow" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1671 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1682 msgid "allow: Allows use Mux connection." msgstr "allow:允许走 Mux 连接。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1587 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1598 msgid "allowInsecure" msgstr "允许不安全连接" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1354 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1365 msgid "allowedIPs(optional)" msgstr "allowedIPs(可选)" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1476 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1487 msgid "android" msgstr "" @@ -3186,7 +3186,7 @@ msgstr "" msgid "anti-AD" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1260 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1271 msgid "chacha20-poly1305" msgstr "" @@ -3194,32 +3194,32 @@ msgstr "" msgid "china-operator-ip" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1365 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1472 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1376 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1483 msgid "chrome" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1708 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1724 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1719 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1735 msgid "comment_tcpcongestion_disable" msgstr "系统默认值" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1641 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1652 msgid "concurrency" msgstr "TCP 最大并发连接数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1370 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1381 msgid "curl" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1705 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1721 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1716 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1732 msgid "custom_tcpcongestion" msgstr "连接服务器节点的 TCP 拥塞控制算法" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1483 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1649 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1662 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1494 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1660 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1673 msgid "disable" msgstr "禁用" @@ -3231,8 +3231,8 @@ msgstr "例如:/etc/ssl/fullchain.pem" msgid "e.g.: /etc/ssl/private.key" msgstr "例如:/etc/ssl/private.key" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1368 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1477 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1379 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1488 msgid "edge" msgstr "" @@ -3240,20 +3240,20 @@ msgstr "" msgid "felixonmars/dnsmasq-china-list" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1366 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1473 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1377 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1484 msgid "firefox" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1238 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1249 msgid "gRPC Idle Timeout" msgstr "gPRC 空闲超时" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1211 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1222 msgid "gRPC Mode" msgstr "gRPC 模式" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1205 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1216 msgid "gRPC Service Name" msgstr "gRPC 服务名称" @@ -3265,23 +3265,23 @@ msgstr "GFW 列表更新 URL" msgid "gfwlist/gfwlist" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1369 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1380 msgid "golang" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:598 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:609 msgid "gost-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1475 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1486 msgid "ios" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:608 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:619 msgid "kcptun" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:901 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:912 msgid "lossless UDP relay using QUIC streams" msgstr "使用 QUIC 流的无损 UDP 中继" @@ -3297,68 +3297,68 @@ msgstr "压缩包中未找到 mihomo 二进制文件" msgid "naive binary not found in archive" msgstr "压缩包中未找到 naive 二进制文件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:900 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:911 msgid "native UDP characteristics" msgstr "原生 UDP 特性" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:560 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1461 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:571 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1472 msgid "none" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:592 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:603 msgid "obfs-local" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1479 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1490 msgid "qq" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1480 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1491 msgid "random" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1481 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1492 msgid "randomized" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1676 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1687 msgid "reject" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:607 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:618 msgid "restls" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1367 -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1474 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1378 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1485 msgid "safari" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:835 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:846 msgid "shadow-TLS SNI" msgstr "服务器名称指示" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:813 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:824 msgid "shadowTLS protocol Version" msgstr "ShadowTLS 协议版本" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1678 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1689 msgid "skip" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1672 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1683 msgid "" "skip: Not use Mux module to carry UDP 443 traffic, Use original UDP " "transmission method of proxy protocol." msgstr "" "skip:不使用 Mux 模块承载 UDP 443 流量,将使用代理协议原本的 UDP 传输方式。" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1452 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1463 msgid "spiderX" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1482 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1493 msgid "unsafe" msgstr "" @@ -3366,7 +3366,7 @@ msgstr "" msgid "v2fly/domain-list-community" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:595 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:606 msgid "v2ray-plugin" msgstr "" @@ -3382,15 +3382,15 @@ msgstr "警告!请不要重复使用端口!" msgid "xray binary not found in archive" msgstr "压缩包中未找到 xray 二进制文件" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:601 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:612 msgid "xray-plugin" msgstr "" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1654 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1665 msgid "xudpConcurrency" msgstr "UDP 最大并发连接数" -#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1667 +#: applications/luci-app-ssr-plus/luasrc/model/cbi/shadowsocksr/client-config.lua:1678 msgid "xudpProxyUDP443" msgstr "对被代理的 UDP/443 流量处理方式" diff --git a/luci-app-syncthing/Makefile b/luci-app-syncthing/Makefile new file mode 100644 index 00000000..2219fcb2 --- /dev/null +++ b/luci-app-syncthing/Makefile @@ -0,0 +1,22 @@ +# Copyright (C) 2020 Gyj1109 +# 适配 OpenWrt 25.12 修改版 + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-app-syncthing +PKG_VERSION:=1.0 +PKG_RELEASE:=3 + +LUCI_TITLE:=LuCI support for Syncthing +LUCI_PKGARCH:=all +# 适配 25.12:确保安装了 syncthing 后,LuCI 界面能正确拉起 +LUCI_DEPENDS:=+syncthing + +include $(TOPDIR)/feeds/luci/luci.mk + +# 明确定义配置文件的归属,这对 25.12 的 apk 管理器非常重要 +define Package/$(PKG_NAME)/conffiles +/etc/config/syncthing +endef + +$(eval $(call BuildPackage,$(PKG_NAME))) diff --git a/luci-app-syncthing/README.md b/luci-app-syncthing/README.md new file mode 100644 index 00000000..b07298c1 --- /dev/null +++ b/luci-app-syncthing/README.md @@ -0,0 +1,2 @@ +# luci-app-syncthing +在Potat0000源码基础上进行了汉化优化,官方openwrt23.05.3编译后可使用 diff --git a/luci-app-syncthing/luasrc/controller/syncthing.lua b/luci-app-syncthing/luasrc/controller/syncthing.lua new file mode 100644 index 00000000..ee2ca7ef --- /dev/null +++ b/luci-app-syncthing/luasrc/controller/syncthing.lua @@ -0,0 +1,17 @@ +module("luci.controller.syncthing", package.seeall) + +function index() + if not nixio.fs.access("/etc/config/syncthing") then + return + end + + entry({"admin", "services", "syncthing"}, cbi("syncthing"), _("文件同步"), 10).dependent = true + entry({"admin", "services", "syncthing", "status"}, call("act_status")).leaf = true +end + +function act_status() + local e = {} + e.running = luci.sys.call("pgrep syncthing >/dev/null") == 0 + luci.http.prepare_content("application/json") + luci.http.write_json(e) +end diff --git a/luci-app-syncthing/luasrc/model/cbi/syncthing.lua b/luci-app-syncthing/luasrc/model/cbi/syncthing.lua new file mode 100644 index 00000000..324ea054 --- /dev/null +++ b/luci-app-syncthing/luasrc/model/cbi/syncthing.lua @@ -0,0 +1,48 @@ +require("nixio.fs") + +m = Map("syncthing", translate("Syncthing同步工具")) + +m:section(SimpleSection).template = "syncthing/syncthing_status" + +s = m:section(TypedSection, "syncthing") + +s.anonymous = true + +o = s:option(Flag, "enabled", translate("启用")) +o.default = 0 +o.rmempty = false + +gui_address = s:option(Value, "gui_address", translate("GUI访问地址")) +gui_address.description = translate("使用0.0.0.0以监控所有访问。") +gui_address.default = "http://0.0.0.0:8384" +gui_address.placeholder = "http://0.0.0.0:8384" +gui_address.rmempty = false + +home = s:option(Value, "home", translate("配置文件目录")) +home.description = translate("只有保存在/etc/syncthing中的配置会自动备份!") +home.default = "/etc/syncthing" +home.placeholder = "/etc/syncthing" +home.rmempty = false + +user = s:option(ListValue, "user", translate("用户")) +user.description = translate("默认是syncthing,但这可能会导致权限被拒绝。Syncthing官方不建议以root身份运行。") +user:value("", translate("syncthing")) +for u in luci.util.execi("cat /etc/passwd | cut -d ':' -f1") do + user:value(u) +end + +macprocs = s:option(Value, "macprocs", translate("线程限制")) +macprocs.description = translate("0表示匹配CPU数量(默认),>0表示显式指定并发数。") +macprocs.default = "0" +macprocs.placeholder = "0" +macprocs.datatype = "range(0,32)" +macprocs.rmempty = false + +nice = s:option(Value, "nice", translate("优先级")) +nice.description = translate("显式指定优先级值。0是最高,19是最低。(暂时不允许设置负值)") +nice.default = "19" +nice.placeholder = "19" +nice.datatype = "range(0,19)" +nice.rmempty = false + +return m diff --git a/luci-app-syncthing/luasrc/view/syncthing/syncthing_status.htm b/luci-app-syncthing/luasrc/view/syncthing/syncthing_status.htm new file mode 100644 index 00000000..566cc020 --- /dev/null +++ b/luci-app-syncthing/luasrc/view/syncthing/syncthing_status.htm @@ -0,0 +1,27 @@ + + +
      +

      + <%:正在收集数据...%> +

      +
      diff --git a/luci-app-syncthing/root/etc/uci-defaults/luci-syncthing b/luci-app-syncthing/root/etc/uci-defaults/luci-syncthing new file mode 100644 index 00000000..3adb7997 --- /dev/null +++ b/luci-app-syncthing/root/etc/uci-defaults/luci-syncthing @@ -0,0 +1,12 @@ +#!/bin/sh +touch /etc/config/syncthing + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@syncthing[-1] + add ucitrack syncthing + set ucitrack.@syncthing[-1].exec='/etc/init.d/syncthing stop && /etc/init.d/syncthing start' + commit ucitrack +EOF +# remove LuCI cache +rm -f /tmp/luci* +exit 0 diff --git a/luci-app-syncthing/root/usr/share/rpcd/acl.d/luci-app-syncthing.json b/luci-app-syncthing/root/usr/share/rpcd/acl.d/luci-app-syncthing.json new file mode 100644 index 00000000..9fc9cc54 --- /dev/null +++ b/luci-app-syncthing/root/usr/share/rpcd/acl.d/luci-app-syncthing.json @@ -0,0 +1,11 @@ +{ + "luci-app-syncthing": { + "description": "Grant UCI access for luci-app-syncthing", + "read": { + "uci": [ "syncthing" ] + }, + "write": { + "uci": [ "syncthing" ] + } + } +} diff --git a/sing-box/Makefile b/sing-box/Makefile index 60235564..904be8a8 100644 --- a/sing-box/Makefile +++ b/sing-box/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=sing-box -PKG_VERSION:=1.13.18 +PKG_VERSION:=1.13.19 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/SagerNet/sing-box/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=e41ed9d7adecd7597c1d5cc91818366a9538d94b41c244225ac40ac948c643f5 +PKG_HASH:=abc2f4805b3fd088c18a5694b51fed6f0e1d06632fae98029d6bf7bd79a1b3a2 PKG_LICENSE:=GPL-3.0-or-later PKG_LICENSE_FILES:=LICENSE