🍉 Sync 2025-11-07 00:12:45
This commit is contained in:
@@ -77,10 +77,12 @@ function index()
|
|||||||
entry({"admin", "services", appname, "connect_status"}, call("connect_status")).leaf = true
|
entry({"admin", "services", appname, "connect_status"}, call("connect_status")).leaf = true
|
||||||
entry({"admin", "services", appname, "ping_node"}, call("ping_node")).leaf = true
|
entry({"admin", "services", appname, "ping_node"}, call("ping_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "urltest_node"}, call("urltest_node")).leaf = true
|
entry({"admin", "services", appname, "urltest_node"}, call("urltest_node")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "add_node"}, call("add_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true
|
entry({"admin", "services", appname, "set_node"}, call("set_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true
|
entry({"admin", "services", appname, "copy_node"}, call("copy_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
|
entry({"admin", "services", appname, "clear_all_nodes"}, call("clear_all_nodes")).leaf = true
|
||||||
entry({"admin", "services", appname, "delete_select_nodes"}, call("delete_select_nodes")).leaf = true
|
entry({"admin", "services", appname, "delete_select_nodes"}, call("delete_select_nodes")).leaf = true
|
||||||
|
entry({"admin", "services", appname, "get_node"}, call("get_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "update_rules"}, call("update_rules")).leaf = true
|
entry({"admin", "services", appname, "update_rules"}, call("update_rules")).leaf = true
|
||||||
entry({"admin", "services", appname, "subscribe_del_node"}, call("subscribe_del_node")).leaf = true
|
entry({"admin", "services", appname, "subscribe_del_node"}, call("subscribe_del_node")).leaf = true
|
||||||
entry({"admin", "services", appname, "subscribe_del_all"}, call("subscribe_del_all")).leaf = true
|
entry({"admin", "services", appname, "subscribe_del_all"}, call("subscribe_del_all")).leaf = true
|
||||||
@@ -397,6 +399,21 @@ function urltest_node()
|
|||||||
http_write_json(e)
|
http_write_json(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function add_node()
|
||||||
|
local redirect = http.formvalue("redirect")
|
||||||
|
|
||||||
|
local uuid = api.gen_short_uuid()
|
||||||
|
uci:section(appname, "nodes", uuid)
|
||||||
|
|
||||||
|
if redirect == "1" then
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http.redirect(api.url("node_config", uuid))
|
||||||
|
else
|
||||||
|
api.uci_save(uci, appname, true, true)
|
||||||
|
http_write_json({result = uuid})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function set_node()
|
function set_node()
|
||||||
local protocol = http.formvalue("protocol")
|
local protocol = http.formvalue("protocol")
|
||||||
local section = http.formvalue("section")
|
local section = http.formvalue("section")
|
||||||
@@ -420,7 +437,7 @@ function copy_node()
|
|||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
uci:delete(appname, uuid, "add_from")
|
uci:delete(appname, uuid, "group")
|
||||||
uci:set(appname, uuid, "add_mode", 1)
|
uci:set(appname, uuid, "add_mode", 1)
|
||||||
api.uci_save(uci, appname)
|
api.uci_save(uci, appname)
|
||||||
http.redirect(api.url("node_config", uuid))
|
http.redirect(api.url("node_config", uuid))
|
||||||
@@ -458,6 +475,7 @@ end
|
|||||||
|
|
||||||
function delete_select_nodes()
|
function delete_select_nodes()
|
||||||
local ids = http.formvalue("ids")
|
local ids = http.formvalue("ids")
|
||||||
|
local redirect = http.formvalue("redirect")
|
||||||
string.gsub(ids, '[^' .. "," .. ']+', function(w)
|
string.gsub(ids, '[^' .. "," .. ']+', function(w)
|
||||||
if (uci:get(appname, "@global[0]", "tcp_node") or "") == w then
|
if (uci:get(appname, "@global[0]", "tcp_node") or "") == w then
|
||||||
uci:delete(appname, '@global[0]', "tcp_node")
|
uci:delete(appname, '@global[0]', "tcp_node")
|
||||||
@@ -532,10 +550,10 @@ function delete_select_nodes()
|
|||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
if (uci:get(appname, w, "add_mode") or "0") == "2" then
|
if (uci:get(appname, w, "add_mode") or "0") == "2" then
|
||||||
local add_from = uci:get(appname, w, "add_from") or ""
|
local group = uci:get(appname, w, "group") or ""
|
||||||
if add_from ~= "" then
|
if group ~= "" then
|
||||||
uci:foreach(appname, "subscribe_list", function(t)
|
uci:foreach(appname, "subscribe_list", function(t)
|
||||||
if t["remark"] == add_from then
|
if t["remark"] == group then
|
||||||
uci:delete(appname, t[".name"], "md5")
|
uci:delete(appname, t[".name"], "md5")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -543,7 +561,40 @@ function delete_select_nodes()
|
|||||||
end
|
end
|
||||||
uci:delete(appname, w)
|
uci:delete(appname, w)
|
||||||
end)
|
end)
|
||||||
api.uci_save(uci, appname, true, true)
|
if redirect == "1" then
|
||||||
|
api.uci_save(uci, appname)
|
||||||
|
http.redirect(api.url("node_list"))
|
||||||
|
else
|
||||||
|
api.uci_save(uci, appname, true, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function get_node()
|
||||||
|
local id = http.formvalue("id")
|
||||||
|
local result = {}
|
||||||
|
local show_node_info = api.uci_get_type("@global_other[0]", "show_node_info", "0")
|
||||||
|
|
||||||
|
function add_is_ipv6_key(o)
|
||||||
|
if o and o.address and show_node_info == "1" then
|
||||||
|
local f = api.get_ipv6_full(o.address)
|
||||||
|
if f ~= "" then
|
||||||
|
o.ipv6 = true
|
||||||
|
o.full_address = f
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if id then
|
||||||
|
result = uci:get_all(appname, id)
|
||||||
|
add_is_ipv6_key(result)
|
||||||
|
else
|
||||||
|
uci:foreach(appname, "nodes", function(t)
|
||||||
|
add_is_ipv6_key(t)
|
||||||
|
result[#result + 1] = t
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
http_write_json(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
function update_rules()
|
function update_rules()
|
||||||
|
|||||||
@@ -21,6 +21,21 @@ o = s:option(Value, "remarks", translate("Node Remarks"))
|
|||||||
o.default = translate("Remarks")
|
o.default = translate("Remarks")
|
||||||
o.rmempty = false
|
o.rmempty = false
|
||||||
|
|
||||||
|
o = s:option(Value, "group", translate("Group Name"))
|
||||||
|
o.default = ""
|
||||||
|
o:value("", translate("default"))
|
||||||
|
local groups = {}
|
||||||
|
m.uci:foreach(appname, "nodes", function(s)
|
||||||
|
if s[".name"] ~= arg[1] then
|
||||||
|
if s.group and s.group ~= "" then
|
||||||
|
groups[s.group] = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
for k, v in pairs(groups) do
|
||||||
|
o:value(k)
|
||||||
|
end
|
||||||
|
|
||||||
o = s:option(ListValue, "type", translate("Type"))
|
o = s:option(ListValue, "type", translate("Type"))
|
||||||
|
|
||||||
if api.is_finded("ipt2socks") then
|
if api.is_finded("ipt2socks") then
|
||||||
|
|||||||
@@ -20,221 +20,6 @@ o.default = "0"
|
|||||||
-- [[ Add the node via the link ]]--
|
-- [[ Add the node via the link ]]--
|
||||||
s:append(Template(appname .. "/node_list/link_add_node"))
|
s:append(Template(appname .. "/node_list/link_add_node"))
|
||||||
|
|
||||||
local auto_detection_time = m:get("@global_other[0]", "auto_detection_time") or "0"
|
|
||||||
local show_node_info = m:get("@global_other[0]", "show_node_info") or "0"
|
|
||||||
|
|
||||||
-- [[ Node List ]]--
|
|
||||||
s = m:section(TypedSection, "nodes")
|
|
||||||
s.anonymous = true
|
|
||||||
s.addremove = true
|
|
||||||
s.template = "cbi/tblsection"
|
|
||||||
s.extedit = api.url("node_config", "%s")
|
|
||||||
function s.create(e, t)
|
|
||||||
local uuid = api.gen_short_uuid()
|
|
||||||
t = uuid
|
|
||||||
TypedSection.create(e, t)
|
|
||||||
luci.http.redirect(e.extedit:format(t))
|
|
||||||
end
|
|
||||||
|
|
||||||
function s.remove(e, t)
|
|
||||||
m.uci:foreach(appname, "socks", function(s)
|
|
||||||
if s["node"] == t then
|
|
||||||
m:del(s[".name"])
|
|
||||||
end
|
|
||||||
for k, v in ipairs(m:get(s[".name"], "autoswitch_backup_node") or {}) do
|
|
||||||
if v and v == t then
|
|
||||||
sys.call(string.format("uci -q del_list %s.%s.autoswitch_backup_node='%s'", appname, s[".name"], v))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
m.uci:foreach(appname, "haproxy_config", function(s)
|
|
||||||
if s["lbss"] and s["lbss"] == t then
|
|
||||||
m:del(s[".name"])
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
m.uci:foreach(appname, "acl_rule", function(s)
|
|
||||||
if s["tcp_node"] and s["tcp_node"] == t then
|
|
||||||
m:set(s[".name"], "tcp_node", "default")
|
|
||||||
end
|
|
||||||
if s["udp_node"] and s["udp_node"] == t then
|
|
||||||
m:set(s[".name"], "udp_node", "default")
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
m.uci:foreach(appname, "nodes", function(s)
|
|
||||||
if s["preproxy_node"] == t then
|
|
||||||
m:del(s[".name"], "preproxy_node")
|
|
||||||
m:del(s[".name"], "chain_proxy")
|
|
||||||
end
|
|
||||||
if s["to_node"] == t then
|
|
||||||
m:del(s[".name"], "to_node")
|
|
||||||
m:del(s[".name"], "chain_proxy")
|
|
||||||
end
|
|
||||||
local list_name = s["urltest_node"] and "urltest_node" or (s["balancing_node"] and "balancing_node")
|
|
||||||
if list_name then
|
|
||||||
local nodes = m.uci:get_list(appname, s[".name"], list_name)
|
|
||||||
if nodes then
|
|
||||||
local changed = false
|
|
||||||
local new_nodes = {}
|
|
||||||
for _, node in ipairs(nodes) do
|
|
||||||
if node ~= t then
|
|
||||||
table.insert(new_nodes, node)
|
|
||||||
else
|
|
||||||
changed = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if changed then
|
|
||||||
m.uci:set_list(appname, s[".name"], list_name, new_nodes)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if s["fallback_node"] == t then
|
|
||||||
m:del(s[".name"], "fallback_node")
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
m.uci:foreach(appname, "subscribe_list", function(s)
|
|
||||||
if s["preproxy_node"] == t then
|
|
||||||
m:del(s[".name"], "preproxy_node")
|
|
||||||
m:del(s[".name"], "chain_proxy")
|
|
||||||
end
|
|
||||||
if s["to_node"] == t then
|
|
||||||
m:del(s[".name"], "to_node")
|
|
||||||
m:del(s[".name"], "chain_proxy")
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
if (m:get(t, "add_mode") or "0") == "2" then
|
|
||||||
local add_from = m:get(t, "add_from") or ""
|
|
||||||
if add_from ~= "" then
|
|
||||||
m.uci:foreach(appname, "subscribe_list", function(s)
|
|
||||||
if s["remark"] == add_from then
|
|
||||||
m:del(s[".name"], "md5")
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
TypedSection.remove(e, t)
|
|
||||||
local new_node = ""
|
|
||||||
local node0 = m:get("@nodes[0]") or nil
|
|
||||||
if node0 then
|
|
||||||
new_node = node0[".name"]
|
|
||||||
end
|
|
||||||
if (m:get("@global[0]", "tcp_node") or "") == t then
|
|
||||||
m:set('@global[0]', "tcp_node", new_node)
|
|
||||||
end
|
|
||||||
if (m:get("@global[0]", "udp_node") or "") == t then
|
|
||||||
m:set('@global[0]', "udp_node", new_node)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
s.sortable = true
|
|
||||||
-- 简洁模式
|
|
||||||
o = s:option(DummyValue, "add_from", "")
|
|
||||||
o.cfgvalue = function(t, n)
|
|
||||||
local v = Value.cfgvalue(t, n)
|
|
||||||
if v and v ~= '' then
|
|
||||||
local group = m:get(n, "group") or ""
|
|
||||||
if group ~= "" then
|
|
||||||
v = v .. " " .. group
|
|
||||||
end
|
|
||||||
return v
|
|
||||||
else
|
|
||||||
return ''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
o = s:option(DummyValue, "remarks", translate("Remarks"))
|
|
||||||
o.rawhtml = true
|
|
||||||
o.cfgvalue = function(t, n)
|
|
||||||
local str = ""
|
|
||||||
local is_sub = m:get(n, "is_sub") or ""
|
|
||||||
local group = m:get(n, "group") or ""
|
|
||||||
local remarks = m:get(n, "remarks") or ""
|
|
||||||
local type = m:get(n, "type") or ""
|
|
||||||
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.type' value='%s'/>", appname, n, type)
|
|
||||||
if type == "sing-box" or type == "Xray" then
|
|
||||||
local protocol = m:get(n, "protocol")
|
|
||||||
if protocol == "_balancing" then
|
|
||||||
protocol = translate("Balancing")
|
|
||||||
elseif protocol == "_urltest" then
|
|
||||||
protocol = "URLTest"
|
|
||||||
elseif protocol == "_shunt" then
|
|
||||||
protocol = translate("Shunt")
|
|
||||||
elseif protocol == "vmess" then
|
|
||||||
protocol = "VMess"
|
|
||||||
elseif protocol == "vless" then
|
|
||||||
protocol = "VLESS"
|
|
||||||
elseif protocol == "shadowsocks" then
|
|
||||||
protocol = "SS"
|
|
||||||
elseif protocol == "shadowsocksr" then
|
|
||||||
protocol = "SSR"
|
|
||||||
elseif protocol == "wireguard" then
|
|
||||||
protocol = "WG"
|
|
||||||
elseif protocol == "hysteria" then
|
|
||||||
protocol = "HY"
|
|
||||||
elseif protocol == "hysteria2" then
|
|
||||||
protocol = "HY2"
|
|
||||||
elseif protocol == "anytls" then
|
|
||||||
protocol = "AnyTLS"
|
|
||||||
elseif protocol == "ssh" then
|
|
||||||
protocol = "SSH"
|
|
||||||
else
|
|
||||||
protocol = protocol:gsub("^%l",string.upper)
|
|
||||||
end
|
|
||||||
if type == "sing-box" then type = "Sing-Box" end
|
|
||||||
type = type .. " " .. protocol
|
|
||||||
end
|
|
||||||
local address = m:get(n, "address") or ""
|
|
||||||
local port = m:get(n, "port") or ""
|
|
||||||
local port_s = (port ~= "") and port or m:get(n, "hysteria_hop") or m:get(n, "hysteria2_hop") or ""
|
|
||||||
str = str .. translate(type) .. ":" .. remarks
|
|
||||||
if address ~= "" and port_s ~= "" then
|
|
||||||
port_s = port_s:gsub(":", "-")
|
|
||||||
if show_node_info == "1" then
|
|
||||||
if datatypes.ip6addr(address) then
|
|
||||||
str = str .. string.format("([%s]:%s)", address, port_s)
|
|
||||||
else
|
|
||||||
str = str .. string.format("(%s:%s)", address, port_s)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.address' value='%s'/>", appname, n, address)
|
|
||||||
str = str .. string.format("<input type='hidden' id='cbid.%s.%s.port' value='%s'/>", appname, n, port)
|
|
||||||
return str
|
|
||||||
end
|
|
||||||
|
|
||||||
---- Ping
|
|
||||||
o = s:option(DummyValue, "ping", "Ping")
|
|
||||||
o.width = "8%"
|
|
||||||
o.rawhtml = true
|
|
||||||
o.cfgvalue = function(t, n)
|
|
||||||
local result = "---"
|
|
||||||
if auto_detection_time ~= "icmp" then
|
|
||||||
result = string.format('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'%s\', this, \'icmp\')">%s</a></span>', n, translate("Test"))
|
|
||||||
else
|
|
||||||
result = string.format('<span class="ping_value" cbiid="%s">---</span>', n)
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
---- TCP Ping
|
|
||||||
o = s:option(DummyValue, "tcping", "TCPing")
|
|
||||||
o.width = "8%"
|
|
||||||
o.rawhtml = true
|
|
||||||
o.cfgvalue = function(t, n)
|
|
||||||
local result = "---"
|
|
||||||
if auto_detection_time ~= "tcping" then
|
|
||||||
result = string.format('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'%s\', this, \'tcping\')">%s</a></span>', n, translate("Test"))
|
|
||||||
else
|
|
||||||
result = string.format('<span class="tcping_value" cbiid="%s">---</span>', n)
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
o = s:option(DummyValue, "_url_test", translate("URL Test"))
|
|
||||||
o.width = "8%"
|
|
||||||
o.rawhtml = true
|
|
||||||
o.cfgvalue = function(t, n)
|
|
||||||
return string.format('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'%s\', this)">%s</a></span>', n, translate("Test"))
|
|
||||||
end
|
|
||||||
|
|
||||||
m:append(Template(appname .. "/node_list/node_list"))
|
m:append(Template(appname .. "/node_list/node_list"))
|
||||||
|
|
||||||
return m
|
return m
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ o.cfgvalue = function(t, n)
|
|||||||
str = str ~= "" and "<br>" .. str or ""
|
str = str ~= "" and "<br>" .. str or ""
|
||||||
local num = 0
|
local num = 0
|
||||||
m.uci:foreach(appname, "nodes", function(s)
|
m.uci:foreach(appname, "nodes", function(s)
|
||||||
if s["add_from"] ~= "" and s["add_from"] == remark then
|
if s["group"] ~= "" and s["group"] == remark then
|
||||||
num = num + 1
|
num = num + 1
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -79,6 +79,10 @@ local api = require "luci.passwall.api"
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function add_new_node() {
|
||||||
|
window.location.href = '<%=api.url("add_node")%>?redirect=1';
|
||||||
|
}
|
||||||
|
|
||||||
//]]>
|
//]]>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -99,15 +103,14 @@ local api = require "luci.passwall.api"
|
|||||||
<div class="cbi-value">
|
<div class="cbi-value">
|
||||||
<label class="cbi-value-title"></label>
|
<label class="cbi-value-title"></label>
|
||||||
<div class="cbi-value-field">
|
<div class="cbi-value-field">
|
||||||
<input class="btn cbi-button cbi-button-add" type="submit" name="cbi.cts.passwall.nodes." value="<%:Add%>" />
|
<input class="btn cbi-button cbi-button-add" type="button" onclick="add_new_node()" value="<%:Add%>" />
|
||||||
<input class="btn cbi-button cbi-button-add" type="button" onclick="open_add_link_div()" value="<%:Add the node via the link%>" />
|
<input class="btn cbi-button cbi-button-add" type="button" onclick="open_add_link_div()" value="<%:Add the node via the link%>" />
|
||||||
<input class="btn cbi-button cbi-button-remove" type="button" onclick="clear_all_nodes()" value="<%:Clear all nodes%>" />
|
<input class="btn cbi-button cbi-button-remove" type="button" onclick="clear_all_nodes()" value="<%:Clear all nodes%>" />
|
||||||
<input class="btn cbi-button cbi-button-remove" type="button" onclick="delete_select_nodes()" value="<%:Delete select nodes%>" />
|
<input class="btn cbi-button cbi-button-remove" type="button" onclick="delete_select_nodes()" value="<%:Delete select nodes%>" />
|
||||||
<input class="btn cbi-button" type="button" onclick="checked_all_node(this)" value="<%:Select all%>" />
|
<input class="btn cbi-button" type="button" id="select_all_btn" onclick="checked_all_node(this)" value="<%:Select all%>" />
|
||||||
<input class="btn cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="<%:Save & Apply%>" />
|
<input class="btn cbi-button cbi-button-apply" type="submit" name="cbi.apply" value="<%:Save & Apply%>" />
|
||||||
<input class="btn cbi-button cbi-button-save" type="submit" name="cbi.save" value="<%:Save%>" />
|
<input class="btn cbi-button cbi-button-save" type="submit" name="cbi.save" value="<%:Save%>" />
|
||||||
<input class="btn cbi-button cbi-button-reset" type="button" value="<%:Reset%>" onclick="location.href='<%=REQUEST_URI%>'" />
|
<input class="btn cbi-button cbi-button-reset" type="button" value="<%:Reset%>" onclick="location.href='<%=REQUEST_URI%>'" />
|
||||||
<div id="div_node_count"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -44,12 +44,54 @@ table td, .table .td {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<% if api.is_js_luci() then -%>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var cbi_t = [];
|
||||||
|
function cbi_t_add(section, tab) {
|
||||||
|
var t = document.getElementById('tab.' + section + '.' + tab);
|
||||||
|
var c = document.getElementById('container.' + section + '.' + tab);
|
||||||
|
|
||||||
|
if( t && c ) {
|
||||||
|
cbi_t[section] = (cbi_t[section] || [ ]);
|
||||||
|
cbi_t[section][tab] = { 'tab': t, 'container': c, 'cid': c.id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function cbi_t_switch(section, tab) {
|
||||||
|
if( cbi_t[section] && cbi_t[section][tab] ) {
|
||||||
|
//在切换选项卡之前,先取消当前激活选项卡的全选状态
|
||||||
|
var btn = document.getElementById("select_all_btn");
|
||||||
|
if (btn) {
|
||||||
|
dechecked_all_node(btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
var o = cbi_t[section][tab];
|
||||||
|
var h = document.getElementById('tab.' + section);
|
||||||
|
for( var tid in cbi_t[section] ) {
|
||||||
|
var o2 = cbi_t[section][tid];
|
||||||
|
if( o.tab.id != o2.tab.id ) {
|
||||||
|
o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab( |$)/, " cbi-tab-disabled ");
|
||||||
|
o2.container.style.display = 'none';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(h) h.value = tab;
|
||||||
|
o2.tab.className = o2.tab.className.replace(/(^| )cbi-tab-disabled( |$)/, " cbi-tab ");
|
||||||
|
o2.container.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<%- end %>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
//<![CDATA[
|
//<![CDATA[
|
||||||
let auto_detection_time = "<%=api.uci_get_type("@global_other[0]", "auto_detection_time", "0")%>"
|
let auto_detection_time = "<%=api.uci_get_type("@global_other[0]", "auto_detection_time", "0")%>"
|
||||||
|
let show_node_info = "<%=api.uci_get_type("@global_other[0]", "show_node_info", "0")%>"
|
||||||
|
|
||||||
var node_list = {};
|
var node_list = [];
|
||||||
var node_count = 0;
|
|
||||||
|
|
||||||
var ajax = {
|
var ajax = {
|
||||||
post: function(url, data, fn_success, timeout, fn_timeout) {
|
post: function(url, data, fn_success, timeout, fn_timeout) {
|
||||||
@@ -106,6 +148,10 @@ table td, .table .td {
|
|||||||
window.location.href = '<%=api.url("copy_node")%>' + "?section=" + cbi_id;
|
window.location.href = '<%=api.url("copy_node")%>' + "?section=" + cbi_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function del_node(cbi_id) {
|
||||||
|
window.location.href = '<%=api.url("delete_select_nodes")%>' + "?redirect=1&ids=" + cbi_id;
|
||||||
|
}
|
||||||
|
|
||||||
var section = "";
|
var section = "";
|
||||||
function open_set_node_div(cbi_id) {
|
function open_set_node_div(cbi_id) {
|
||||||
section = cbi_id;
|
section = cbi_id;
|
||||||
@@ -120,6 +166,7 @@ table td, .table .td {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _cbi_row_top(id) {
|
function _cbi_row_top(id) {
|
||||||
|
//此函数已经损坏,等待修复或其他解决方案。
|
||||||
var dom = document.getElementById("cbi-passwall-" + id);
|
var dom = document.getElementById("cbi-passwall-" + id);
|
||||||
if (dom) {
|
if (dom) {
|
||||||
var trs = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-section-table-row");
|
var trs = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-section-table-row");
|
||||||
@@ -135,7 +182,9 @@ table td, .table .td {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checked_all_node(btn) {
|
function checked_all_node(btn) {
|
||||||
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
|
var visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
|
||||||
|
if (!visibleContainer) return;
|
||||||
|
var doms = visibleContainer.getElementsByClassName("nodes_select");
|
||||||
if (doms && doms.length > 0) {
|
if (doms && doms.length > 0) {
|
||||||
for (var i = 0 ; i < doms.length; i++) {
|
for (var i = 0 ; i < doms.length; i++) {
|
||||||
doms[i].checked = true;
|
doms[i].checked = true;
|
||||||
@@ -146,7 +195,9 @@ table td, .table .td {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dechecked_all_node(btn) {
|
function dechecked_all_node(btn) {
|
||||||
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
|
var visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
|
||||||
|
if (!visibleContainer) return;
|
||||||
|
var doms = visibleContainer.getElementsByClassName("nodes_select");
|
||||||
if (doms && doms.length > 0) {
|
if (doms && doms.length > 0) {
|
||||||
for (var i = 0 ; i < doms.length; i++) {
|
for (var i = 0 ; i < doms.length; i++) {
|
||||||
doms[i].checked = false;
|
doms[i].checked = false;
|
||||||
@@ -158,7 +209,9 @@ table td, .table .td {
|
|||||||
|
|
||||||
function delete_select_nodes() {
|
function delete_select_nodes() {
|
||||||
var ids = [];
|
var ids = [];
|
||||||
var doms = document.getElementById("cbi-passwall-nodes").getElementsByClassName("nodes_select");
|
var visibleContainer = document.querySelector('#cbi-passwall-nodes > .cbi-tabcontainer[style*="display:block"], #cbi-passwall-nodes > .cbi-tabcontainer[style*="display: block"]');
|
||||||
|
if (!visibleContainer) return;
|
||||||
|
var doms = visibleContainer.getElementsByClassName("nodes_select");
|
||||||
if (doms && doms.length > 0) {
|
if (doms && doms.length > 0) {
|
||||||
for (var i = 0 ; i < doms.length; i++) {
|
for (var i = 0 ; i < doms.length; i++) {
|
||||||
if (doms[i].checked) {
|
if (doms[i].checked) {
|
||||||
@@ -215,7 +268,7 @@ table td, .table .td {
|
|||||||
if (id) {
|
if (id) {
|
||||||
var dom = document.getElementById("cbi-passwall-" + id);
|
var dom = document.getElementById("cbi-passwall-" + id);
|
||||||
if (dom) {
|
if (dom) {
|
||||||
dom.title = "当前使用的 TCP 节点";
|
dom.title = '<%=api.i18n.translatef("Currently using %s node", "TCP")%>';
|
||||||
dom.classList.add("_now_use_bg");
|
dom.classList.add("_now_use_bg");
|
||||||
//var v = "<a style='color: red'>当前TCP节点:</a>" + document.getElementById("cbid.passwall." + id + ".remarks").value;
|
//var v = "<a style='color: red'>当前TCP节点:</a>" + document.getElementById("cbid.passwall." + id + ".remarks").value;
|
||||||
//document.getElementById("cbi-passwall-" + id + "-remarks").innerHTML = v;
|
//document.getElementById("cbi-passwall-" + id + "-remarks").innerHTML = v;
|
||||||
@@ -230,9 +283,9 @@ table td, .table .td {
|
|||||||
var dom = document.getElementById("cbi-passwall-" + id);
|
var dom = document.getElementById("cbi-passwall-" + id);
|
||||||
if (dom) {
|
if (dom) {
|
||||||
if (result["TCP"] == result["UDP"]) {
|
if (result["TCP"] == result["UDP"]) {
|
||||||
dom.title = "当前使用的 TCP/UDP 节点";
|
dom.title = '<%=api.i18n.translatef("Currently using %s node", "TCP/UDP")%>';
|
||||||
} else {
|
} else {
|
||||||
dom.title = "当前使用的 UDP 节点";
|
dom.title = '<%=api.i18n.translatef("Currently using %s node", "UDP")%>';
|
||||||
}
|
}
|
||||||
dom.classList.add("_now_use_bg");
|
dom.classList.add("_now_use_bg");
|
||||||
var dom_remarks = document.getElementById("cbi-passwall-" + id + "-remarks");
|
var dom_remarks = document.getElementById("cbi-passwall-" + id + "-remarks");
|
||||||
@@ -309,6 +362,7 @@ table td, .table .td {
|
|||||||
/* 自动Ping */
|
/* 自动Ping */
|
||||||
function pingAllNodes() {
|
function pingAllNodes() {
|
||||||
if (auto_detection_time == "icmp" || auto_detection_time == "tcping") {
|
if (auto_detection_time == "icmp" || auto_detection_time == "tcping") {
|
||||||
|
const now = Date.now();
|
||||||
var nodes = [];
|
var nodes = [];
|
||||||
const ping_value = document.getElementsByClassName(auto_detection_time == "tcping" ? 'tcping_value' : 'ping_value');
|
const ping_value = document.getElementsByClassName(auto_detection_time == "tcping" ? 'tcping_value' : 'ping_value');
|
||||||
for (var i = 0; i < ping_value.length; i++) {
|
for (var i = 0; i < ping_value.length; i++) {
|
||||||
@@ -316,7 +370,7 @@ table td, .table .td {
|
|||||||
var full = get_address_full(cbi_id);
|
var full = get_address_full(cbi_id);
|
||||||
if ((auto_detection_time == "icmp" && full.address != "" ) || (auto_detection_time == "tcping" && full.address != "" && full.port != "")) {
|
if ((auto_detection_time == "icmp" && full.address != "" ) || (auto_detection_time == "tcping" && full.address != "" && full.port != "")) {
|
||||||
var flag = false;
|
var flag = false;
|
||||||
//当有多个相同地址和端口时合在一起
|
// Merge duplicates
|
||||||
for (var j = 0; j < nodes.length; j++) {
|
for (var j = 0; j < nodes.length; j++) {
|
||||||
if (nodes[j].address == full.address && nodes[j].port == full.port) {
|
if (nodes[j].address == full.address && nodes[j].port == full.port) {
|
||||||
nodes[j].indexs = nodes[j].indexs + "," + i;
|
nodes[j].indexs = nodes[j].indexs + "," + i;
|
||||||
@@ -326,11 +380,23 @@ table td, .table .td {
|
|||||||
}
|
}
|
||||||
if (flag)
|
if (flag)
|
||||||
continue;
|
continue;
|
||||||
nodes.push({
|
|
||||||
indexs: i + "",
|
const cacheData = JSON.parse(localStorage.getItem(auto_detection_time + ":" + full.address + ":" + full.port));
|
||||||
address: full.address,
|
if (cacheData && cacheData.savetime && (now - cacheData.timestamp) < cacheData.savetime) {
|
||||||
port: full.port
|
if (cacheData.value < 100)
|
||||||
});
|
ping_value[i].innerHTML = "<font style='color:green'>" + cacheData.value + " ms" + "</font>";
|
||||||
|
else if (cacheData.value < 200)
|
||||||
|
ping_value[i].innerHTML = "<font style='color:#fb9a05'>" + cacheData.value + " ms" + "</font>";
|
||||||
|
else if (cacheData.value >= 200)
|
||||||
|
ping_value[i].innerHTML = "<font style='color:red'>" + cacheData.value + " ms" + "</font>";
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem(auto_detection_time + ":" + full.address + ":" + full.port);
|
||||||
|
nodes.push({
|
||||||
|
indexs: i + "",
|
||||||
|
address: full.address,
|
||||||
|
port: full.port
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,39 +405,47 @@ table td, .table .td {
|
|||||||
const dom = nodes[index];
|
const dom = nodes[index];
|
||||||
if (!dom) res()
|
if (!dom) res()
|
||||||
ajax.post('<%=api.url("ping_node")%>', {
|
ajax.post('<%=api.url("ping_node")%>', {
|
||||||
index: dom.indexs,
|
index: dom.indexs,
|
||||||
address: dom.address,
|
address: dom.address,
|
||||||
port: dom.port,
|
port: dom.port,
|
||||||
type: auto_detection_time
|
type: auto_detection_time
|
||||||
},
|
},
|
||||||
function(x, result) {
|
function(x, result) {
|
||||||
if (x && x.status == 200) {
|
if (x && x.status == 200) {
|
||||||
var strs = dom.indexs.split(",");
|
|
||||||
for (var i = 0; i < strs.length; i++) {
|
|
||||||
if (result.ping == null || result.ping.trim() == "") {
|
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
|
||||||
} else {
|
|
||||||
var ping = parseInt(result.ping);
|
|
||||||
if (ping < 100)
|
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
|
||||||
else if (ping < 200)
|
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
|
||||||
else if (ping >= 200)
|
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res();
|
|
||||||
},
|
|
||||||
5000,
|
|
||||||
function(x) {
|
|
||||||
var strs = dom.indexs.split(",");
|
var strs = dom.indexs.split(",");
|
||||||
for (var i = 0; i < strs.length; i++) {
|
for (var i = 0; i < strs.length; i++) {
|
||||||
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
if (result.ping == null || result.ping.trim() == "") {
|
||||||
|
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||||
|
} else {
|
||||||
|
var ping = parseInt(result.ping);
|
||||||
|
//save to cache
|
||||||
|
const cache_data = {
|
||||||
|
dom_id: strs[i],
|
||||||
|
timestamp: Date.now(),
|
||||||
|
savetime: 60 * 1000,
|
||||||
|
value: ping
|
||||||
|
};
|
||||||
|
localStorage.setItem(auto_detection_time + ":" + dom.address + ":" + dom.port, JSON.stringify(cache_data));
|
||||||
|
if (ping < 100)
|
||||||
|
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>";
|
||||||
|
else if (ping < 200)
|
||||||
|
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>";
|
||||||
|
else if (ping >= 200)
|
||||||
|
ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res();
|
|
||||||
}
|
}
|
||||||
);
|
res();
|
||||||
|
},
|
||||||
|
5000,
|
||||||
|
function(x) {
|
||||||
|
var strs = dom.indexs.split(",");
|
||||||
|
for (var i = 0; i < strs.length; i++) {
|
||||||
|
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>";
|
||||||
|
}
|
||||||
|
res();
|
||||||
|
}
|
||||||
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,66 +461,212 @@ table td, .table .td {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
var edit_btn = document.getElementById("cbi-passwall-nodes").getElementsByClassName("cbi-button cbi-button-edit");
|
<script type="text/template" id="nodes-table-template">
|
||||||
for (var i = 0; i < edit_btn.length; i++) {
|
<fieldset class="cbi-section cbi-tblsection" id="cbi-passwall-nodes-{{group}}-fieldset">
|
||||||
try {
|
<table class="table cbi-section-table" id="cbi-passwall-nodes-{{group}}-table" style="">
|
||||||
var onclick_str = edit_btn[i].getAttribute("onclick");
|
<tr class="tr cbi-section-table-titles anonymous">
|
||||||
var id = onclick_str.substring(onclick_str.lastIndexOf('/') + 1, onclick_str.length - 1);
|
<th class="th cbi-section-table-cell" style="width:40%"><%:Remarks%></th>
|
||||||
var td = edit_btn[i].parentNode;
|
<th class="th cbi-section-table-cell" style="width:8%">Ping</th>
|
||||||
var new_div = "";
|
<th class="th cbi-section-table-cell" style="width:8%">TCPing</th>
|
||||||
//添加"勾选"框
|
<th class="th cbi-section-table-cell" style="width:8%"><%:URL Test%></th>
|
||||||
new_div += '<input class="cbi-input-checkbox nodes_select" type="checkbox" cbid="' + id + '" /> ';
|
<th class="th cbi-section-table-cell cbi-section-actions"></th>
|
||||||
//添加"置顶"按钮
|
</tr>
|
||||||
new_div += '<input class="btn cbi-button" type="button" value="<%:To Top%>" onclick="_cbi_row_top(\'' + id + '\')"/> ';
|
{{node-tr}}
|
||||||
//添加"应用"按钮
|
</table>
|
||||||
new_div += '<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Use%>" id="apply_' + id + '" onclick="open_set_node_div(\'' + id + '\')"/> ';
|
<div class="cbi-section-create cbi-tblsection-create">
|
||||||
//添加"复制"按钮
|
<input class="cbi-button cbi-button-add" type="button" value="<%:Add%>" onclick="location.href='<%=api.url("add_node")%>?redirect=1'">
|
||||||
new_div += '<input class="btn cbi-button cbi-button-add" type="button" value="<%:Copy%>" onclick="copy_node(\'' + id + '\')"/> ';
|
</div>
|
||||||
td.innerHTML = new_div + td.innerHTML;
|
</fieldset>
|
||||||
|
</script>
|
||||||
|
|
||||||
var obj = {};
|
<script type="text/template" id="node-tr-template">
|
||||||
obj.id = id;
|
<tr class="tr cbi-section-table-row" id="cbi-passwall-{{id}}">
|
||||||
obj.type = document.getElementById("cbid.passwall." + id + ".type").value;
|
<input class="hidden" id="cbid.passwall.{{id}}.remarks" value="{{remarks_val}}"/>
|
||||||
var address_dom = document.getElementById("cbid.passwall." + id + ".address");
|
<input class="hidden" id="cbid.passwall.{{id}}.address" value="{{address_val}}"/>
|
||||||
var port_dom = document.getElementById("cbid.passwall." + id + ".port");
|
<input class="hidden" id="cbid.passwall.{{id}}.port" value="{{port_val}}"/>
|
||||||
if (address_dom && port_dom) {
|
<td class="td cbi-value-field">{{remarks}}</td>
|
||||||
obj.address = address_dom.value;
|
<td class="td cbi-value-field">{{ping}}</td>
|
||||||
obj.port = port_dom.value;
|
<td class="td cbi-value-field">{{tcping}}</td>
|
||||||
|
<td class="td cbi-value-field">{{url_test}}</td>
|
||||||
|
<td class="td cbi-section-table-cell nowrap cbi-section-actions">
|
||||||
|
<div>
|
||||||
|
<!--It has been damaged and awaits repair or other solutions.-->
|
||||||
|
<!--<input class="btn cbi-button" type="button" value="<%:To Top%>" onclick="_cbi_row_top('{{id}}')"/>-->
|
||||||
|
<input class="cbi-input-checkbox nodes_select" type="checkbox" cbid="{{id}}" />
|
||||||
|
<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Use%>" id="apply_{{id}}" onclick="open_set_node_div('{{id}}')"/>
|
||||||
|
<input class="btn cbi-button cbi-button-add" type="button" value="<%:Copy%>" onclick="copy_node('{{id}}')"/>
|
||||||
|
<input class="btn cbi-button cbi-button-edit" type="button" value="<%:Edit%>" onclick="location.href='<%=api.url("node_config")%>/{{id}}'" alt="<%:Edit%>" title="<%:Edit%>">
|
||||||
|
<input class="btn cbi-button cbi-button-remove" type="button" value="<%:Delete%>" onclick="del_node('{{id}}')" alt="<%:Delete%>" title="<%:Delete%>">
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<fieldset class="cbi-section" id="node_list">
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function get_remarks_name(o) {
|
||||||
|
let str = "";
|
||||||
|
let remarks = o["remarks"] || "";
|
||||||
|
let type = o["type"] || "";
|
||||||
|
str += "<input type='hidden' id='cbid.passwall." + o[".name"] + ".type' value='" + type + "'/>";
|
||||||
|
if (type == "sing-box" || type == "Xray") {
|
||||||
|
let protocol = o["protocol"]
|
||||||
|
let p = "";
|
||||||
|
if (protocol == "_balancing") {
|
||||||
|
p = "<%:Balancing%>";
|
||||||
|
} else if (protocol == "_urltest") {
|
||||||
|
p = "URLTest";
|
||||||
|
} else if (protocol == "_shunt") {
|
||||||
|
p = "<%:Shunt%>";
|
||||||
|
} else if (protocol == "vmess") {
|
||||||
|
p = "VMess";
|
||||||
|
} else if (protocol == "vless") {
|
||||||
|
p = "VLESS";
|
||||||
|
} else if (protocol == "shadowsocks") {
|
||||||
|
p = "SS";
|
||||||
|
} else if (protocol == "shadowsocksr") {
|
||||||
|
p = "SSR";
|
||||||
|
} else if (protocol == "wireguard") {
|
||||||
|
p = "WG";
|
||||||
|
} else if (protocol == "hysteria") {
|
||||||
|
p = "HY";
|
||||||
|
} else if (protocol == "hysteria2") {
|
||||||
|
p = "HY2";
|
||||||
|
} else if (protocol == "anytls") {
|
||||||
|
p = "AnyTLS";
|
||||||
|
} else if (protocol == "ssh") {
|
||||||
|
p = "SSH";
|
||||||
|
} else {
|
||||||
|
p = protocol.charAt(0).toUpperCase() + protocol.slice(1);
|
||||||
}
|
}
|
||||||
|
if (type == "sing-box") {
|
||||||
node_count++;
|
type = "Sing-Box";
|
||||||
var add_from = document.getElementById("cbid.passwall." + id + ".add_from").value;
|
}
|
||||||
if (node_list[add_from])
|
type += " " + p;
|
||||||
node_list[add_from].push(obj);
|
|
||||||
else
|
|
||||||
node_list[add_from] = [];
|
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(err) {
|
let address = o["address"] || "";
|
||||||
console.error(err);
|
let port = o["port"] || "";
|
||||||
|
let port_s = "";
|
||||||
|
if (port != "") {
|
||||||
|
port_s = port;
|
||||||
|
} else {
|
||||||
|
port_s = o["hysteria_hop"] || o["hysteria2_hop"];
|
||||||
}
|
}
|
||||||
|
str += type + ":" + remarks;
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
get_now_use_node();
|
XHR.get('<%=api.url("get_node")%>', null,
|
||||||
|
function(x, result) {
|
||||||
|
var node_list = result
|
||||||
|
|
||||||
if (true) {
|
var group_nodes = {}
|
||||||
var str = "";
|
for (let i = 0; i < node_list.length; i++) {
|
||||||
for (var add_from in node_list) {
|
let _node = node_list[i]
|
||||||
var num = node_list[add_from].length + 1;
|
if (!_node.group || _node.group === "") {
|
||||||
if (add_from == "") {
|
_node.group = "<%:default%>"
|
||||||
add_from = "<%:Self add%>";
|
}
|
||||||
|
if (!group_nodes[_node.group]) {
|
||||||
|
group_nodes[_node.group] = []
|
||||||
|
}
|
||||||
|
group_nodes[_node.group].push(_node)
|
||||||
}
|
}
|
||||||
str += add_from + " " + "<%:Node num%>: <a style='color: red'>" + num + "</a>   ";
|
|
||||||
}
|
|
||||||
document.getElementById("div_node_count").innerHTML = "<div style='margin-top:5px'>" + str + "</div>";
|
|
||||||
}
|
|
||||||
|
|
||||||
//UI渲染完成后再自动Ping
|
var tab_ul_html = '<ul class="cbi-tabmenu">'
|
||||||
|
var tab_ul_li_html = ''
|
||||||
|
var tab_content_html = '<fieldset class="cbi-section-node cbi-section-node-tabbed" id="cbi-passwall-nodes">'
|
||||||
|
var nodes_table_template = document.getElementById("nodes-table-template");
|
||||||
|
var node_template = document.getElementById("node-tr-template");
|
||||||
|
var default_group = null
|
||||||
|
for (let group in group_nodes) {
|
||||||
|
if (default_group == null)
|
||||||
|
default_group = group
|
||||||
|
|
||||||
|
var table_html = "";
|
||||||
|
if (true) {
|
||||||
|
//Node List
|
||||||
|
var new_nodes_table_dom = nodes_table_template.cloneNode(true);
|
||||||
|
var _html = new_nodes_table_dom.innerHTML;
|
||||||
|
_html = _html.split("{{group}}").join(group);
|
||||||
|
var node_tr_html = "";
|
||||||
|
for (var i = 0; i < group_nodes[group].length; i++) {
|
||||||
|
let o = group_nodes[group][i]
|
||||||
|
var newDom = node_template.cloneNode(true);
|
||||||
|
newDom.classList.add("cbi-rowstyle-" + (i % 2 + 1));
|
||||||
|
var innerHTML = newDom.innerHTML;
|
||||||
|
if (auto_detection_time != "icmp" && o["address"] && o["port"]) {
|
||||||
|
innerHTML = innerHTML.split("{{ping}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'{{id}}\', this, \'icmp\')"><%:Test%></a></span>');
|
||||||
|
} else {
|
||||||
|
innerHTML = innerHTML.split("{{ping}}").join('<span class="ping_value" cbiid="{{id}}">---</span>');
|
||||||
|
}
|
||||||
|
if (auto_detection_time != "tcping" && o["address"] && o["port"]) {
|
||||||
|
innerHTML = innerHTML.split("{{tcping}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'{{id}}\', this, \'tcping\')"><%:Test%></a></span>');
|
||||||
|
} else {
|
||||||
|
innerHTML = innerHTML.split("{{tcping}}").join('<span class="tcping_value" cbiid="{{id}}">---</span>');
|
||||||
|
}
|
||||||
|
innerHTML = innerHTML.split("{{url_test}}").join('<span class="ping"><a href="javascript:void(0)" onclick="javascript:urltest_node(\'{{id}}\', this)"><%:Test%></a></span>');
|
||||||
|
innerHTML = innerHTML.split("{{id}}").join(o[".name"]);
|
||||||
|
innerHTML = innerHTML.split("{{group}}").join(o["group"] || "");
|
||||||
|
let node_remarks = get_remarks_name(o);
|
||||||
|
if (show_node_info == "1") {
|
||||||
|
if (o["address"] && o["port"]) {
|
||||||
|
let _address = o["address"]
|
||||||
|
if (o["full_address"])
|
||||||
|
_address = o["full_address"]
|
||||||
|
node_remarks += "<br>" + _address + ":" + o["port"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
innerHTML = innerHTML.split("{{remarks}}").join(node_remarks);
|
||||||
|
innerHTML = innerHTML.split("{{remarks_val}}").join(o["remarks"]);
|
||||||
|
innerHTML = innerHTML.split("{{address_val}}").join(o["address"] || "");
|
||||||
|
innerHTML = innerHTML.split("{{port_val}}").join(o["port"] || "");
|
||||||
|
|
||||||
|
node_tr_html += innerHTML
|
||||||
|
}
|
||||||
|
_html = _html.split("{{node-tr}}").join(node_tr_html);
|
||||||
|
table_html = _html;
|
||||||
|
}
|
||||||
|
|
||||||
|
tab_ul_li_html +=
|
||||||
|
'<li id="tab.passwall.nodes.' + group + '" class="cbi-tab">' +
|
||||||
|
'<a onclick="this.blur(); return cbi_t_switch(\'passwall.nodes\', \'' + group + '\')" href="<%=REQUEST_URI%>?tab.passwall.nodes=' + group + '">' + group + " | " + "<font style='color: red'>" + group_nodes[group].length + '</font></a>' +
|
||||||
|
'</li>'
|
||||||
|
tab_content_html +=
|
||||||
|
'<div class="cbi-tabcontainer" id="container.passwall.nodes.' + group + '" style="display: none;">' +
|
||||||
|
'' + table_html +
|
||||||
|
'</div>'
|
||||||
|
}
|
||||||
|
|
||||||
|
tab_ul_html += tab_ul_li_html + '</ul>'
|
||||||
|
tab_content_html += tab_content_html + '</fieldset>'
|
||||||
|
var tab_html = tab_ul_html + tab_content_html
|
||||||
|
|
||||||
|
document.getElementById("node_list").innerHTML = tab_html
|
||||||
|
|
||||||
|
for (let group in group_nodes) {
|
||||||
|
cbi_t_add("passwall.nodes", group)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (default_group) {
|
||||||
|
cbi_t_switch("passwall.nodes", default_group)
|
||||||
|
}
|
||||||
|
|
||||||
|
get_now_use_node();
|
||||||
|
|
||||||
|
pingAllNodes();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
window.onload = function () {
|
window.onload = function () {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
pingAllNodes();
|
pingAllNodes();
|
||||||
}, 800);
|
}, 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
//]]>
|
//]]>
|
||||||
|
|||||||
@@ -1974,3 +1974,9 @@ msgstr "如留空,则使用随机版本。"
|
|||||||
|
|
||||||
msgid "The configured type also applies to the core specified when manually importing nodes."
|
msgid "The configured type also applies to the core specified when manually importing nodes."
|
||||||
msgstr "配置的类型同样适用于手动导入节点时所指定的核心程序。"
|
msgstr "配置的类型同样适用于手动导入节点时所指定的核心程序。"
|
||||||
|
|
||||||
|
msgid "Group Name"
|
||||||
|
msgstr "分组名"
|
||||||
|
|
||||||
|
msgid "Currently using %s node"
|
||||||
|
msgstr "当前使用的 %s 节点"
|
||||||
|
|||||||
@@ -35,14 +35,13 @@ EOF
|
|||||||
|
|
||||||
chmod +x /usr/share/passwall/*.sh
|
chmod +x /usr/share/passwall/*.sh
|
||||||
|
|
||||||
## 4.77-5 below upgrade to 4.77-6 above
|
|
||||||
[ -e "/etc/config/passwall_show" ] && rm -rf /etc/config/passwall_show
|
|
||||||
|
|
||||||
[ "$(uci -q get passwall.@global_xray[0].sniffing)" == "1" ] && [ "$(uci -q get passwall.@global_xray[0].route_only)" != "1" ] && uci -q set passwall.@global_xray[0].sniffing_override_dest=1
|
[ "$(uci -q get passwall.@global_xray[0].sniffing)" == "1" ] && [ "$(uci -q get passwall.@global_xray[0].route_only)" != "1" ] && uci -q set passwall.@global_xray[0].sniffing_override_dest=1
|
||||||
uci -q delete passwall.@global_xray[0].sniffing
|
uci -q delete passwall.@global_xray[0].sniffing
|
||||||
uci -q delete passwall.@global_xray[0].route_only
|
uci -q delete passwall.@global_xray[0].route_only
|
||||||
uci -q commit passwall
|
uci -q commit passwall
|
||||||
|
|
||||||
|
sed -i "s#add_from#group#g" /etc/config/passwall 2>/dev/null
|
||||||
|
|
||||||
rm -f /tmp/luci-indexcache
|
rm -f /tmp/luci-indexcache
|
||||||
rm -rf /tmp/luci-modulecache/
|
rm -rf /tmp/luci-modulecache/
|
||||||
killall -HUP rpcd 2>/dev/null
|
killall -HUP rpcd 2>/dev/null
|
||||||
|
|||||||
@@ -2114,7 +2114,7 @@ stop() {
|
|||||||
# 结束 SS 插件进程
|
# 结束 SS 插件进程
|
||||||
# kill_all xray-plugin v2ray-plugin obfs-local shadow-tls
|
# kill_all xray-plugin v2ray-plugin obfs-local shadow-tls
|
||||||
local pid_file pid
|
local pid_file pid
|
||||||
find "$TMP_PATH" -type f -name '*_plugin.pid' | while read -r pid_file; do
|
find "$TMP_PATH" -type f -name '*_plugin.pid' 2>/dev/null | while read -r pid_file; do
|
||||||
read -r pid < "$pid_file"
|
read -r pid < "$pid_file"
|
||||||
if [ -n "$pid" ]; then
|
if [ -n "$pid" ]; then
|
||||||
kill -9 "$pid" >/dev/null 2>&1
|
kill -9 "$pid" >/dev/null 2>&1
|
||||||
|
|||||||
@@ -781,7 +781,7 @@ filter_direct_node_list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
add_firewall_rule() {
|
add_firewall_rule() {
|
||||||
echolog "开始加载防火墙规则..."
|
echolog "开始加载 iptables 防火墙规则..."
|
||||||
ipset -! create $IPSET_LOCAL nethash maxelem 1048576
|
ipset -! create $IPSET_LOCAL nethash maxelem 1048576
|
||||||
ipset -! create $IPSET_LAN nethash maxelem 1048576
|
ipset -! create $IPSET_LAN nethash maxelem 1048576
|
||||||
ipset -! create $IPSET_VPS nethash maxelem 1048576
|
ipset -! create $IPSET_VPS nethash maxelem 1048576
|
||||||
@@ -980,20 +980,17 @@ add_firewall_rule() {
|
|||||||
$ipt_n -I PREROUTING 1 -j PSW_DNS
|
$ipt_n -I PREROUTING 1 -j PSW_DNS
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$ipt_m -N PSW_DIVERT
|
|
||||||
$ipt_m -A PSW_DIVERT -j MARK --set-mark 1
|
|
||||||
$ipt_m -A PSW_DIVERT -j ACCEPT
|
|
||||||
|
|
||||||
$ipt_m -N PSW_RULE
|
$ipt_m -N PSW_RULE
|
||||||
$ipt_m -A PSW_RULE -j CONNMARK --restore-mark
|
$ipt_m -A PSW_RULE -j CONNMARK --restore-mark
|
||||||
$ipt_m -A PSW_RULE -m mark --mark 1 -j RETURN
|
$ipt_m -A PSW_RULE -m mark --mark 1 -j RETURN
|
||||||
$ipt_m -A PSW_RULE -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j MARK --set-xmark 1
|
$ipt_m -A PSW_RULE -p tcp -m tcp --syn -j MARK --set-xmark 1
|
||||||
$ipt_m -A PSW_RULE -p udp -m conntrack --ctstate NEW -j MARK --set-xmark 1
|
$ipt_m -A PSW_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark 1
|
||||||
$ipt_m -A PSW_RULE -j CONNMARK --save-mark
|
$ipt_m -A PSW_RULE -j CONNMARK --save-mark
|
||||||
|
|
||||||
$ipt_m -N PSW
|
$ipt_m -N PSW
|
||||||
$ipt_m -A PSW $(dst $IPSET_LAN) -j RETURN
|
$ipt_m -A PSW $(dst $IPSET_LAN) -j RETURN
|
||||||
$ipt_m -A PSW $(dst $IPSET_VPS) -j RETURN
|
$ipt_m -A PSW $(dst $IPSET_VPS) -j RETURN
|
||||||
|
$ipt_m -A PSW -m conntrack --ctdir REPLY -j RETURN
|
||||||
|
|
||||||
[ ! -z "${WAN_IP}" ] && {
|
[ ! -z "${WAN_IP}" ] && {
|
||||||
$ipt_m -A PSW $(comment "WAN_IP_RETURN") -d "${WAN_IP}" -j RETURN
|
$ipt_m -A PSW $(comment "WAN_IP_RETURN") -d "${WAN_IP}" -j RETURN
|
||||||
@@ -1002,11 +999,11 @@ add_firewall_rule() {
|
|||||||
unset WAN_IP
|
unset WAN_IP
|
||||||
|
|
||||||
insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW"
|
insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW"
|
||||||
insert_rule_before "$ipt_m" "PREROUTING" "PSW" "-p tcp -m socket -j PSW_DIVERT"
|
|
||||||
|
|
||||||
$ipt_m -N PSW_OUTPUT
|
$ipt_m -N PSW_OUTPUT
|
||||||
$ipt_m -A PSW_OUTPUT $(dst $IPSET_LAN) -j RETURN
|
$ipt_m -A PSW_OUTPUT $(dst $IPSET_LAN) -j RETURN
|
||||||
$ipt_m -A PSW_OUTPUT $(dst $IPSET_VPS) -j RETURN
|
$ipt_m -A PSW_OUTPUT $(dst $IPSET_VPS) -j RETURN
|
||||||
|
$ipt_m -A PSW_OUTPUT -m conntrack --ctdir REPLY -j RETURN
|
||||||
|
|
||||||
[ -n "$IPT_APPEND_DNS" ] && {
|
[ -n "$IPT_APPEND_DNS" ] && {
|
||||||
local local_dns dns_address dns_port
|
local local_dns dns_address dns_port
|
||||||
@@ -1053,20 +1050,17 @@ add_firewall_rule() {
|
|||||||
$ip6t_n -I PREROUTING 1 -j PSW_DNS
|
$ip6t_n -I PREROUTING 1 -j PSW_DNS
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$ip6t_m -N PSW_DIVERT
|
|
||||||
$ip6t_m -A PSW_DIVERT -j MARK --set-mark 1
|
|
||||||
$ip6t_m -A PSW_DIVERT -j ACCEPT
|
|
||||||
|
|
||||||
$ip6t_m -N PSW_RULE
|
$ip6t_m -N PSW_RULE
|
||||||
$ip6t_m -A PSW_RULE -j CONNMARK --restore-mark
|
$ip6t_m -A PSW_RULE -j CONNMARK --restore-mark
|
||||||
$ip6t_m -A PSW_RULE -m mark --mark 1 -j RETURN
|
$ip6t_m -A PSW_RULE -m mark --mark 1 -j RETURN
|
||||||
$ip6t_m -A PSW_RULE -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j MARK --set-xmark 1
|
$ip6t_m -A PSW_RULE -p tcp -m tcp --syn -j MARK --set-xmark 1
|
||||||
$ip6t_m -A PSW_RULE -p udp -m conntrack --ctstate NEW -j MARK --set-xmark 1
|
$ip6t_m -A PSW_RULE -p udp -m conntrack --ctstate NEW,RELATED -j MARK --set-xmark 1
|
||||||
$ip6t_m -A PSW_RULE -j CONNMARK --save-mark
|
$ip6t_m -A PSW_RULE -j CONNMARK --save-mark
|
||||||
|
|
||||||
$ip6t_m -N PSW
|
$ip6t_m -N PSW
|
||||||
$ip6t_m -A PSW $(dst $IPSET_LAN6) -j RETURN
|
$ip6t_m -A PSW $(dst $IPSET_LAN6) -j RETURN
|
||||||
$ip6t_m -A PSW $(dst $IPSET_VPS6) -j RETURN
|
$ip6t_m -A PSW $(dst $IPSET_VPS6) -j RETURN
|
||||||
|
$ip6t_m -A PSW -m conntrack --ctdir REPLY -j RETURN
|
||||||
|
|
||||||
WAN6_IP=$(get_wan6_ip)
|
WAN6_IP=$(get_wan6_ip)
|
||||||
[ ! -z "${WAN6_IP}" ] && $ip6t_m -A PSW $(comment "WAN6_IP_RETURN") -d ${WAN6_IP} -j RETURN
|
[ ! -z "${WAN6_IP}" ] && $ip6t_m -A PSW $(comment "WAN6_IP_RETURN") -d ${WAN6_IP} -j RETURN
|
||||||
@@ -1079,6 +1073,7 @@ add_firewall_rule() {
|
|||||||
$ip6t_m -A PSW_OUTPUT -m mark --mark 0xff -j RETURN
|
$ip6t_m -A PSW_OUTPUT -m mark --mark 0xff -j RETURN
|
||||||
$ip6t_m -A PSW_OUTPUT $(dst $IPSET_LAN6) -j RETURN
|
$ip6t_m -A PSW_OUTPUT $(dst $IPSET_LAN6) -j RETURN
|
||||||
$ip6t_m -A PSW_OUTPUT $(dst $IPSET_VPS6) -j RETURN
|
$ip6t_m -A PSW_OUTPUT $(dst $IPSET_VPS6) -j RETURN
|
||||||
|
$ip6t_m -A PSW_OUTPUT -m conntrack --ctdir REPLY -j RETURN
|
||||||
[ "${USE_BLOCK_LIST}" = "1" ] && $ip6t_m -A PSW_OUTPUT $(dst $IPSET_BLOCK6) -j DROP
|
[ "${USE_BLOCK_LIST}" = "1" ] && $ip6t_m -A PSW_OUTPUT $(dst $IPSET_BLOCK6) -j DROP
|
||||||
[ "${USE_DIRECT_LIST}" = "1" ] && $ip6t_m -A PSW_OUTPUT $(dst $IPSET_WHITE6) -j RETURN
|
[ "${USE_DIRECT_LIST}" = "1" ] && $ip6t_m -A PSW_OUTPUT $(dst $IPSET_WHITE6) -j RETURN
|
||||||
|
|
||||||
@@ -1315,7 +1310,7 @@ del_firewall_rule() {
|
|||||||
$ipt -D $chain $index 2>/dev/null
|
$ipt -D $chain $index 2>/dev/null
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
for chain in "PSW" "PSW_OUTPUT" "PSW_DIVERT" "PSW_DNS" "PSW_RULE"; do
|
for chain in "PSW" "PSW_OUTPUT" "PSW_DNS" "PSW_RULE"; do
|
||||||
$ipt -F $chain 2>/dev/null
|
$ipt -F $chain 2>/dev/null
|
||||||
$ipt -X $chain 2>/dev/null
|
$ipt -X $chain 2>/dev/null
|
||||||
done
|
done
|
||||||
@@ -1369,7 +1364,7 @@ gen_include() {
|
|||||||
[ -z "${_ipt}" ] && return
|
[ -z "${_ipt}" ] && return
|
||||||
|
|
||||||
echo "*$2"
|
echo "*$2"
|
||||||
${_ipt}-save -t $2 | grep "PSW" | grep -v "\-j PSW$" | grep -v "mangle\-OUTPUT\-PSW" | grep -v "socket \-j PSW_DIVERT$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
|
${_ipt}-save -t $2 | grep "PSW" | grep -v "\-j PSW$" | sed -e "s/^-A \(OUTPUT\|PREROUTING\)/-I \1 1/"
|
||||||
echo 'COMMIT'
|
echo 'COMMIT'
|
||||||
}
|
}
|
||||||
local __ipt=""
|
local __ipt=""
|
||||||
@@ -1390,7 +1385,6 @@ gen_include() {
|
|||||||
[ -z "${is_tproxy}" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p tcp -j PSW")
|
[ -z "${is_tproxy}" ] && \$(${MY_PATH} insert_rule_after "$ipt_n" "PREROUTING" "prerouting_rule" "-p tcp -j PSW")
|
||||||
|
|
||||||
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW")
|
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "mwan3" "-j PSW")
|
||||||
\$(${MY_PATH} insert_rule_before "$ipt_m" "PREROUTING" "PSW" "-p tcp -m socket -j PSW_DIVERT")
|
|
||||||
|
|
||||||
WAN_IP=\$(${MY_PATH} get_wan_ip)
|
WAN_IP=\$(${MY_PATH} get_wan_ip)
|
||||||
|
|
||||||
@@ -1423,7 +1417,6 @@ gen_include() {
|
|||||||
[ "$accept_icmpv6" = "1" ] && $ip6t_n -A PREROUTING -p ipv6-icmp -j PSW
|
[ "$accept_icmpv6" = "1" ] && $ip6t_n -A PREROUTING -p ipv6-icmp -j PSW
|
||||||
|
|
||||||
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "-j PSW")
|
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "mwan3" "-j PSW")
|
||||||
\$(${MY_PATH} insert_rule_before "$ip6t_m" "PREROUTING" "PSW" "-p tcp -m socket -j PSW_DIVERT")
|
|
||||||
|
|
||||||
PR_INDEX=\$(${MY_PATH} RULE_LAST_INDEX "$ip6t_m" PSW WAN6_IP_RETURN -1)
|
PR_INDEX=\$(${MY_PATH} RULE_LAST_INDEX "$ip6t_m" PSW WAN6_IP_RETURN -1)
|
||||||
if [ \$PR_INDEX -ge 0 ]; then
|
if [ \$PR_INDEX -ge 0 ]; then
|
||||||
|
|||||||
@@ -815,7 +815,7 @@ filter_direct_node_list() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
add_firewall_rule() {
|
add_firewall_rule() {
|
||||||
echolog "开始加载防火墙规则..."
|
echolog "开始加载 nftables 防火墙规则..."
|
||||||
gen_nft_tables
|
gen_nft_tables
|
||||||
gen_nftset $NFTSET_VPS ipv4_addr 0 0
|
gen_nftset $NFTSET_VPS ipv4_addr 0 0
|
||||||
gen_nftset $NFTSET_GFW ipv4_addr "2d" 0
|
gen_nftset $NFTSET_GFW ipv4_addr "2d" 0
|
||||||
@@ -986,10 +986,6 @@ add_firewall_rule() {
|
|||||||
nft_output_chain="PSW_OUTPUT_MANGLE"
|
nft_output_chain="PSW_OUTPUT_MANGLE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nft "add chain $NFTABLE_NAME PSW_DIVERT"
|
|
||||||
nft "flush chain $NFTABLE_NAME PSW_DIVERT"
|
|
||||||
nft "add rule $NFTABLE_NAME PSW_DIVERT meta l4proto tcp socket transparent 1 mark set 1 counter accept"
|
|
||||||
|
|
||||||
nft "add chain $NFTABLE_NAME PSW_DNS"
|
nft "add chain $NFTABLE_NAME PSW_DNS"
|
||||||
nft "flush chain $NFTABLE_NAME PSW_DNS"
|
nft "flush chain $NFTABLE_NAME PSW_DNS"
|
||||||
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
|
if [ $(config_t_get global dns_redirect "1") = "0" ]; then
|
||||||
@@ -1005,8 +1001,8 @@ add_firewall_rule() {
|
|||||||
nft "flush chain $NFTABLE_NAME PSW_RULE"
|
nft "flush chain $NFTABLE_NAME PSW_RULE"
|
||||||
nft "add rule $NFTABLE_NAME PSW_RULE meta mark set ct mark counter"
|
nft "add rule $NFTABLE_NAME PSW_RULE meta mark set ct mark counter"
|
||||||
nft "add rule $NFTABLE_NAME PSW_RULE meta mark 1 counter return"
|
nft "add rule $NFTABLE_NAME PSW_RULE meta mark 1 counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW_RULE tcp flags &(fin|syn|rst|ack) == syn meta mark set mark and 0x0 xor 0x1 counter"
|
nft "add rule $NFTABLE_NAME PSW_RULE tcp flags syn meta mark set mark and 0x0 xor 0x1 counter"
|
||||||
nft "add rule $NFTABLE_NAME PSW_RULE meta l4proto udp ct state new meta mark set mark and 0x0 xor 0x1 counter"
|
nft "add rule $NFTABLE_NAME PSW_RULE meta l4proto udp ct state new,related meta mark set mark and 0x0 xor 0x1 counter"
|
||||||
nft "add rule $NFTABLE_NAME PSW_RULE ct mark set mark counter"
|
nft "add rule $NFTABLE_NAME PSW_RULE ct mark set mark counter"
|
||||||
|
|
||||||
#ipv4 tproxy mode and udp
|
#ipv4 tproxy mode and udp
|
||||||
@@ -1014,11 +1010,13 @@ add_firewall_rule() {
|
|||||||
nft "flush chain $NFTABLE_NAME PSW_MANGLE"
|
nft "flush chain $NFTABLE_NAME PSW_MANGLE"
|
||||||
nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_LAN counter return"
|
nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_LAN counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_VPS counter return"
|
nft "add rule $NFTABLE_NAME PSW_MANGLE ip daddr @$NFTSET_VPS counter return"
|
||||||
|
nft "add rule $NFTABLE_NAME PSW_MANGLE ct direction reply counter return"
|
||||||
|
|
||||||
nft "add chain $NFTABLE_NAME PSW_OUTPUT_MANGLE"
|
nft "add chain $NFTABLE_NAME PSW_OUTPUT_MANGLE"
|
||||||
nft "flush chain $NFTABLE_NAME PSW_OUTPUT_MANGLE"
|
nft "flush chain $NFTABLE_NAME PSW_OUTPUT_MANGLE"
|
||||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_LAN counter return"
|
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_LAN counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_VPS counter return"
|
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_VPS counter return"
|
||||||
|
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ct direction reply counter return"
|
||||||
|
|
||||||
[ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_BLOCK counter drop"
|
[ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_BLOCK counter drop"
|
||||||
[ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_WHITE counter return"
|
[ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE ip daddr @$NFTSET_WHITE counter return"
|
||||||
@@ -1027,7 +1025,6 @@ add_firewall_rule() {
|
|||||||
# jump chains
|
# jump chains
|
||||||
nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol udp counter jump PSW_MANGLE"
|
nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol udp counter jump PSW_MANGLE"
|
||||||
[ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol tcp counter jump PSW_MANGLE"
|
[ -n "${is_tproxy}" ] && nft "add rule $NFTABLE_NAME mangle_prerouting ip protocol tcp counter jump PSW_MANGLE"
|
||||||
insert_rule_before "$NFTABLE_NAME" "mangle_prerouting" "PSW_MANGLE" "counter jump PSW_DIVERT"
|
|
||||||
|
|
||||||
#ipv4 tcp redirect mode
|
#ipv4 tcp redirect mode
|
||||||
[ -z "${is_tproxy}" ] && {
|
[ -z "${is_tproxy}" ] && {
|
||||||
@@ -1078,11 +1075,13 @@ add_firewall_rule() {
|
|||||||
nft "flush chain $NFTABLE_NAME PSW_MANGLE_V6"
|
nft "flush chain $NFTABLE_NAME PSW_MANGLE_V6"
|
||||||
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_LAN6 counter return"
|
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_LAN6 counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
||||||
|
nft "add rule $NFTABLE_NAME PSW_MANGLE_V6 ct direction reply counter return"
|
||||||
|
|
||||||
nft "add chain $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6"
|
nft "add chain $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6"
|
||||||
nft "flush chain $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6"
|
nft "flush chain $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6"
|
||||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_LAN6 counter return"
|
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_LAN6 counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_VPS6 counter return"
|
||||||
|
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ct direction reply counter return"
|
||||||
[ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_BLOCK6 counter drop"
|
[ "${USE_BLOCK_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_BLOCK6 counter drop"
|
||||||
[ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_WHITE6 counter return"
|
[ "${USE_DIRECT_LIST}" = "1" ] && nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 ip6 daddr @$NFTSET_WHITE6 counter return"
|
||||||
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta mark 0xff counter return"
|
nft "add rule $NFTABLE_NAME PSW_OUTPUT_MANGLE_V6 meta mark 0xff counter return"
|
||||||
@@ -1398,7 +1397,7 @@ gen_include() {
|
|||||||
|
|
||||||
local __nft=" "
|
local __nft=" "
|
||||||
__nft=$(cat <<- EOF
|
__nft=$(cat <<- EOF
|
||||||
[ -z "\$(nft list chain $NFTABLE_NAME mangle_prerouting | grep PSW_DIVERT)" ] && nft -f ${nft_chain_file}
|
[ -z "\$(nft list chain $NFTABLE_NAME mangle_prerouting | grep PSW)" ] && nft -f ${nft_chain_file}
|
||||||
[ -z "${is_tproxy}" ] && {
|
[ -z "${is_tproxy}" ] && {
|
||||||
PR_INDEX=\$(sh ${MY_PATH} RULE_LAST_INDEX "$NFTABLE_NAME" PSW_NAT WAN_IP_RETURN -1)
|
PR_INDEX=\$(sh ${MY_PATH} RULE_LAST_INDEX "$NFTABLE_NAME" PSW_NAT WAN_IP_RETURN -1)
|
||||||
if [ \$PR_INDEX -ge 0 ]; then
|
if [ \$PR_INDEX -ge 0 ]; then
|
||||||
|
|||||||
@@ -450,12 +450,12 @@ local function get_subscribe_info(cfgid, value)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- 处理数据
|
-- 处理数据
|
||||||
local function processData(szType, content, add_mode, add_from)
|
local function processData(szType, content, add_mode, group)
|
||||||
--log(content, add_mode, add_from)
|
--log(content, add_mode, group)
|
||||||
local result = {
|
local result = {
|
||||||
timeout = 60,
|
timeout = 60,
|
||||||
add_mode = add_mode, --0为手动配置,1为导入,2为订阅
|
add_mode = add_mode, --0为手动配置,1为导入,2为订阅
|
||||||
add_from = add_from
|
group = group
|
||||||
}
|
}
|
||||||
--ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0)
|
--ssr://base64(host:port:protocol:method:obfs:base64pass/?obfsparam=base64param&protoparam=base64param&remarks=base64remarks&group=base64group&udpport=0&uot=0)
|
||||||
if szType == 'ssr' then
|
if szType == 'ssr' then
|
||||||
@@ -1539,14 +1539,14 @@ local function curl(url, file, ua, mode)
|
|||||||
return tonumber(result)
|
return tonumber(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function truncate_nodes(add_from)
|
local function truncate_nodes(group)
|
||||||
for _, config in pairs(CONFIG) do
|
for _, config in pairs(CONFIG) do
|
||||||
if config.currentNodes and #config.currentNodes > 0 then
|
if config.currentNodes and #config.currentNodes > 0 then
|
||||||
local newNodes = {}
|
local newNodes = {}
|
||||||
local removeNodesSet = {}
|
local removeNodesSet = {}
|
||||||
for k, v in pairs(config.currentNodes) do
|
for k, v in pairs(config.currentNodes) do
|
||||||
if v.currentNode and v.currentNode.add_mode == "2" then
|
if v.currentNode and v.currentNode.add_mode == "2" then
|
||||||
if (not add_from) or (add_from and add_from == v.currentNode.add_from) then
|
if (not group) or (group and group == v.currentNode.group) then
|
||||||
removeNodesSet[v.currentNode[".name"]] = true
|
removeNodesSet[v.currentNode[".name"]] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1561,7 +1561,7 @@ local function truncate_nodes(add_from)
|
|||||||
end
|
end
|
||||||
else
|
else
|
||||||
if config.currentNode and config.currentNode.add_mode == "2" then
|
if config.currentNode and config.currentNode.add_mode == "2" then
|
||||||
if (not add_from) or (add_from and add_from == config.currentNode.add_from) then
|
if (not group) or (group and group == config.currentNode.group) then
|
||||||
if config.delete then
|
if config.delete then
|
||||||
config.delete(config)
|
config.delete(config)
|
||||||
elseif config.set then
|
elseif config.set then
|
||||||
@@ -1573,13 +1573,13 @@ local function truncate_nodes(add_from)
|
|||||||
end
|
end
|
||||||
uci:foreach(appname, "nodes", function(node)
|
uci:foreach(appname, "nodes", function(node)
|
||||||
if node.add_mode == "2" then
|
if node.add_mode == "2" then
|
||||||
if (not add_from) or (add_from and add_from == node.add_from) then
|
if (not group) or (group and group == node.group) then
|
||||||
uci:delete(appname, node['.name'])
|
uci:delete(appname, node['.name'])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
uci:foreach(appname, "subscribe_list", function(o)
|
uci:foreach(appname, "subscribe_list", function(o)
|
||||||
if (not add_from) or add_from == o.remark then
|
if (not group) or group == o.remark then
|
||||||
uci:delete(appname, o['.name'], "md5")
|
uci:delete(appname, o['.name'], "md5")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -1720,7 +1720,7 @@ local function update_node(manual)
|
|||||||
if manual == 0 and next(group) then
|
if manual == 0 and next(group) then
|
||||||
uci:foreach(appname, "nodes", function(node)
|
uci:foreach(appname, "nodes", function(node)
|
||||||
-- 如果未发现新节点或手动导入的节点就不要删除了...
|
-- 如果未发现新节点或手动导入的节点就不要删除了...
|
||||||
if node.add_mode == "2" and (node.add_from and group[node.add_from] == true) then
|
if node.add_mode == "2" and (node.group and group[node.group] == true) then
|
||||||
uci:delete(appname, node['.name'])
|
uci:delete(appname, node['.name'])
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
@@ -1797,7 +1797,7 @@ local function update_node(manual)
|
|||||||
luci.sys.call("/etc/init.d/" .. appname .. " restart > /dev/null 2>&1 &")
|
luci.sys.call("/etc/init.d/" .. appname .. " restart > /dev/null 2>&1 &")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function parse_link(raw, add_mode, add_from, cfgid)
|
local function parse_link(raw, add_mode, group, cfgid)
|
||||||
if raw and #raw > 0 then
|
if raw and #raw > 0 then
|
||||||
local nodes, szType
|
local nodes, szType
|
||||||
local node_list = {}
|
local node_list = {}
|
||||||
@@ -1833,17 +1833,17 @@ local function parse_link(raw, add_mode, add_from, cfgid)
|
|||||||
xpcall(function ()
|
xpcall(function ()
|
||||||
local result
|
local result
|
||||||
if szType == 'ssd' then
|
if szType == 'ssd' then
|
||||||
result = processData(szType, v, add_mode, add_from)
|
result = processData(szType, v, add_mode, group)
|
||||||
elseif not szType then
|
elseif not szType then
|
||||||
local node = api.trim(v)
|
local node = api.trim(v)
|
||||||
local dat = split(node, "://")
|
local dat = split(node, "://")
|
||||||
if dat and dat[1] and dat[2] then
|
if dat and dat[1] and dat[2] then
|
||||||
if dat[1] == 'vmess' or dat[1] == 'ssr' then
|
if dat[1] == 'vmess' or dat[1] == 'ssr' then
|
||||||
local link = api.trim(dat[2]:gsub("#.*$", ""))
|
local link = api.trim(dat[2]:gsub("#.*$", ""))
|
||||||
result = processData(dat[1], base64Decode(link), add_mode, add_from)
|
result = processData(dat[1], base64Decode(link), add_mode, group)
|
||||||
else
|
else
|
||||||
local link = dat[2]:gsub("&", "&"):gsub("%s*#%s*", "#") -- 一些奇葩的链接用"&"当做"&","#"前后带空格
|
local link = dat[2]:gsub("&", "&"):gsub("%s*#%s*", "#") -- 一些奇葩的链接用"&"当做"&","#"前后带空格
|
||||||
result = processData(dat[1], link, add_mode, add_from)
|
result = processData(dat[1], link, add_mode, group)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -1874,14 +1874,14 @@ local function parse_link(raw, add_mode, add_from, cfgid)
|
|||||||
end
|
end
|
||||||
if #node_list > 0 then
|
if #node_list > 0 then
|
||||||
nodeResult[#nodeResult + 1] = {
|
nodeResult[#nodeResult + 1] = {
|
||||||
remark = add_from,
|
remark = group,
|
||||||
list = node_list
|
list = node_list
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
log('成功解析【' .. add_from .. '】节点数量: ' .. #node_list)
|
log('成功解析【' .. group .. '】节点数量: ' .. #node_list)
|
||||||
else
|
else
|
||||||
if add_mode == "2" then
|
if add_mode == "2" then
|
||||||
log('获取到的【' .. add_from .. '】订阅内容为空,可能是订阅地址无效,或是网络问题,请诊断!')
|
log('获取到的【' .. group .. '】订阅内容为空,可能是订阅地址无效,或是网络问题,请诊断!')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ THEME_TITLE:=Kucat Theme
|
|||||||
PKG_NAME:=luci-theme-$(THEME_NAME)
|
PKG_NAME:=luci-theme-$(THEME_NAME)
|
||||||
LUCI_TITLE:=Kucat Theme by sirpdboy
|
LUCI_TITLE:=Kucat Theme by sirpdboy
|
||||||
LUCI_DEPENDS:=
|
LUCI_DEPENDS:=
|
||||||
PKG_VERSION:=2.7.3
|
PKG_VERSION:=2.7.4
|
||||||
PKG_RELEASE:=20251028
|
PKG_RELEASE:=20251106
|
||||||
|
|
||||||
define Package/luci-theme-$(THEME_NAME)/conffiles
|
define Package/luci-theme-$(THEME_NAME)/conffiles
|
||||||
/www/luci-static/resources/background/
|
/www/luci-static/resources/background/
|
||||||
|
|||||||
@@ -869,7 +869,7 @@ small {
|
|||||||
.main-right>#maincontent {
|
.main-right>#maincontent {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: rgba(var(--primary-rgbbody),var(--primary-rgbm-ts));
|
background-color: rgba(var(--primary-rgbbody),var(--primary-rgbm-ts));
|
||||||
padding: 0.2rem 0.2rem 3rem 0.2rem;
|
padding: 0.2rem 0.2rem 3rem 0.5rem;
|
||||||
z-index: 50
|
z-index: 50
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,7 +960,51 @@ header .fill .status span {
|
|||||||
flex-wrap: nowrap
|
flex-wrap: nowrap
|
||||||
}
|
}
|
||||||
|
|
||||||
span[data-indicator="uci-changes"],span[data-indicator="poll-status"] {
|
span[data-indicator="poll-status"] {
|
||||||
|
font-size: 0 !important;
|
||||||
|
cursor: pointer;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
color: transparent !important;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
display: flex;
|
||||||
|
background-color: rgba(255, 255, 255, 0);
|
||||||
|
-moz-appearance: none;
|
||||||
|
padding: 1rem;
|
||||||
|
transition: all .3s
|
||||||
|
}
|
||||||
|
|
||||||
|
span[data-indicator="poll-status"]:not([data-style="inactive"]):before {
|
||||||
|
font-size: 1.5rem !important;
|
||||||
|
font-family: 'kucat' !important;
|
||||||
|
content: "\e20b";
|
||||||
|
color: var(--body-color);
|
||||||
|
text-decoration: none
|
||||||
|
}
|
||||||
|
|
||||||
|
span[data-indicator="poll-status"]:not([data-style="active"]):before {
|
||||||
|
font-size: 1.5rem !important;
|
||||||
|
font-family: 'kucat' !important;
|
||||||
|
content: "\e20a";
|
||||||
|
color: var(--body-color);
|
||||||
|
text-decoration: none
|
||||||
|
}
|
||||||
|
|
||||||
|
#indicators span[data-indicator="poll-status"],{
|
||||||
|
line-height: 1;
|
||||||
|
padding: 1rem;
|
||||||
|
cursor: pointer !important;
|
||||||
|
font-weight: normal !important;
|
||||||
|
margin: 0;
|
||||||
|
display: inline-block
|
||||||
|
}
|
||||||
|
|
||||||
|
#indicators span[data-indicator="poll-status"]:hover {
|
||||||
|
border-radius: var(--radius1);
|
||||||
|
text-decoration: none
|
||||||
|
}
|
||||||
|
|
||||||
|
span[data-indicator="uci-changes"],#indicators span[data-indicator="poll-status"] {
|
||||||
font-size: 0 !important;
|
font-size: 0 !important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
@@ -979,7 +1023,7 @@ span[data-indicator="uci-changes"]:before {
|
|||||||
text-decoration: none
|
text-decoration: none
|
||||||
}
|
}
|
||||||
|
|
||||||
span[data-indicator="poll-status"]:not([data-style="inactive"]):before {
|
#indicators span[data-indicator="poll-status"]:not([data-style="inactive"]):before {
|
||||||
font-size: 1.5rem !important;
|
font-size: 1.5rem !important;
|
||||||
font-family: 'kucat' !important;
|
font-family: 'kucat' !important;
|
||||||
content: "\e936";
|
content: "\e936";
|
||||||
@@ -987,7 +1031,7 @@ span[data-indicator="poll-status"]:not([data-style="inactive"]):before {
|
|||||||
text-decoration: none
|
text-decoration: none
|
||||||
}
|
}
|
||||||
|
|
||||||
span[data-indicator="poll-status"]:not([data-style="active"]):before {
|
#indicators span[data-indicator="poll-status"]:not([data-style="active"]):before {
|
||||||
font-family: 'kucat' !important;
|
font-family: 'kucat' !important;
|
||||||
font-size: 1.5rem !important;
|
font-size: 1.5rem !important;
|
||||||
content: "\e932";
|
content: "\e932";
|
||||||
@@ -995,7 +1039,7 @@ span[data-indicator="poll-status"]:not([data-style="active"]):before {
|
|||||||
text-decoration: none
|
text-decoration: none
|
||||||
}
|
}
|
||||||
.pdboy-dark:hover,.pdboy-light:hover,
|
.pdboy-dark:hover,.pdboy-light:hover,
|
||||||
span[data-indicator="uci-changes"]:hover,span[data-indicator="poll-status"]:hover,.pdboy-qlogout:hover,.showSide:hover {
|
span[data-indicator="uci-changes"]:hover,#indicators span[data-indicator="poll-status"]:hover,.pdboy-qlogout:hover,.showSide:hover {
|
||||||
background-color: var(--menu-hover-barbgcolor) !important;
|
background-color: var(--menu-hover-barbgcolor) !important;
|
||||||
color: var(--menu-hover-color);
|
color: var(--menu-hover-color);
|
||||||
border-radius: var(--radius1);
|
border-radius: var(--radius1);
|
||||||
@@ -1003,7 +1047,7 @@ span[data-indicator="uci-changes"]:hover,span[data-indicator="poll-status"]:hove
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pdboy-dark,.pdboy-light,
|
.pdboy-dark,.pdboy-light,
|
||||||
span[data-indicator="uci-changes"],span[data-indicator="poll-status"],.pdboy-qlogout {
|
span[data-indicator="uci-changes"],#indicators span[data-indicator="poll-status"],.pdboy-qlogout {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
cursor: pointer !important;
|
cursor: pointer !important;
|
||||||
@@ -1089,63 +1133,6 @@ span[data-indicator="uci-changes"],span[data-indicator="poll-status"],.pdboy-qlo
|
|||||||
-moz-osx-font-smoothing: grayscale
|
-moz-osx-font-smoothing: grayscale
|
||||||
}
|
}
|
||||||
|
|
||||||
.danger {
|
|
||||||
background-color: #d9534f !important;
|
|
||||||
color: #eee
|
|
||||||
}
|
|
||||||
|
|
||||||
.warning {
|
|
||||||
background-color: #b98413 !important;
|
|
||||||
margin: 0 0 0.5rem 0;
|
|
||||||
color: #eee
|
|
||||||
}
|
|
||||||
|
|
||||||
.success {
|
|
||||||
background-color: #1a8361 !important;
|
|
||||||
color: #eee;
|
|
||||||
width: 14rem !important
|
|
||||||
}
|
|
||||||
|
|
||||||
#log_textarea {
|
|
||||||
box-shadow: 0 1px 1px 0 rgba(0,0,0,0.16),0 0 1px 0 var(--input-boxcolor)
|
|
||||||
}
|
|
||||||
|
|
||||||
.error {
|
|
||||||
color: #f00
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert,.alert-message {
|
|
||||||
padding: 1rem;
|
|
||||||
border: 0;
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
line-height: 1.6em;
|
|
||||||
font-family: inherit;
|
|
||||||
min-width: inherit;
|
|
||||||
overflow: unset;
|
|
||||||
border-radius: var(--radius1);
|
|
||||||
background-color: rgba(var(--primary-rgbbody),var(--primary-rgbm-ts));
|
|
||||||
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 var(--input-boxcolor)
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-message>* {
|
|
||||||
margin: 0;
|
|
||||||
white-space: normal
|
|
||||||
}
|
|
||||||
|
|
||||||
.alert-message>h4 {
|
|
||||||
margin: 0.5rem;
|
|
||||||
color: red;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
font-weight: bold
|
|
||||||
}
|
|
||||||
|
|
||||||
.errorbox {
|
|
||||||
color: #f8f8f8;
|
|
||||||
background-color: #f0ad4e;
|
|
||||||
border-color: #eea236
|
|
||||||
}
|
|
||||||
|
|
||||||
.container .alert,.container .alert-message {
|
.container .alert,.container .alert-message {
|
||||||
margin-top: 1rem
|
margin-top: 1rem
|
||||||
}
|
}
|
||||||
@@ -1420,7 +1407,7 @@ h2 {
|
|||||||
h3 {
|
h3 {
|
||||||
font-size: var(--font-d);
|
font-size: var(--font-d);
|
||||||
display: block;
|
display: block;
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0 0 1rem;
|
||||||
color: var(--primary-title-color);
|
color: var(--primary-title-color);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
letter-spacing: 0.1rem;
|
letter-spacing: 0.1rem;
|
||||||
@@ -1433,7 +1420,7 @@ h4 {
|
|||||||
padding: 0.75rem 1.25rem;
|
padding: 0.75rem 1.25rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
font-size: var(--font-z);
|
font-size: var(--font-z);
|
||||||
color: var(--primary-title-color) !important;
|
color: var(--primary-title-color) ;
|
||||||
padding-bottom: 10px
|
padding-bottom: 10px
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2529,11 +2516,68 @@ select,input {
|
|||||||
min-width: 270px;
|
min-width: 270px;
|
||||||
max-width: 900px;
|
max-width: 900px;
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
|
border-radius: var(--radius2) !important;
|
||||||
|
background-color: rgba(var(--primary-rgbbody), 1)!important;
|
||||||
|
color: var(--primary-title-color)!important;
|
||||||
|
box-shadow: 0 2px 10px 0px rgba(255, 255, 255, .16), 0 0 10px 0 rgba(255, 255, 255, .12);
|
||||||
margin: 5em auto;
|
margin: 5em auto;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
border-radius: var(--radius2) !important;
|
}
|
||||||
background-color: rgba(var(--primary-rgbbody),1)!important;
|
|
||||||
box-shadow: 0 2px 10px 0px rgba(255,255,255,.16),0 0 10px 0 rgba(255,255,255,.12)
|
.danger {
|
||||||
|
background-color: #d9534f ;
|
||||||
|
color: #eee
|
||||||
|
}
|
||||||
|
|
||||||
|
#log_textarea {
|
||||||
|
box-shadow: 0 1px 1px 0 rgba(0,0,0,0.16),0 0 1px 0 var(--input-boxcolor)
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: #f00
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert,.alert-message {
|
||||||
|
padding: 1rem;
|
||||||
|
border: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
line-height: 1.6em;
|
||||||
|
font-family: inherit;
|
||||||
|
min-width: inherit;
|
||||||
|
overflow: unset;
|
||||||
|
border-radius: var(--radius1);
|
||||||
|
background-color: rgba(var(--primary-rgbbody),var(--primary-rgbm-ts));
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 0 2px 0 var(--input-boxcolor)
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-message>* {
|
||||||
|
margin: 0;
|
||||||
|
white-space: normal
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-message>h4 {
|
||||||
|
margin: 0.5rem;
|
||||||
|
color: red;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
font-weight: bold
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
background-color: #b98413 !important;
|
||||||
|
color: #eee!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success {
|
||||||
|
background-color: #1a8361 !important;
|
||||||
|
color: #eee!important;
|
||||||
|
width: 14rem !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.errorbox {
|
||||||
|
color: #f8f8f8!important;
|
||||||
|
background-color: #f0ad4e!important;
|
||||||
|
border-color: #eea236
|
||||||
}
|
}
|
||||||
|
|
||||||
#modal_overlay .cbi-section,.modal .cbi-section {
|
#modal_overlay .cbi-section,.modal .cbi-section {
|
||||||
@@ -2599,10 +2643,9 @@ select,input {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notice {
|
.notice {
|
||||||
background-color: #b98413 !important;
|
color: var(--primary-title-color);
|
||||||
background-color: rgba(var(--primary-rgbm),1) !important;
|
background-color: rgba(var(--primary-rgbbody), 1);
|
||||||
padding: 2rem 1rem;
|
padding: 2rem 1rem;
|
||||||
color: #eee
|
|
||||||
}
|
}
|
||||||
.modal>p {
|
.modal>p {
|
||||||
font-size: var(--font-x);
|
font-size: var(--font-x);
|
||||||
@@ -2718,9 +2761,8 @@ body.modal-overlay-active #modal_overlay {
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: .2em;
|
left: .2em;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
color: var(--body-color);
|
|
||||||
content: "";
|
content: "";
|
||||||
|
color: var(--body-color);
|
||||||
background: url(../../resources/icons/loading.svg) no-repeat center,
|
background: url(../../resources/icons/loading.svg) no-repeat center,
|
||||||
url(../../resources/icons/loading.gif) no-repeat center;
|
url(../../resources/icons/loading.gif) no-repeat center;
|
||||||
background-size: 20px;
|
background-size: 20px;
|
||||||
@@ -4028,6 +4070,7 @@ pre.command-output {
|
|||||||
--bg-light: rgba(255, 255, 255, 0);
|
--bg-light: rgba(255, 255, 255, 0);
|
||||||
--bg-gray: rgba(var(--primary-rgbm), 0.02);
|
--bg-gray: rgba(var(--primary-rgbm), 0.02);
|
||||||
--text-title: var(--primary-title-color);
|
--text-title: var(--primary-title-color);
|
||||||
|
--text-secondary: var(--body-color);
|
||||||
--border-color: rgba(255, 255, 255, 0);
|
--border-color: rgba(255, 255, 255, 0);
|
||||||
--border-light: rgba(255, 255, 255, 0);
|
--border-light: rgba(255, 255, 255, 0);
|
||||||
--text-primary: var(--inputtext-color);
|
--text-primary: var(--inputtext-color);
|
||||||
@@ -4189,12 +4232,11 @@ pre.command-output {
|
|||||||
.bandix-card ,
|
.bandix-card ,
|
||||||
.stats-card
|
.stats-card
|
||||||
{
|
{
|
||||||
background-color: rgba(var(--primary-rgbm), 0.1)!important;
|
background-color: rgba(var(--primary-rgbm), 0.05)!important;
|
||||||
border-radius: 0 !important;
|
box-shadow: 0 1px 3px 0 var(--input-boxcolor) !important;
|
||||||
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0) !important;
|
|
||||||
margin-bottom: 0 !important;
|
|
||||||
border: 0px solid #333!important;
|
border: 0px solid #333!important;
|
||||||
border-bottom: 0px solid var(--input-boxcolor)!important;
|
border-bottom: 0px solid var(--input-boxcolor)!important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
overflow: auto!important;
|
overflow: auto!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4283,6 +4325,9 @@ border-bottom: 0px solid #f1f5f9!important;
|
|||||||
[data-page="admin-system-package-manager"] .modal>textarea {
|
[data-page="admin-system-package-manager"] .modal>textarea {
|
||||||
white-space: nowrap
|
white-space: nowrap
|
||||||
}
|
}
|
||||||
|
[data-page="admin-status-overview"] #view>div {
|
||||||
|
padding: 0rem 0rem 1rem 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
.main>.main-left,.cbi-section,[data-tab-title],[data-page^="admin-system-admin"]:not(.node-main-login) .cbi-map:not(#cbi-dropbear),#maincontent>.container>form,#maincontent>.container>form>div,.tabs,.cbi-tabmenu,.cbi-tooltip,#view>p,#view>div,#view>table {
|
.main>.main-left,.cbi-section,[data-tab-title],[data-page^="admin-system-admin"]:not(.node-main-login) .cbi-map:not(#cbi-dropbear),#maincontent>.container>form,#maincontent>.container>form>div,.tabs,.cbi-tabmenu,.cbi-tooltip,#view>p,#view>div,#view>table {
|
||||||
backdrop-filter: var(--ufilter);
|
backdrop-filter: var(--ufilter);
|
||||||
@@ -4392,24 +4437,29 @@ div#add_link_div {
|
|||||||
padding: 0.5rem
|
padding: 0.5rem
|
||||||
}
|
}
|
||||||
|
|
||||||
div#file-manager-container {
|
#file-manager-container {
|
||||||
margin-left: 0.5rem
|
margin-left: 0.5rem
|
||||||
}
|
}
|
||||||
|
|
||||||
div#content-filemanager>div#file-list-container {
|
#content-filemanager>#file-list-container {
|
||||||
margin-top: 10px !important
|
margin-top: 10px !important;
|
||||||
|
min-width: 800px !important;
|
||||||
|
max-width: 100% !important;
|
||||||
|
width: auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
div#file-manager-container #file-table tr>th {
|
#file-manager-container #file-table tr>th {
|
||||||
background-color: rgba(var(--primary-rgbm),1);
|
background-color: rgba(var(--primary-rgbm),1);
|
||||||
color: var(--menu-color)
|
color: var(--menu-color)
|
||||||
}
|
}
|
||||||
|
#file-list-container table>tbody>tr>td span {
|
||||||
div#file-manager-container #status-bar {
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
#file-manager-container #status-bar {
|
||||||
background-color: rgba(var(--primary-rgbm),0.3)
|
background-color: rgba(var(--primary-rgbm),0.3)
|
||||||
}
|
}
|
||||||
|
|
||||||
div#file-manager-container #status-bar #status-info {
|
#file-manager-container #status-bar #status-info {
|
||||||
color: var(--title-color)
|
color: var(--title-color)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4417,6 +4467,9 @@ div#file-manager-container #status-bar #status-info {
|
|||||||
background-color: rgba(var(--primary-rgbm),0.4) !important
|
background-color: rgba(var(--primary-rgbm),0.4) !important
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#file-list-container table>tbody>tr>td {
|
||||||
|
padding: 0.2rem
|
||||||
|
}
|
||||||
.cbi-tabcontainer-content #editor-container {
|
.cbi-tabcontainer-content #editor-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 1px solid var(--inputborder-color)
|
border: 1px solid var(--inputborder-color)
|
||||||
@@ -4441,9 +4494,6 @@ div#file-manager-container #status-bar #status-info {
|
|||||||
--clr-header: var(--title-color)
|
--clr-header: var(--title-color)
|
||||||
}
|
}
|
||||||
|
|
||||||
#file-list-container table>tbody>tr>td {
|
|
||||||
padding: 0.2rem
|
|
||||||
}
|
|
||||||
|
|
||||||
.tr.cbi-section-table-row[id*="wolplus"],.tr.cbi-section-table-row[id*="firewall"] {
|
.tr.cbi-section-table-row[id*="wolplus"],.tr.cbi-section-table-row[id*="firewall"] {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
Reference in New Issue
Block a user