diff --git a/clashoo/Makefile b/clashoo/Makefile
index ddb5515f..e6b49d1d 100644
--- a/clashoo/Makefile
+++ b/clashoo/Makefile
@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=clashoo
-PKG_SHORT_SHA:=a91201f
+PKG_SHORT_SHA:=d5f57a5
PKG_COMMIT_DATE:=2026.09.08
PKG_VERSION:=$(PKG_COMMIT_DATE)~$(PKG_SHORT_SHA)
@@ -11,8 +11,8 @@ PKG_SOURCE:=$(PKG_NAME)-alpha-$(PKG_SHORT_SHA).tar.gz
PKG_SOURCE_SUBDIR:=$(PKG_NAME)-alpha-$(PKG_SHORT_SHA)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-alpha-$(PKG_SHORT_SHA)
PKG_SOURCE_URL:=https://github.com/kenzok8/openwrt-clashoo/releases/download/mihomo-src
-PKG_SOURCE_VERSION:=a91201f1fc1eb9576f284a4655d819326662fb61
-PKG_HASH:=ca9c09031531332890ceadab7748ad33a24e391eac1b8a6de929c38151eeca7e
+PKG_SOURCE_VERSION:=d5f57a5e290eafd77a2b28d8db36e3bd70071398
+PKG_HASH:=1c657c4abdf3f87b51a1f1af1cc9c97b71c1d8a498fd3d9ef31cb9db63b12214
PKG_BUILD_VERSION:=alpha-$(PKG_SHORT_SHA)
PKG_LICENSE:=GPL3.0+
diff --git a/luci-app-passwall/luasrc/controller/passwall.lua b/luci-app-passwall/luasrc/controller/passwall.lua
index e9fa889f..71ec33ca 100644
--- a/luci-app-passwall/luasrc/controller/passwall.lua
+++ b/luci-app-passwall/luasrc/controller/passwall.lua
@@ -479,7 +479,21 @@ function add_node()
uci_set(uid, "group", group)
end
- uci_set(uid, "type", "Socks")
+ if api.is_finded("ipt2socks") then
+ uci_set(uid, "type", "Socks")
+ elseif api.finded_com("sing-box") then
+ uci_set(uid, "type", "sing-box")
+ elseif api.finded_com("xray") then
+ uci_set(uid, "type", "Xray")
+ elseif api.is_finded("sslocal") then
+ uci_set(uid, "type", "SS-Rust")
+ elseif api.is_finded("ssr-local") then
+ uci_set(uid, "type", "SSR")
+ elseif api.finded_com("hysteria") then
+ uci_set(uid, "type", "Hysteria2")
+ elseif api.is_finded("naive") then
+ uci_set(uid, "type", "Naiveproxy")
+ end
if redirect == "1" then
uci_save()
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
index 12752c54..032a989e 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/global.lua
@@ -112,6 +112,10 @@ o:value("", translate("Close"))
o.group = {""}
current_node_id = m:get(s.section, "node")
+local node_value = s.fields["node"]:formvalue(s.section)
+if node_value then
+ current_node_id = node_value
+end
current_node = current_node_id and m:get(current_node_id) or {}
-- Shunt Start
@@ -120,17 +124,10 @@ if (has_singbox or has_xray) and #nodes_table > 0 then
if current_node.protocol == "_shunt" then
local shunt_lua = loadfile("/usr/lib/lua/luci/model/cbi/passwall/client/include/shunt_options.lua")
setfenv(shunt_lua, getfenv(1))(m, s, {
- s_cfgid = s.section,
- node_id = current_node_id,
node = current_node,
- socks_list = socks_list,
- urltest_list = urltest_list,
- balancing_list = balancing_list,
- iface_list = iface_list,
- normal_list = normal_list,
verify_option = s.fields["node"],
tab = "Shunt",
- tab_desc = translate("Shunt Rule")
+ tab_desc = translate("Shunt Rule"),
})
end
else
@@ -165,6 +162,11 @@ o = s:taboption("Main", Flag, "node_socks_bind_local", translate("Node") .. " So
o.default = "1"
o:depends("_node", "1")
+o = s:taboption("Main", DummyValue, "node_save_before", "")
+o.template = m:template_path("/cbi/hidevalue")
+o.value = current_node[".name"]
+o.cbid = function(self, section) return "node_save_before" end
+
o = s:taboption("Main", DummyValue, "_node", "")
o.template = m:template_path("/cbi/hidevalue")
o.value = "1"
@@ -647,6 +649,8 @@ s:tab("maintain", translate("Maintain"))
o = s:taboption("maintain", DummyValue, "")
o.template = m:template_path("/global/backup")
+m:appendTemplate("/include/node_change", { verify_option = s.fields["node"], shunt_list = api.jsonc.stringify(shunt_list) })
+
-- [[ Socks Server ]]--
o = s:taboption("Main", Flag, "socks_enabled", "Socks " .. translate("Main switch"))
o.rmempty = false
@@ -784,7 +788,7 @@ for k, v in pairs(nodes_table) do
end
end
-m:appendTemplate("/global/footer", {shunt_list = api.jsonc.stringify(shunt_list)})
+m:appendTemplate("/global/footer")
m:appendTemplate("/cbi/sortable", {sectiontype = s2.sectiontype})
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/include/shunt_options.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/include/shunt_options.lua
index 0528992a..22d5bac6 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/include/shunt_options.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/include/shunt_options.lua
@@ -1,13 +1,28 @@
local m, s, data = ...
-if not data.node_id or not data.node then
+if not data.node or not data.node[".name"] then
return
end
local api = m.api
-local s_cfgid = data.s_cfgid
-local current_node_id = data.node_id
+local section_id = s.section
+local current_node = data.node
+local current_node_id = current_node[".name"]
+local verify_option = data.verify_option
local node_list = data.node_list or api.get_node_list()
+local shunt_section_type = "shunt_option_list"
+
+if data.tab then
+ if #s.tab_names > 0 then
+ table.insert(s.tab_names, 2, data.tab)
+ s.tabs[data.tab] = {
+ title = data.tab_desc,
+ childs = { }
+ }
+ else
+ s:tab(data.tab, data.tab_desc)
+ end
+end
local groups = {}
m:foreach("shunt_rules", function(s)
@@ -16,6 +31,9 @@ m:foreach("shunt_rules", function(s)
end
end)
+local node_save_before = luci.http.formvalue("node_save_before")
+local load_shunt = luci.http.formvalue("load_shunt")
+
local function get_cfgvalue()
return function(self, section)
return m:get(current_node_id, self.option)
@@ -23,8 +41,10 @@ local function get_cfgvalue()
end
local function get_write()
return function(self, section, value)
- if data.verify_option then
- if data.verify_option:formvalue(section) == current_node_id then
+ if node_save_before and node_save_before ~= current_node_id then return end
+ if load_shunt == "1" then return end
+ if verify_option then
+ if verify_option:formvalue(section) == current_node_id then
m:set(current_node_id, self.option, value)
end
else
@@ -34,8 +54,10 @@ local function get_write()
end
local function get_remove()
return function(self, section)
- if data.verify_option then
- if data.verify_option:formvalue(section) == current_node_id then
+ if node_save_before and node_save_before ~= current_node_id then return end
+ if load_shunt == "1" then return end
+ if verify_option then
+ if verify_option:formvalue(section) == current_node_id then
m:del(current_node_id, self.option)
end
else
@@ -44,10 +66,6 @@ local function get_remove()
end
end
-if data.tab then
- s:tab(data.tab, data.tab_desc)
-end
-
local function add_option(class, option_name, option_title, option_desc)
local a
if data.tab then
@@ -63,8 +81,8 @@ local function add_option(class, option_name, option_title, option_desc)
a.write = get_write()
a.remove = get_remove()
end
- if data.verify_option then
- a:depends(data.verify_option.option, current_node_id)
+ if verify_option then
+ a:depends(verify_option.option, current_node_id)
end
return a
end
@@ -81,7 +99,7 @@ local function add_depends(o, deps)
end
end
-if data.node.type == "Xray" then
+if current_node.type == "Xray" then
o = add_option(ListValue, "domainStrategy", translate("Domain Strategy"))
o:value("AsIs")
o:value("IPIfNonMatch")
@@ -134,7 +152,7 @@ table.insert(shunt_rules, {
s2 = m:section(Table, shunt_rules, " ")
s2.config = m.config
-s2.sectiontype = "shunt_option_list"
+s2.sectiontype = shunt_section_type
o = s2:option(DummyValue, "remarks", translate("Rule"))
o.rawhtml = true
@@ -157,9 +175,13 @@ _node.cfgvalue = function(self, section)
return m:get(current_node_id, shunt_rules[section]["_node_option"]) or shunt_rules[section]["_node_default"]
end
_node.write = function(self, section, value)
+ if node_save_before and node_save_before ~= current_node_id then return end
+ if load_shunt == "1" then return end
return m:set(current_node_id, shunt_rules[section]["_node_option"], value)
end
_node.remove = function(self, section)
+ if node_save_before and node_save_before ~= current_node_id then return end
+ if load_shunt == "1" then return end
return m:del(current_node_id, shunt_rules[section]["_node_option"])
end
@@ -170,9 +192,13 @@ o.cfgvalue = function(self, section)
return m:get(current_node_id, shunt_rules[section]["_fakedns_option"])
end
o.write = function(self, section, value)
+ if node_save_before and node_save_before ~= current_node_id then return end
+ if load_shunt == "1" then return end
return m:set(current_node_id, shunt_rules[section]["_fakedns_option"], value)
end
o.remove = function(self, section)
+ if node_save_before and node_save_before ~= current_node_id then return end
+ if load_shunt == "1" then return end
return m:del(current_node_id, shunt_rules[section]["_fakedns_option"])
end
@@ -186,9 +212,13 @@ proxy_tag_node.cfgvalue = function(self, section)
return m:get(current_node_id, shunt_rules[section]["_proxy_tag_option"])
end
proxy_tag_node.write = function(self, section, value)
+ if node_save_before and node_save_before ~= current_node_id then return end
+ if load_shunt == "1" then return end
return m:set(current_node_id, shunt_rules[section]["_proxy_tag_option"], value)
end
proxy_tag_node.remove = function(self, section)
+ if node_save_before and node_save_before ~= current_node_id then return end
+ if load_shunt == "1" then return end
return m:del(current_node_id, shunt_rules[section]["_proxy_tag_option"])
end
@@ -204,4 +234,11 @@ for k1, v1 in pairs(node_list) do
end
end
-m:appendTemplate("/include/shunt_options", {id = current_node_id, s_cfgid = s_cfgid or current_node_id, normal_list = api.jsonc.stringify(node_list.normal_list)})
+m:appendTemplate("/include/shunt_options", {
+ node_id = current_node_id,
+ section_id = section_id or current_node_id,
+ section_type = shunt_section_type,
+ tab_name = data.tab,
+ normal_list = api.jsonc.stringify(node_list.normal_list),
+ shunt_list = api.jsonc.stringify(node_list.shunt_list)
+})
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 20f8ff3f..9c4315d0 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
@@ -61,7 +61,6 @@ end
local types_dir = "/usr/lib/lua/luci/model/cbi/" .. api.appname .. "/client/type/"
s.val = {}
s.val["type"] = m:get(arg[1], "type")
-s.val["protocol"] = m:get(arg[1], "protocol")
if luci.http.formvalue("cbi.submit") == "1" then
local formvalue_type = luci.http.formvalue(formvalue_key .. "type")
@@ -72,34 +71,6 @@ end
o = s:option(ListValue, "type", translate("Type"))
-if api.is_finded("ipt2socks") then
- local type_name = "Socks"
-
- 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 = s2:option(Value, "address", translate("Address (Support Domain Name)"))
-
- o = s2:option(Value, "port", translate("Port"))
- o.datatype = "port"
-
- o = s2:option(Value, "username", translate("Username"))
-
- o = s2:option(Value, "password", translate("Password"))
- o.password = true
-
- api.luci_types(s, s2)
- end
-end
-
local type_table = {}
for filename in api.fs.dir(types_dir) do
table.insert(type_table, filename)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/0_socks.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/0_socks.lua
new file mode 100644
index 00000000..23856bad
--- /dev/null
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/0_socks.lua
@@ -0,0 +1,35 @@
+if not api.is_finded("ipt2socks") then
+ return
+end
+
+-- [[ Socks ]]
+local m, s1 = ...
+local type_name = "Socks"
+
+s1.fields["type"]:value(type_name, "Socks")
+
+if s1.val["type"] and s1.val["type"] ~= type_name then
+ return
+end
+
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
+s.type_name = type_name
+s.option_prefix = "socks_"
+api.set_type_cbi(s)
+
+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, "username", translate("Username"))
+
+o = s:option(Value, "password", translate("Password"))
+o.password = true
+
+api.type_cbi_section(s1, s)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua
index a4c032a7..3008a514 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/1_sing-box.lua
@@ -17,15 +17,11 @@ if s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
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 ""
+api.set_type_cbi(s)
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"
@@ -72,24 +68,20 @@ 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
+
+local protocol_val = m:get(s.section, "protocol")
+local formvalue_proto = s.fields["protocol"]:formvalue(s.section)
+if formvalue_proto then
+ protocol_val = formvalue_proto
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_urltest_options = protocol_val == "_urltest"
+local load_shunt_options = protocol_val == "_shunt"
+local load_iface_options = protocol_val == "_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()
@@ -115,11 +107,11 @@ if load_urltest_options then -- [[ URLTest Start ]]
end
end
-- 读取旧 DynamicList
- function o.custom_cfgvalue(self, section)
+ function o.cfgvalue(self, section)
return table.concat(m:get(section, "urltest_node") or {}, " ")
end
-- 写入保持 DynamicList
- function o.custom_write(self, section, value)
+ function o.write(self, section, value)
local old = m:get(section, "urltest_node") or {}
local new, set = {}, {}
for v in value:gmatch("%S+") do
@@ -935,7 +927,7 @@ if not load_shunt_options then
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
+ if v.id ~= s.section 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
@@ -949,14 +941,15 @@ if not load_shunt_options then
end
end
-api.luci_types(s1, s)
+api.type_cbi_section(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 = {
+ [".name"] = s.section,
+ type = type_name,
+ },
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
index 6ff9f508..5684127d 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/2_xray.lua
@@ -15,15 +15,11 @@ if s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
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 ""
+api.set_type_cbi(s)
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"
@@ -53,31 +49,26 @@ if api.compare_versions(xray_version, ">=", "1.8.12") then
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
+local protocol_val = m:get(s.section, "protocol")
+local formvalue_proto = s.fields["protocol"]:formvalue(s.section)
+if formvalue_proto then
+ protocol_val = formvalue_proto
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_balancing_options = protocol_val == "_balancing"
+local load_shunt_options = protocol_val == "_shunt"
+local load_iface_options = protocol_val == "_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
+ if e.id ~= s.section then
fallback_list[#fallback_list + 1] = {
id = e["id"],
remark = e["remark"],
@@ -110,11 +101,11 @@ if load_balancing_options then -- [[ Load balancing Start ]]
end
end
-- 读取旧 DynamicList
- function o.custom_cfgvalue(self, section)
+ function o.cfgvalue(self, section)
return table.concat(m:get(section, "balancing_node") or {}, " ")
end
-- 写入保持 DynamicList
- function o.custom_write(self, section, value)
+ function o.write(self, section, value)
local old = m:get(section, "balancing_node") or {}
local new, set = {}, {}
for v in value:gmatch("%S+") do
@@ -213,7 +204,7 @@ if load_balancing_options then -- [[ Load balancing Start ]]
local depth = get_fallback_depth(v.id)
-- 超过最大套娃层数后,不允许继续选择 balancer
if depth < MAX_FALLBACK_DEPTH
- and not will_loop(arg[1], v.id)
+ and not will_loop(s.section, 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")
@@ -678,13 +669,13 @@ o.validate = function(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)
+o.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)
+o.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
@@ -700,7 +691,7 @@ o.custom_write = function(self, section, value)
m:del(section, "download_address")
end
end
-o.custom_remove = function(self, section, value)
+o.remove = function(self, section, value)
m:del(section, "xhttp_extra")
m:del(section, "download_address")
end
@@ -763,13 +754,13 @@ o.validate = function(self, value)
if v then return v end
return nil, "FinalMask " .. translate("Must be JSON text!")
end
-o.custom_cfgvalue = function(self, section, value)
+o.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)
+o.write = function(self, section, value)
m:set(section, "finalmask", api.base64Encode(value) or "")
end
@@ -871,7 +862,7 @@ if not load_shunt_options then
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
+ if v.id ~= s.section 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
@@ -885,14 +876,16 @@ if not load_shunt_options then
end
end
-api.luci_types(s1, s)
+api.type_cbi_section(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 = {
+ [".name"] = s.section,
+ type = type_name,
+ },
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
index 1c7562dc..30f63d71 100644
--- 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
@@ -12,9 +12,11 @@ if s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "ssrust_"
+api.set_type_cbi(s)
local ssrust_encrypt_method_list = {
"none", "plain",
@@ -69,4 +71,4 @@ end
o = s:option(Value, "plugin_opts", translate("opts"))
o:depends({ plugin_enabled = true })
-api.luci_types(s1, s)
+api.type_cbi_section(s1, s)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/4_ssr.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/4_ssr.lua
index e86e470b..542ee14d 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/4_ssr.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/4_ssr.lua
@@ -12,9 +12,11 @@ if s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "ssr_"
+api.set_type_cbi(s)
local ssr_encrypt_method_list = {
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
@@ -63,4 +65,4 @@ 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)
+api.type_cbi_section(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
index d9b4d600..1ec43518 100644
--- 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
@@ -12,13 +12,11 @@ if s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "hysteria2_"
-
-local function _n(name)
- return s.option_prefix .. name
-end
+api.set_type_cbi(s)
o = s:option(ListValue, "protocol", translate("Protocol"))
o:value("udp", "UDP")
@@ -32,22 +30,22 @@ 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.rewrite_option = 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.rewrite_option = o.option
o:depends({ realms = false })
o = s:option(Flag, "realms", translate("Realms"))
o.default = "0"
-o.rewrite_option = _n(o.option)
+o.rewrite_option = 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.rewrite_option = o.option
o:depends({ realms = "1" })
o.validate = function(self, value)
value = api.trim(value)
@@ -58,26 +56,26 @@ 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.rewrite_option = o.option
o:depends({ realms = "1" })
o = s:option(Flag, "realm_upnp", translate("Enable") .. " UPnP/NAT-PMP", translate("Enable UPnP/NAT-PMP port mapping on your gateway to improve hole punching success."))
o.default = "0"
-o.rewrite_option = _n(o.option)
+o.rewrite_option = 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.rewrite_option = 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.rewrite_option = o.option
o = s:option(Value, "obfs_password", translate("Obfs Password"))
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
o:depends({ obfs_type = "salamander" })
o:depends({ obfs_type = "gecko" })
@@ -86,14 +84,14 @@ o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ obfs_type = "gecko" })
-o.rewrite_option = _n(o.option)
+o.rewrite_option = 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.rewrite_option = o.option
o = s:option(Flag, "fast_open", translate("Fast Open"))
o.default = "0"
@@ -106,28 +104,28 @@ 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.rewrite_option = o.option
o = s:option(Value, "down_mbps", translate("Max download Mbps"))
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
o = s:option(Value, "recv_window", translate("QUIC stream receive window"))
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
o = s:option(Value, "recv_window_conn", translate("QUIC connection receive window"))
-o.rewrite_option = _n(o.option)
+o.rewrite_option = 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.rewrite_option = 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.rewrite_option = o.option
o = s:option(Flag, "disable_mtu_discovery", translate("Disable MTU detection"))
o.default = "0"
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
o = s:option(Flag, "ech", translate("ECH"))
@@ -145,6 +143,6 @@ end
o = s:option(Flag, "lazy_start", translate("Lazy Start"))
o.default = "0"
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
-api.luci_types(s1, s)
+api.type_cbi_section(s1, s)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/6_naive.lua b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/6_naive.lua
index b00c0c3f..83dc7d91 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/client/type/6_naive.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/client/type/6_naive.lua
@@ -12,9 +12,11 @@ if s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "naive_"
+api.set_type_cbi(s)
o = s:option(ListValue, "protocol", translate("Protocol"))
o:value("https", translate("HTTPS"))
@@ -30,4 +32,4 @@ o = s:option(Value, "username", translate("Username"))
o = s:option(Value, "password", translate("Password"))
o.password = true
-api.luci_types(s1, s)
+api.type_cbi_section(s1, s)
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
index 3b267d62..91acbf79 100644
--- 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
@@ -15,9 +15,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "socks_"
+api.set_type_cbi(s)
o = s:option(Value, "port", translate("Listen Port"))
o.datatype = "port"
@@ -44,4 +46,4 @@ o:depends({ firewall_allow = true })
o = s:option(Flag, "log", translate("Log"))
o.default = "1"
-api.luci_types(s1, s)
+api.type_cbi_section(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
index 592028c3..05fb9724 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/1_sing-box.lua
@@ -21,9 +21,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "singbox_"
+api.set_type_cbi(s)
local singbox_tags = luci.sys.exec(singbox_bin .. " version | grep 'Tags:' | awk '{print $2}'")
@@ -48,13 +50,13 @@ o.validate = function(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)
+o.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)
+o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -562,4 +564,4 @@ o:value("warn")
o:value("error")
o:depends({ log = true })
-api.luci_types(s1, s)
+api.type_cbi_section(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
index 11ec4fab..02dfc68d 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/2_xray.lua
@@ -19,9 +19,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "xray_"
+api.set_type_cbi(s)
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"
@@ -44,13 +46,13 @@ o.validate = function(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)
+o.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)
+o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -257,8 +259,8 @@ end
-- [[ 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.default = m:get(s.section, "tls_certificateFile") or "/etc/config/ssl/" .. s.section .. ".pem"
+if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
o:depends({ tls = true, reality = false })
o:depends({ protocol = "hysteria2"})
o.validate = function(self, value, t)
@@ -273,8 +275,8 @@ o.validate = function(self, value, t)
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.default = m:get(s.section, "tls_keyFile") or "/etc/config/ssl/" .. s.section .. ".key"
+if o and o:formvalue(s.section) then o.default = o:formvalue(s.section) end
o:depends({ tls = true, reality = false })
o:depends({ protocol = "hysteria2"})
o.validate = function(self, value, t)
@@ -396,13 +398,13 @@ o:depends({ use_finalmask = true })
o.rows = 10
o.wrap = "off"
o.datatype = "json"
-o.custom_cfgvalue = function(self, section, value)
+o.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)
+o.write = function(self, section, value)
m:set(section, "finalmask", api.base64Encode(value) or "")
end
@@ -549,4 +551,4 @@ o:value("warning")
o:value("error")
o:depends({ log = true })
-api.luci_types(s1, s)
+api.type_cbi_section(s1, s)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/3_ss-rust.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/3_ss-rust.lua
index 851247af..9c7f4cc2 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/3_ss-rust.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/3_ss-rust.lua
@@ -16,9 +16,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "ssrust_"
+api.set_type_cbi(s)
local ssrust_encrypt_method_list = {
"plain", "none",
@@ -39,13 +41,13 @@ o.validate = function(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)
+o.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)
+o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -88,4 +90,4 @@ o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
-api.luci_types(s1, s)
+api.type_cbi_section(s1, s)
diff --git a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/4_ssr.lua b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/4_ssr.lua
index 8e54f6fd..9453bdf4 100644
--- a/luci-app-passwall/luasrc/model/cbi/passwall/server/type/4_ssr.lua
+++ b/luci-app-passwall/luasrc/model/cbi/passwall/server/type/4_ssr.lua
@@ -16,9 +16,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "ssr_"
+api.set_type_cbi(s)
local ssr_encrypt_method_list = {
"none", "table", "rc2-cfb", "rc4", "rc4-md5", "rc4-md5-6", "aes-128-cfb",
@@ -52,13 +54,13 @@ o.validate = function(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)
+o.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)
+o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -119,4 +121,4 @@ o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
-api.luci_types(s1, s)
+api.type_cbi_section(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
index 9a037ff7..c7147f50 100644
--- 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
@@ -12,13 +12,11 @@ if s1.val["type"] and s1.val["type"] ~= type_name then
return
end
-local s = NamedSection(m, arg[1], "server")
+local s = NamedSection(m, arg[1], "tmp_" .. s1.sectiontype)
+s.parent = s1
s.type_name = type_name
s.option_prefix = "hysteria2_"
-
-local function _n(name)
- return s.option_prefix .. name
-end
+api.set_type_cbi(s)
o = s:option(Flag, "custom", translate("Use Custom Config"))
@@ -33,13 +31,13 @@ o.validate = function(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)
+o.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)
+o.write = function(self, section, value)
m:set(section, "config_str", api.base64Encode(value) or "")
end
@@ -55,11 +53,11 @@ o:depends({ custom = false })
o = s:option(Flag, "realms", translate("Realms"))
o.default = "0"
-o.rewrite_option = _n(o.option)
+o.rewrite_option = 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.rewrite_option = o.option
o:depends({ realms = "1" })
o.validate = function(self, value)
value = api.trim(value)
@@ -70,23 +68,23 @@ 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.rewrite_option = o.option
o:depends({ realms = "1" })
o = s:option(Flag, "realm_upnp", translate("Enable") .. " UPnP/NAT-PMP", translate("Enable UPnP/NAT-PMP port mapping on your gateway to improve hole punching success."))
o.default = "0"
-o.rewrite_option = _n(o.option)
+o.rewrite_option = 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.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(Value, "obfs_password", translate("Obfs Password"))
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
o:depends({ obfs_type = "salamander" })
o:depends({ obfs_type = "gecko" })
@@ -95,31 +93,31 @@ o.datatype = "uinteger"
o.placeholder = "512"
o.default = "512"
o:depends({ obfs_type = "gecko" })
-o.rewrite_option = _n(o.option)
+o.rewrite_option = 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.rewrite_option = o.option
o = s:option(Flag, "udp", translate("UDP"))
o.default = "1"
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(Value, "up_mbps", translate("Max upload Mbps"))
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(Value, "down_mbps", translate("Max download Mbps"))
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(Flag, "ignoreClientBandwidth", translate("ignoreClientBandwidth"))
o.default = "0"
-o.rewrite_option = _n(o.option)
+o.rewrite_option = o.option
o:depends({ custom = false })
o = s:option(FileUpload, "tls_certificateFile", translate("Public key absolute path"), translate("as:") .. "/etc/ssl/fullchain.pem")
@@ -181,4 +179,4 @@ o = s:option(Flag, "log", translate("Log"))
o.default = "1"
o.rmempty = false
-api.luci_types(s1, s)
+api.type_cbi_section(s1, s)
diff --git a/luci-app-passwall/luasrc/passwall/api.lua b/luci-app-passwall/luasrc/passwall/api.lua
index d9d3cf8f..c0f60b46 100644
--- a/luci-app-passwall/luasrc/passwall/api.lua
+++ b/luci-app-passwall/luasrc/passwall/api.lua
@@ -1537,110 +1537,88 @@ function return_map(map)
return map
end
-function luci_types(s, s2)
+function set_type_cbi(s)
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)
+ local s1 = s.parent
+ function s.option(self, class, option, ...)
+ local obj = class(self.map, self, option, ...)
+ obj.config_option = option
+ obj.option_prefix = self.option_prefix
+ obj.option = self.option_prefix .. option
+ obj.cfgvalue = function(o_self, section)
+ if o_self.rewrite_option then
+ return o_self.map:get(section, o_self.rewrite_option)
+ else
+ return o_self.map:get(section, o_self.config_option)
+ end
+ end
+ obj.write = function(o_self, section, value)
+ if s1.fields["type"]:formvalue(self.section) == self.type_name then
+ local new_val = value
+ if util.instanceof(o_self, cbi.DynamicList) then
+ local new_t = {}
+ if type(value) == "table" then
+ new_t = table_remove_duplicates(value)
+ else
+ new_t = { value }
+ end
+ if o_self.cast == "string" then
+ new_val = table.concat(new_t, " ")
+ else
+ new_val = new_t
+ end
+ end
+ if o_self.rewrite_option then
+ o_self.map:set(section, o_self.rewrite_option, new_val)
+ else
+ o_self.map:set(section, o_self.config_option, new_val)
+ end
+ end
+ end
+ obj.remove = function(o_self, section)
+ if s1.fields["type"]:formvalue(self.section) == self.type_name then
+ if o_self.rewrite_option then
+ o_self.map:del(section, o_self.rewrite_option)
+ else
+ o_self.map:del(section, o_self.config_option)
+ end
+ end
+ end
+ obj.depends = function(o_self, field, value)
+ local deps
+ if type(field) == "string" then
+ deps = {}
+ deps[field] = value
+ else
+ deps = field
+ end
+ local new_deps = {}
+ for k, v in pairs(deps) do
+ local n_k = k
+ if self.fields[k] then
+ n_k = self.fields[k].option
+ end
+ new_deps[n_k] = v
+ end
+ new_deps["type"] = self.type_name
+ if next(new_deps) then
+ table.insert(o_self.deps, new_deps)
+ end
+ end
+ self:append(obj)
+ self.fields[option] = obj
+ return obj
end
+end
+
+function type_cbi_section(s, s2)
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
- return m:get(section, self.config_option)
- end
- end
- 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
- m:del(section, self.rewrite_option)
- else
- m:del(section, self.config_option)
- end
- end
- end
- end
+ if #o.deps == 0 then
+ o:depends({ type = s2.type_name })
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)
+ s.fields[o.option] = o
end
end
diff --git a/luci-app-passwall/luasrc/passwall/util_xray.lua b/luci-app-passwall/luasrc/passwall/util_xray.lua
index 80d0d275..519497dd 100644
--- a/luci-app-passwall/luasrc/passwall/util_xray.lua
+++ b/luci-app-passwall/luasrc/passwall/util_xray.lua
@@ -44,6 +44,7 @@ function gen_outbound(flag, node, tag, proxy_table)
local remarks = node.remarks
local proxy_tag = nil
+ local dialer_proxy_tag = nil
local fragment = nil
local noise = nil
local run_socks_instance = true
@@ -86,12 +87,7 @@ function gen_outbound(flag, node, tag, proxy_table)
node.stream_security = "none"
proxy_tag = "socks <- " .. node_id
else
- if proxy_tag then
- node.proxySettings = {
- tag = proxy_tag,
- transportLayer = true
- }
- end
+ dialer_proxy_tag = proxy_tag
end
if node.type == "Xray" then
@@ -135,7 +131,6 @@ function gen_outbound(flag, node, tag, proxy_table)
_flag = flag,
_flag_proxy_tag = proxy_tag,
tag = tag,
- proxySettings = node.proxySettings or nil,
protocol = node.protocol,
mux = {
enabled = (node.mux == "1") and true or false,
@@ -143,7 +138,7 @@ function gen_outbound(flag, node, tag, proxy_table)
xudpConcurrency = (node.mux == "1" and ((node.xudp_concurrency) and tonumber(node.xudp_concurrency) or 8)) or nil
} or nil,
-- 底层传输配置
- streamSettings = (node.streamSettings or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and {
+ streamSettings = (node.streamSettings or dialer_proxy_tag or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and {
sockopt = {
mark = 255,
domainStrategy = node.domain_strategy or "UseIP",
@@ -154,7 +149,8 @@ function gen_outbound(flag, node, tag, proxy_table)
PrioritizeIPv6 = false,
Interleave = 1,
MaxConcurrentTry = 4
- } or nil
+ } or nil,
+ dialerProxy = dialer_proxy_tag,
},
[(api.compare_versions(xray_version, "<", "26.7.11")) and "network" or "method"] = node.transport, -- Todo: Remove version check and "network"
security = node.stream_security,
@@ -1209,10 +1205,9 @@ function gen_config(var)
end
if preproxy_outbound then
outbound.tag = preproxy_outbound.tag .. " -> " .. outbound.tag
- outbound.proxySettings = {
- tag = preproxy_outbound.tag,
- transportLayer = true
- }
+ outbound.streamSettings = outbound.streamSettings or {}
+ outbound.streamSettings.sockopt = outbound.streamSettings.sockopt or {}
+ outbound.streamSettings.sockopt.dialerProxy = preproxy_outbound.tag
if not exist then
last_insert_outbound = preproxy_outbound
end
@@ -1260,10 +1255,9 @@ function gen_config(var)
if to_outbound then
to_outbound.tag = outbound.tag .. " -> " .. to_outbound.tag
if to_node.type == "Xray" then
- to_outbound.proxySettings = {
- tag = outbound.tag,
- transportLayer = true
- }
+ to_outbound.streamSettings = to_outbound.streamSettings or {}
+ to_outbound.streamSettings.sockopt = to_outbound.streamSettings.sockopt or {}
+ to_outbound.streamSettings.sockopt.dialerProxy = outbound.tag
end
table.insert(outbounds_table, to_outbound)
default_outTag = to_outbound.tag
diff --git a/luci-app-passwall/luasrc/view/passwall/global/footer.htm b/luci-app-passwall/luasrc/view/passwall/global/footer.htm
index d122cedd..bdacc409 100644
--- a/luci-app-passwall/luasrc/view/passwall/global/footer.htm
+++ b/luci-app-passwall/luasrc/view/passwall/global/footer.htm
@@ -14,11 +14,6 @@ local sid = "@global[0]"
}
}
-.shunt-tab-hidden {
- display: none !important;
- visibility: hidden !important;
-}
-
@media screen and (max-width: 1152px) {
#cbi-<%=appname%>-socks .cbi-section-table-titles {
display: none !important;
@@ -28,7 +23,6 @@ local sid = "@global[0]"
diff --git a/luci-app-passwall/luasrc/view/passwall/include/node_change.htm b/luci-app-passwall/luasrc/view/passwall/include/node_change.htm
new file mode 100644
index 00000000..862649de
--- /dev/null
+++ b/luci-app-passwall/luasrc/view/passwall/include/node_change.htm
@@ -0,0 +1,73 @@
+<%
+local map = self.map
+local api = map.api
+local config = map.config
+local verify_option = self.verify_option
+local section_id = verify_option.section.section
+-%>
+<% if verify_option then -%>
+
+<%- end %>
\ No newline at end of file
diff --git a/luci-app-passwall/luasrc/view/passwall/include/shunt_options.htm b/luci-app-passwall/luasrc/view/passwall/include/shunt_options.htm
index 20d081a6..53e9a5f9 100644
--- a/luci-app-passwall/luasrc/view/passwall/include/shunt_options.htm
+++ b/luci-app-passwall/luasrc/view/passwall/include/shunt_options.htm
@@ -2,18 +2,22 @@
local map = self.map
local api = map.api
local config = map.config
-local id = self.id
-local s_cfgid = self.s_cfgid
+local node_id = self.node_id
+local verify_option = self.verify_option
+local section_id = self.section_id
+local section_type = self.section_type
+local tab_name = self.tab_name
-%>
\ No newline at end of file
diff --git a/luci-app-passwall/luasrc/view/passwall/node_config/footer.htm b/luci-app-passwall/luasrc/view/passwall/node_config/footer.htm
index e6a9da82..cfe03b1c 100644
--- a/luci-app-passwall/luasrc/view/passwall/node_config/footer.htm
+++ b/luci-app-passwall/luasrc/view/passwall/node_config/footer.htm
@@ -35,27 +35,30 @@ local config = map.config
});
waitForElement('select[name*="<%=config%>"][name*="protocol"]', function(el) {
let o_val = el.value;
+ const name_split = el.name.split(".");
+ const name = name_split[name_split.length - 1];
el.addEventListener("change", () => {
el.blur();
if (el.value.startsWith("_") || (o_val.startsWith("_") && !el.value.startsWith("_"))) {
- let name_split = el.name.split(".");
- let name = name_split[name_split.length - 1];
- let save = true;
- if (save) {
- /*
- const saveBtn = document.getElementsByClassName('cbi-button-save');
- if (saveBtn && saveBtn.length > 0) {
- saveBtn[saveBtn.length - 1].click();
- }
- */
- update_config(node_id, {
- remarks: getOption("<%=config%>", "<%=sid%>", "remarks").value,
- group: getOption("<%=config%>", "<%=sid%>", "group").value,
- protocol: getOption("<%=config%>", "<%=sid%>", name).value,
- }, node_config_url);
- } else {
- window.location.href = node_config_url + "?select_proto=" + encodeURIComponent(el.value);
+ if (el.value.startsWith("_")) {
+ const map = document.getElementById("cbi-<%=config%>");
+ const hiddenInput = document.createElement('input');
+ hiddenInput.type = 'hidden';
+ hiddenInput.name = 'load' + el.value;
+ hiddenInput.value = '1';
+ map.appendChild(hiddenInput);
}
+ const saveBtn = document.getElementsByClassName('cbi-button-save');
+ if (saveBtn && saveBtn.length > 0) {
+ saveBtn[saveBtn.length - 1].click();
+ }
+ /*
+ update_config(node_id, {
+ remarks: getOption("<%=config%>", "<%=sid%>", "remarks").value,
+ group: getOption("<%=config%>", "<%=sid%>", "group").value,
+ protocol: getOption("<%=config%>", "<%=sid%>", name).value,
+ }, node_config_url);
+ */
}
});
});
diff --git a/luci-app-passwall/root/usr/share/passwall/app.sh b/luci-app-passwall/root/usr/share/passwall/app.sh
index 36c4052b..52069949 100755
--- a/luci-app-passwall/root/usr/share/passwall/app.sh
+++ b/luci-app-passwall/root/usr/share/passwall/app.sh
@@ -566,11 +566,7 @@ start_global() {
local node_socks_bind_local=$(config_n_get @global[0] node_socks_bind_local 1)
local node_socks_bind="127.0.0.1"
[ "${node_socks_bind_local}" != "1" ] && node_socks_bind="0.0.0.0"
- local global_socks_port=$(config_n_get @global[0] node_socks_port 1070)
- GLOBAL_SOCKS_port=$(get_new_port $global_socks_port)
- if [ "$GLOBAL_SOCKS_port" != "$global_socks_port" ]; then
- echolog "注意:全局节点 Socks 端口冲突,原端口 ${global_socks_port} 已自动更改为 ${GLOBAL_SOCKS_port}!"
- fi
+ GLOBAL_SOCKS_port=$(config_n_get @global[0] node_socks_port 1070)
GLOBAL_HTTP_port=$(config_n_get @global[0] node_http_port 0)
[ "$GLOBAL_HTTP_port" != "0" ] && local on_node_http=1
if [ $PROXY_IPV6 = "1" ]; then
diff --git a/luci-app-passwall2/Makefile b/luci-app-passwall2/Makefile
index 4fe9ce4b..e787e41c 100644
--- a/luci-app-passwall2/Makefile
+++ b/luci-app-passwall2/Makefile
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2
PKG_VERSION:=26.9.9
-PKG_RELEASE:=1
+PKG_RELEASE:=2
PKG_PO_VERSION:=$(PKG_VERSION)
PKG_CONFIG_DEPENDS:= \
diff --git a/luci-app-passwall2/luasrc/passwall2/util_xray.lua b/luci-app-passwall2/luasrc/passwall2/util_xray.lua
index f006efae..6befb203 100644
--- a/luci-app-passwall2/luasrc/passwall2/util_xray.lua
+++ b/luci-app-passwall2/luasrc/passwall2/util_xray.lua
@@ -59,6 +59,7 @@ function gen_outbound(flag, node, tag, proxy_table)
local remarks = node.remarks
local proxy_tag = nil
+ local dialer_proxy_tag = nil
local fragment = nil
local noise = nil
local run_socks_instance = true
@@ -97,12 +98,7 @@ function gen_outbound(flag, node, tag, proxy_table)
node.stream_security = "none"
proxy_tag = "socks <- " .. node_id
else
- if proxy_tag then
- node.proxySettings = {
- tag = proxy_tag,
- transportLayer = true
- }
- end
+ dialer_proxy_tag = proxy_tag
end
if node.type == "Xray" then
@@ -146,14 +142,13 @@ function gen_outbound(flag, node, tag, proxy_table)
_flag = flag,
_flag_proxy_tag = proxy_tag,
tag = tag,
- proxySettings = node.proxySettings or nil,
protocol = node.protocol,
mux = {
enabled = (node.mux == "1") and true or false,
concurrency = (node.mux == "1" and ((node.mux_concurrency) and tonumber(node.mux_concurrency) or -1)) or nil,
xudpConcurrency = (node.mux == "1" and ((node.xudp_concurrency) and tonumber(node.xudp_concurrency) or 8)) or nil
} or nil,
- streamSettings = (node.streamSettings or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and {
+ streamSettings = (node.streamSettings or dialer_proxy_tag or node.protocol == "vmess" or node.protocol == "vless" or node.protocol == "socks" or node.protocol == "shadowsocks" or node.protocol == "trojan" or node.protocol == "hysteria") and {
sockopt = {
mark = 255,
domainStrategy = node.domain_strategy or "UseIP",
@@ -164,7 +159,8 @@ function gen_outbound(flag, node, tag, proxy_table)
PrioritizeIPv6 = false,
Interleave = 1,
MaxConcurrentTry = 4
- } or nil
+ } or nil,
+ dialerProxy = dialer_proxy_tag,
},
[(api.compare_versions(xray_version, "<", "26.7.11")) and "network" or "method"] = node.transport, -- Todo: Remove version check and "network"
security = node.stream_security,
@@ -1208,10 +1204,9 @@ function gen_config(var)
end
if preproxy_outbound then
outbound.tag = preproxy_outbound.tag .. " -> " .. outbound.tag
- outbound.proxySettings = {
- tag = preproxy_outbound.tag,
- transportLayer = true
- }
+ outbound.streamSettings = outbound.streamSettings or {}
+ outbound.streamSettings.sockopt = outbound.streamSettings.sockopt or {}
+ outbound.streamSettings.sockopt.dialerProxy = preproxy_outbound.tag
if not exist then
last_insert_outbound = preproxy_outbound
end
@@ -1259,10 +1254,9 @@ function gen_config(var)
if to_outbound then
to_outbound.tag = outbound.tag .. " -> " .. to_outbound.tag
if to_node.type == "Xray" then
- to_outbound.proxySettings = {
- tag = outbound.tag,
- transportLayer = true
- }
+ to_outbound.streamSettings = to_outbound.streamSettings or {}
+ to_outbound.streamSettings.sockopt = to_outbound.streamSettings.sockopt or {}
+ to_outbound.streamSettings.sockopt.dialerProxy = outbound.tag
end
table.insert(outbounds_table, to_outbound)
default_outTag = to_outbound.tag