update 2026-09-09 16:33:06

This commit is contained in:
action committed 2026-09-09 16:33:06 +08:00
1 parent 09f0910b78
commit fe313e7d23
27 files changed
+528 -431

No files matched your search

+3 -3
View File
@@ -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+
@@ -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()
@@ -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})
@@ -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)
})
@@ -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)
@@ -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)
@@ -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
@@ -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
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
+76 -98
View File
@@ -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
+11 -17
View File
@@ -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
@@ -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]"
<script type="text/javascript">
//<![CDATA[
let global_id = "<%=sid%>";
const shunt_list = JSON.parse('<%=self.shunt_list%>');
function to_edit_node(btn, stype) {
if (!btn) return;
@@ -235,47 +229,5 @@ local sid = "@global[0]"
select.insertAdjacentElement("afterend", logLink);
};
})();
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
const hiddenSelect = document.getElementById("cbid.<%=appname%>.<%=sid%>.node");
let o_val = hiddenSelect.value
const o_hasItem = shunt_list.find(element => element.id == o_val);
hiddenSelect.addEventListener("change", function(el){
let new_val = el.target.value
const new_hasItem = shunt_list.find(element => element.id == new_val);
if (new_hasItem) {
XHR.get('<%=api.url("update_config")%>', {
id: "<%=sid%>",
data: JSON.stringify({
node: new_val
})
},
function(x, data) {
if (x && x.status == 200 && data.code == 1) {
window.location.reload();
}
else {
alert("<%:Error%>");
}
});
} else {
try {
document.getElementById("tab.<%=appname%>.<%=sid%>.Shunt").classList.add('shunt-tab-hidden');
document.getElementById("tab.<%=appname%>.<%=sid%>.Shunt").style.display = "none";
} catch (error) {}
try {
document.querySelector('li[data-tab*="Shunt"]').classList.add('shunt-tab-hidden');
document.querySelector('li[data-tab*="Shunt"]').style.display = "none";
} catch (error) {}
}
});
let shunt_taboption = document.getElementById("container.<%=appname%>.<%=sid%>.Shunt");
if (shunt_taboption) {
let shunt_option_list = document.getElementById("cbi-<%=appname%>-shunt_option_list");
if (shunt_option_list) {
shunt_taboption.appendChild(shunt_option_list);
}
}
}, 100));
//]]>
</script>
@@ -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 -%>
<script type="text/javascript">
//<![CDATA[
document.addEventListener("DOMContentLoaded", () => {
const shunt_list = JSON.parse('<%=self.shunt_list%>');
const dom_node_id = "<%=verify_option:cbid(section_id)%>";
let uci_node_val = "";
const onChange = (e) => {
const new_val = e.target.value;
const to_shunt = shunt_list.some(element => element.id == new_val);
if (to_shunt) {
const map = document.getElementById("cbi-<%=config%>");
const hiddenInput = document.createElement('input');
hiddenInput.type = 'hidden';
hiddenInput.name = 'node_save_before';
hiddenInput.value = uci_node_val;
map.appendChild(hiddenInput);
const saveBtn = document.getElementsByClassName('cbi-button-save');
if (saveBtn && saveBtn.length > 0) {
saveBtn[saveBtn.length - 1].click();
}
/*
XHR.get('<%=api.url("update_config")%>', {
id: "<%=section_id%>",
data: JSON.stringify({
node: new_val,
mode: "1"
})
}, function(x, data) {
if (x && x.status == 200 && data.code == 1) {
window.location.reload();
} else {
alert("<%:Error%>");
}
});
*/
} else {
try { shunt.hide(); } catch (error) {}
}
};
const check = () => {
const el = document.getElementById(dom_node_id);
if (!el) {
try { shunt.hide(); } catch (error) {}
return;
}
let is_shunt = shunt_list.some(element => element.id == el.value);
if (is_shunt) {
try { shunt.show(); } catch (error) {}
}
if (!el.hasEventListener) {
uci_node_val = el.value;
el.addEventListener("change", onChange);
el.hasEventListener = true;
}
};
const observer = new MutationObserver(check);
observer.observe(document.body, {
childList: true,
subtree: true
});
check();
});
//]]>
</script>
<%- end %>
@@ -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
-%>
<style>
.hidden {
.shunt_hidden {
display: none !important;
visibility: hidden !important;
}
</style>
<script type="text/javascript">
//<![CDATA[
const normal_list = JSON.parse('<%=self.normal_list%>');
var normal_list = JSON.parse('<%=self.normal_list%>');
function check_fakedns(id, val) {
const dom_id = "cbid.table." + id + ".";
const fakedns_dom = document.getElementById(dom_id + "_fakedns");
@@ -21,12 +25,14 @@ local s_cfgid = self.s_cfgid
const selectNode = document.getElementById(dom_id + "_node");
val = selectNode.value;
}
if (val == "" || val == "_direct") {
fakedns_dom.value = 0;
fakedns_dom.checked = false;
fakedns_dom.classList.add('hidden');
} else {
fakedns_dom.classList.remove('hidden');
if (fakedns_dom) {
if (val == "" || val == "_direct") {
fakedns_dom.value = 0;
fakedns_dom.checked = false;
fakedns_dom.classList.add('shunt_hidden');
} else {
fakedns_dom.classList.remove('shunt_hidden');
}
}
}
function check_proxy_tag(id, val) {
@@ -45,13 +51,13 @@ local s_cfgid = self.s_cfgid
const searchInput = document.getElementById(cbid + ".search");
const listContainer = document.getElementById(cbid + ".list");
lv_change(cbid, listContainer, hiddenSelect, labelSpan, searchInput, "", "<%:Close (Not use)%>");
proxy_tag_dom.classList.add('hidden');
proxy_tag_dom?.classList.add('shunt_hidden');
} else {
proxy_tag_dom.classList.remove('hidden');
proxy_tag_dom?.classList.remove('shunt_hidden');
}
}
function refresh_depends() {
const table_dom = document.getElementById("cbi-passwall-shunt_option_list");
const table_dom = document.getElementById("cbi-<%=config%>-<%=section_type%>");
if (table_dom) {
const trs = table_dom.getElementsByTagName("tr");
for (let i = 1; i < trs.length;i++) {
@@ -60,40 +66,82 @@ local s_cfgid = self.s_cfgid
}
}
}
const shunt = {
tab() {
// Move the shunt options to Tab
<% if tab_name then -%>
const shunt_taboption = document.getElementById("container.<%=config%>.<%=section_id%>.<%=tab_name%>");
if (shunt_taboption) {
const shunt_option_list = document.getElementById("cbi-<%=config%>-<%=section_type%>");
if (shunt_option_list) {
shunt_taboption.appendChild(shunt_option_list);
}
}
<%- end %>
},
hide() {
document.getElementById("cbi-<%=config%>-<%=section_type%>")?.classList.add('shunt_hidden');
<% if tab_name then -%>
try { document.getElementById("tab.<%=config%>.<%=section_id%>.<%=tab_name%>")?.classList.add('shunt_hidden'); } catch (error) {}
try { document.querySelector('li[data-tab*="<%=tab_name%>"]')?.classList.add('shunt_hidden'); } catch (error) {}
const shunt_taboption = document.getElementById("container.<%=config%>.<%=section_id%>.<%=tab_name%>");
if (shunt_taboption) {
[...shunt_taboption.querySelectorAll('[name]')].forEach(el => {
const nameValue = el.getAttribute('name');
el.setAttribute('o-name', nameValue);
el.removeAttribute('name');
});
}
<%- end %>
},
show() {
document.getElementById("cbi-<%=config%>-<%=section_type%>")?.classList.remove('shunt_hidden');
<% if tab_name then -%>
try { document.getElementById("tab.<%=config%>.<%=section_id%>.<%=tab_name%>")?.classList.remove('shunt_hidden'); } catch (error) {}
try { document.querySelector('li[data-tab*="<%=tab_name%>"]')?.classList.remove('shunt_hidden'); } catch (error) {}
const shunt_taboption = document.getElementById("container.<%=config%>.<%=section_id%>.<%=tab_name%>");
if (shunt_taboption) {
[...shunt_taboption.querySelectorAll('[o-name]')].forEach(el => {
const nameValue = el.getAttribute('o-name');
el.setAttribute('name', nameValue);
el.removeAttribute('o-name');
});
}
<%- end %>
}
}
document.addEventListener("DOMContentLoaded", function () {
shunt.tab();
waitForElement('select[name*="<%=config%>"][name*="shunt_group"]', function(el) {
let o_val = el.value;
el.addEventListener("change", () => {
el.blur();
if (o_val != el.value) {
let save = true;
if (save) {
update_config("<%=id%>", {
shunt_group: getOption("<%=config%>", "<%=s_cfgid%>", "shunt_group").value,
}, get_current_url());
}
update_config("<%=node_id%>", {
shunt_group: getOption("<%=config%>", "<%=section_id%>", "shunt_group").value,
}, get_current_url());
}
});
});
});
document.addEventListener("DOMContentLoaded", () => setTimeout(() => {
refresh_depends();
const table_dom = document.getElementById("cbi-passwall-shunt_option_list");
if (table_dom) {
const trs = table_dom.getElementsByTagName("tr");
for (let i = 1; i < trs.length;i++) {
const selectNode = document.getElementById("cbid.table." + i + "._node.main");
selectNode.addEventListener("change", function(el){
let new_val = el.target.value
check_fakedns(i, new_val);
check_proxy_tag(i, new_val);
});
if (i == trs.length - 1) {
const newArray = window.lv_dropdown_data["cbid.table." + i + "._node"].ungrouped.filter(item => item.key !== "_default");
window.lv_dropdown_data["cbid.table." + i + "._node"].ungrouped = newArray
setTimeout(() => {
refresh_depends();
const table_dom = document.getElementById("cbi-<%=config%>-<%=section_type%>");
if (table_dom) {
const trs = table_dom.getElementsByTagName("tr");
for (let i = 1; i < trs.length;i++) {
const selectNode = document.getElementById("cbid.table." + i + "._node.main");
selectNode.addEventListener("change", function(el){
let new_val = el.target.value
check_fakedns(i, new_val);
check_proxy_tag(i, new_val);
});
if (i == trs.length - 1) {
const newArray = window.lv_dropdown_data["cbid.table." + i + "._node"].ungrouped.filter(item => item.key !== "_default");
window.lv_dropdown_data["cbid.table." + i + "._node"].ungrouped = newArray
}
}
}
}
}, 100));
}, 200)
});
//]]>
</script>
@@ -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);
*/
}
});
});
@@ -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
+1 -1
View File
@@ -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:= \
@@ -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