🎄 Sync 2025-11-05 10:53:12
This commit is contained in:
@@ -5,10 +5,10 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=daed
|
||||
PKG_VERSION:=2025.09.23
|
||||
PKG_VERSION:=2025.11.03
|
||||
DAED_VERSION:=daed-c3588a9
|
||||
WING_VERSION:=wing-6df3da2
|
||||
CORE_VERSION:=core-5abd651
|
||||
CORE_VERSION:=core-7e67e31
|
||||
WING_HASH_SHORT:=$(shell echo $(WING_VERSION) | cut -d- -f2)
|
||||
CORE_HASH_SHORT:=$(shell echo $(CORE_VERSION) | cut -d- -f2)
|
||||
PKG_RELEASE:=1
|
||||
|
||||
@@ -74,10 +74,12 @@ function index()
|
||||
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, "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, "copy_node"}, call("copy_node")).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, "get_node"}, call("get_node")).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_all"}, call("subscribe_del_all")).leaf = true
|
||||
@@ -326,6 +328,21 @@ function urltest_node()
|
||||
http_write_json(e)
|
||||
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()
|
||||
local type = http.formvalue("type")
|
||||
local config = http.formvalue("config")
|
||||
@@ -350,7 +367,7 @@ function copy_node()
|
||||
end)
|
||||
end
|
||||
end
|
||||
uci:delete(appname, uuid, "add_from")
|
||||
uci:delete(appname, uuid, "group")
|
||||
uci:set(appname, uuid, "add_mode", 1)
|
||||
api.uci_save(uci, appname)
|
||||
http.redirect(api.url("node_config", uuid))
|
||||
@@ -386,6 +403,7 @@ end
|
||||
|
||||
function delete_select_nodes()
|
||||
local ids = http.formvalue("ids")
|
||||
local redirect = http.formvalue("redirect")
|
||||
string.gsub(ids, '[^' .. "," .. ']+', function(w)
|
||||
if (uci:get(appname, "@global[0]", "node") or "") == w then
|
||||
uci:delete(appname, '@global[0]', "node")
|
||||
@@ -454,10 +472,10 @@ function delete_select_nodes()
|
||||
end
|
||||
end)
|
||||
if (uci:get(appname, w, "add_mode") or "0") == "2" then
|
||||
local add_from = uci:get(appname, w, "add_from") or ""
|
||||
if add_from ~= "" then
|
||||
local group = uci:get(appname, w, "group") or ""
|
||||
if group ~= "" then
|
||||
uci:foreach(appname, "subscribe_list", function(t)
|
||||
if t["remark"] == add_from then
|
||||
if t["remark"] == group then
|
||||
uci:delete(appname, t[".name"], "md5")
|
||||
end
|
||||
end)
|
||||
@@ -465,7 +483,25 @@ function delete_select_nodes()
|
||||
end
|
||||
uci:delete(appname, w)
|
||||
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 = {}
|
||||
if id then
|
||||
result = uci:get_all(appname, id)
|
||||
else
|
||||
uci:foreach(appname, "nodes", function(t)
|
||||
result[#result + 1] = t
|
||||
end)
|
||||
end
|
||||
http_write_json(result)
|
||||
end
|
||||
|
||||
function update_rules()
|
||||
|
||||
@@ -22,6 +22,19 @@ o = s:option(Value, "remarks", translate("Node Remarks"))
|
||||
o.default = translate("Remarks")
|
||||
o.rmempty = false
|
||||
|
||||
o = s:option(Value, "group", translate("Group Name"))
|
||||
local groups = {}
|
||||
m.uci:foreach(appname, "nodes", function(s)
|
||||
if s[".name"] ~= arg[1] then
|
||||
if s.group then
|
||||
groups[s.group] = true
|
||||
end
|
||||
end
|
||||
end)
|
||||
for k, v in pairs(groups) do
|
||||
o:value(k)
|
||||
end
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
local types_dir = "/usr/lib/lua/luci/model/cbi/passwall2/client/type/"
|
||||
|
||||
|
||||
@@ -21,214 +21,6 @@ o.default = "0"
|
||||
-- [[ Add the node via the link ]]--
|
||||
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, "acl_rule", function(s)
|
||||
if s["node"] and s["node"] == t then
|
||||
m:set(s[".name"], "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]", "node") or "") == t then
|
||||
if new_node then
|
||||
m:set('@global[0]', "node", new_node)
|
||||
else
|
||||
m:del('@global[0]', "node")
|
||||
end
|
||||
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"))
|
||||
|
||||
return m
|
||||
|
||||
@@ -195,7 +195,7 @@ o.cfgvalue = function(t, n)
|
||||
str = str ~= "" and "<br>" .. str or ""
|
||||
local num = 0
|
||||
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
|
||||
end
|
||||
end)
|
||||
|
||||
@@ -79,6 +79,10 @@ local api = require "luci.passwall2.api"
|
||||
}
|
||||
}
|
||||
|
||||
function add_new_node() {
|
||||
window.location.href = '<%=api.url("add_node")%>?redirect=1';
|
||||
}
|
||||
|
||||
//]]>
|
||||
</script>
|
||||
|
||||
@@ -99,7 +103,7 @@ local api = require "luci.passwall2.api"
|
||||
<div class="cbi-value">
|
||||
<label class="cbi-value-title"></label>
|
||||
<div class="cbi-value-field">
|
||||
<input class="btn cbi-button cbi-button-add" type="submit" name="cbi.cts.<%=api.appname%>.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-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%>" />
|
||||
@@ -107,7 +111,6 @@ local api = require "luci.passwall2.api"
|
||||
<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-reset" type="button" value="<%:Reset%>" onclick="location.href='<%=REQUEST_URI%>'" />
|
||||
<div id="div_node_count"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -61,11 +61,45 @@ table td, .table .td {
|
||||
}
|
||||
</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 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">
|
||||
//<![CDATA[
|
||||
let auto_detection_time = "<%=api.uci_get_type("global_other", "auto_detection_time", "0")%>"
|
||||
var node_list = {};
|
||||
var node_count = 0;
|
||||
var nodes_list = [];
|
||||
|
||||
var ajax = {
|
||||
post: function(url, data, fn_success, timeout, fn_timeout) {
|
||||
@@ -122,6 +156,10 @@ table td, .table .td {
|
||||
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 = "";
|
||||
function open_set_node_div(cbi_id) {
|
||||
section = cbi_id;
|
||||
@@ -136,6 +174,7 @@ table td, .table .td {
|
||||
}
|
||||
|
||||
function _cbi_row_top(id) {
|
||||
//It has been damaged and awaits repair or other solutions.
|
||||
var dom = document.getElementById("cbi-passwall2-" + id);
|
||||
if (dom) {
|
||||
var trs = document.getElementById("cbi-passwall2-nodes").getElementsByClassName("cbi-section-table-row");
|
||||
@@ -217,13 +256,12 @@ table td, .table .td {
|
||||
function get_address_full(id) {
|
||||
var address = (document.getElementById("cbid.passwall2." + id + ".address") || {}).value || "";
|
||||
var port = (document.getElementById("cbid.passwall2." + id + ".port") || {}).value || "";
|
||||
//判断是否含有汉字
|
||||
//Has Chinese characters?
|
||||
var reg = /[\u4E00-\u9FFF]+/;
|
||||
address = !reg.test(address) ? address : "";
|
||||
return { address: address, port: port };
|
||||
}
|
||||
|
||||
//获取当前使用的节点
|
||||
function get_now_use_node() {
|
||||
XHR.get('<%=api.url("get_now_use_node")%>', null,
|
||||
function(x, result) {
|
||||
@@ -231,9 +269,9 @@ table td, .table .td {
|
||||
if (id) {
|
||||
var dom = document.getElementById("cbi-passwall2-" + id);
|
||||
if (dom) {
|
||||
dom.title = "当前使用的节点";
|
||||
dom.title = "<%:Using...%>";
|
||||
dom.classList.add("_now_use_bg");
|
||||
//var v = "<a style='color: red'>当前节点:</a>" + document.getElementById("cbid.passwall2." + id + ".remarks").value;
|
||||
//var v = "<a style='color: red'><%:Using...%>:</a>" + document.getElementById("cbid.passwall2." + id + ".remarks").value;
|
||||
//document.getElementById("cbi-passwall2-" + id + "-remarks").innerHTML = v;
|
||||
var dom_remarks = document.getElementById("cbi-passwall2-" + id + "-remarks");
|
||||
if (dom_remarks) {
|
||||
@@ -306,7 +344,7 @@ table td, .table .td {
|
||||
}
|
||||
}
|
||||
|
||||
/* 自动Ping */
|
||||
/* Auto Ping */
|
||||
function pingAllNodes() {
|
||||
if (auto_detection_time == "icmp" || auto_detection_time == "tcping") {
|
||||
var nodes = [];
|
||||
@@ -316,7 +354,7 @@ table td, .table .td {
|
||||
var full = get_address_full(cbi_id);
|
||||
if ((auto_detection_time == "icmp" && full.address != "" ) || (auto_detection_time == "tcping" && full.address != "" && full.port != "")) {
|
||||
var flag = false;
|
||||
//当有多个相同地址和端口时合在一起
|
||||
// Merge duplicates
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
if (nodes[j].address == full.address && nodes[j].port == full.port) {
|
||||
nodes[j].indexs = nodes[j].indexs + "," + i;
|
||||
@@ -387,66 +425,203 @@ table td, .table .td {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var edit_btn = document.getElementById("cbi-passwall2-nodes").getElementsByClassName("cbi-button cbi-button-edit");
|
||||
for (var i = 0; i < edit_btn.length; i++) {
|
||||
try {
|
||||
var onclick_str = edit_btn[i].getAttribute("onclick");
|
||||
var id = onclick_str.substring(onclick_str.lastIndexOf('/') + 1, onclick_str.length - 1);
|
||||
var td = edit_btn[i].parentNode;
|
||||
var new_div = "";
|
||||
//添加"勾选"框
|
||||
new_div += '<input class="cbi-input-checkbox nodes_select" type="checkbox" cbid="' + id + '" /> ';
|
||||
//添加"置顶"按钮
|
||||
new_div += '<input class="btn cbi-button" type="button" value="<%:To Top%>" onclick="_cbi_row_top(\'' + id + '\')"/> ';
|
||||
//添加"应用"按钮
|
||||
new_div += '<input class="btn cbi-button cbi-button-apply" type="button" value="<%:Use%>" id="apply_' + id + '" onclick="open_set_node_div(\'' + id + '\')"/> ';
|
||||
//添加"复制"按钮
|
||||
new_div += '<input class="btn cbi-button cbi-button-add" type="button" value="<%:Copy%>" onclick="copy_node(\'' + id + '\')"/> ';
|
||||
td.innerHTML = new_div + td.innerHTML;
|
||||
|
||||
var obj = {};
|
||||
obj.id = id;
|
||||
obj.type = document.getElementById("cbid.passwall2." + id + ".type").value;
|
||||
var address_dom = document.getElementById("cbid.passwall2." + id + ".address");
|
||||
var port_dom = document.getElementById("cbid.passwall2." + id + ".port");
|
||||
if (address_dom && port_dom) {
|
||||
obj.address = address_dom.value;
|
||||
obj.port = port_dom.value;
|
||||
</script>
|
||||
|
||||
|
||||
<script type="text/template" id="nodes-table-template">
|
||||
<fieldset class="cbi-section cbi-tblsection" id="cbi-passwall2-nodes-{{group}}-fieldset">
|
||||
<table class="table cbi-section-table" id="cbi-passwall2-nodes-{{group}}-table" style="">
|
||||
<tr class="tr cbi-section-table-titles anonymous">
|
||||
<th class="th cbi-section-table-cell" style="width:40%"><%:Remarks%></th>
|
||||
<th class="th cbi-section-table-cell" style="width:8%">Ping</th>
|
||||
<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>
|
||||
<th class="th cbi-section-table-cell cbi-section-actions"></th>
|
||||
</tr>
|
||||
{{node-tr}}
|
||||
</table>
|
||||
<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'">
|
||||
</div>
|
||||
</fieldset>
|
||||
</script>
|
||||
|
||||
<script type="text/template" id="node-tr-template">
|
||||
<tr class="tr cbi-section-table-row" id="cbi-passwall2-{{id}}">
|
||||
<td class="td cbi-value-field">{{remarks}}<input class="hidden" id="cbid.passwall2.{{id}}.remarks" value="{{remarks}}"/></td>
|
||||
<td class="td cbi-value-field">{{ping}}</td>
|
||||
<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="<%:Del%>" onclick="del_node('{{id}}')" alt="<%:Del%>" title="<%:Del%>">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</script>
|
||||
|
||||
<fieldset class="cbi-section" id="node_list">
|
||||
</fieldset>
|
||||
|
||||
<script type="text/javascript">
|
||||
function get_remarks_name(o) {
|
||||
let show_node_info = "<%=api.uci_get_type("global_other", "show_node_info", "0")%>"
|
||||
let str = "";
|
||||
let remarks = o["remarks"] || "";
|
||||
let type = o["type"] || "";
|
||||
str += "<input type='hidden' id='cbid.passwall2." + 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);
|
||||
}
|
||||
|
||||
node_count++;
|
||||
var add_from = document.getElementById("cbid.passwall2." + id + ".add_from").value;
|
||||
if (node_list[add_from])
|
||||
node_list[add_from].push(obj);
|
||||
else
|
||||
node_list[add_from] = [];
|
||||
|
||||
if (type == "sing-box") {
|
||||
type = "Sing-Box";
|
||||
}
|
||||
type += " " + p;
|
||||
}
|
||||
catch(err) {
|
||||
console.error(err);
|
||||
let address = o["address"] || "";
|
||||
let port = o["port"] || "";
|
||||
let port_s = "";
|
||||
if (port != "") {
|
||||
port_s = port;
|
||||
} else {
|
||||
port_s = o["hysteria_hop"] || o["hysteria2_hop"];
|
||||
}
|
||||
str += type + ":" + remarks;
|
||||
if (address != "" && port_s != "") {
|
||||
port_s = port_s.split(":").join("-");
|
||||
if (show_node_info == "1") {
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
str += "<input type='hidden' id='cbid.passwall2." + o[".name"] + ".address' value='" + address + "'/>";
|
||||
str += "<input type='hidden' id='cbid.passwall2." + o[".name"] + ".port' value='" + port + "'/>";
|
||||
return str;
|
||||
}
|
||||
|
||||
get_now_use_node();
|
||||
|
||||
if (true) {
|
||||
var str = "";
|
||||
for (var add_from in node_list) {
|
||||
var num = node_list[add_from].length + 1;
|
||||
if (add_from == "") {
|
||||
add_from = "<%:Self add%>";
|
||||
XHR.get('<%=api.url("get_node")%>', null,
|
||||
function(x, result) {
|
||||
var node_list = result
|
||||
|
||||
var group_nodes = {}
|
||||
for (let i = 0; i < node_list.length; i++) {
|
||||
let _node = node_list[i]
|
||||
if (!_node.group) {
|
||||
_node.group = "default"
|
||||
}
|
||||
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>   ";
|
||||
|
||||
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-passwall2-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") {
|
||||
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") {
|
||||
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"] || "");
|
||||
innerHTML = innerHTML.split("{{remarks}}").join(get_remarks_name(o));
|
||||
|
||||
node_tr_html += innerHTML
|
||||
}
|
||||
_html = _html.split("{{node-tr}}").join(node_tr_html);
|
||||
table_html = _html;
|
||||
}
|
||||
|
||||
tab_ul_li_html +=
|
||||
'<li id="tab.passwall2.nodes.' + group + '" class="cbi-tab">' +
|
||||
'<a onclick="this.blur(); return cbi_t_switch(\'passwall2.nodes\', \'' + group + '\')" href="<%=REQUEST_URI%>?tab.passwall2.nodes=' + group + '">' + group + " | " + "<font style='color: red'>" + group_nodes[group].length + '</font></a>' +
|
||||
'</li>'
|
||||
tab_content_html +=
|
||||
'<div class="cbi-tabcontainer" id="container.passwall2.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("passwall2.nodes", group)
|
||||
}
|
||||
|
||||
if (default_group) {
|
||||
cbi_t_switch("passwall2.nodes", default_group)
|
||||
}
|
||||
|
||||
get_now_use_node();
|
||||
}
|
||||
document.getElementById("div_node_count").innerHTML = "<div style='margin-top:5px'>" + str + "</div>";
|
||||
}
|
||||
|
||||
//UI渲染完成后再自动Ping
|
||||
);
|
||||
|
||||
window.onload = function () {
|
||||
setTimeout(function () {
|
||||
pingAllNodes();
|
||||
}, 800);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
//]]>
|
||||
|
||||
@@ -1836,3 +1836,9 @@ msgstr "如留空,则使用随机版本。"
|
||||
|
||||
msgid "The configured type also applies to the core specified when manually importing nodes."
|
||||
msgstr "配置的类型同样适用于手动导入节点时所指定的核心程序。"
|
||||
|
||||
msgid "Group Name"
|
||||
msgstr "分组名"
|
||||
|
||||
msgid "Using..."
|
||||
msgstr "使用中。"
|
||||
|
||||
@@ -35,13 +35,13 @@ EOF
|
||||
|
||||
chmod +x /usr/share/passwall2/*.sh
|
||||
|
||||
[ -e "/etc/config/passwall2_show" ] && rm -rf /etc/config/passwall2_show
|
||||
|
||||
[ "$(uci -q get passwall2.@global_xray[0].sniffing)" == "1" ] && [ "$(uci -q get passwall2.@global_xray[0].route_only)" != "1" ] && uci -q set passwall2.@global_xray[0].sniffing_override_dest=1
|
||||
uci -q delete passwall2.@global_xray[0].sniffing
|
||||
uci -q delete passwall2.@global_xray[0].route_only
|
||||
uci -q commit passwall2
|
||||
|
||||
sed -i "s#add_from#group#g" /etc/config/passwall2 2>/dev/null
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
rm -rf /tmp/luci-modulecache/
|
||||
killall -HUP rpcd 2>/dev/null
|
||||
|
||||
@@ -358,7 +358,7 @@ load_acl() {
|
||||
ipset -! create $ipset_white6 nethash family inet6 maxelem 1048576
|
||||
|
||||
#分流规则的IP列表(使用分流节点时导入)
|
||||
gen_shunt_list ${node} shunt_list4 shunt_list6 ${write_ipset_direct} ${ipset_white} ${ipset_white6}
|
||||
gen_shunt_list "${node}" shunt_list4 shunt_list6 ${write_ipset_direct} ${ipset_white} ${ipset_white6}
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -671,7 +671,7 @@ filter_direct_node_list() {
|
||||
}
|
||||
|
||||
add_firewall_rule() {
|
||||
echolog "开始加载防火墙规则..."
|
||||
echolog "开始加载 iptables 防火墙规则..."
|
||||
ipset -! create $IPSET_LOCAL nethash maxelem 1048576
|
||||
ipset -! create $IPSET_LAN nethash maxelem 1048576
|
||||
ipset -! create $IPSET_VPS nethash maxelem 1048576
|
||||
@@ -735,7 +735,7 @@ add_firewall_rule() {
|
||||
ipset -! create $ipset_global_white6 nethash family inet6 maxelem 1048576 timeout 259200
|
||||
|
||||
#分流规则的IP列表(使用分流节点时导入)
|
||||
gen_shunt_list ${NODE} SHUNT_LIST4 SHUNT_LIST6 ${WRITE_IPSET_DIRECT} ${ipset_global_white} ${ipset_global_white6}
|
||||
gen_shunt_list "${NODE}" SHUNT_LIST4 SHUNT_LIST6 ${WRITE_IPSET_DIRECT} ${ipset_global_white} ${ipset_global_white6}
|
||||
|
||||
# 过滤所有节点IP
|
||||
filter_vpsip > /dev/null 2>&1 &
|
||||
|
||||
@@ -382,7 +382,7 @@ load_acl() {
|
||||
gen_nftset $nftset_white6 ipv6_addr 3d 3d
|
||||
|
||||
#分流规则的IP列表(使用分流节点时导入)
|
||||
gen_shunt_list ${node} shunt_list4 shunt_list6 ${write_ipset_direct} ${nftset_white} ${nftset_white6}
|
||||
gen_shunt_list "${node}" shunt_list4 shunt_list6 ${write_ipset_direct} ${nftset_white} ${nftset_white6}
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -701,7 +701,7 @@ filter_direct_node_list() {
|
||||
}
|
||||
|
||||
add_firewall_rule() {
|
||||
echolog "开始加载防火墙规则..."
|
||||
echolog "开始加载 nftables 防火墙规则..."
|
||||
gen_nft_tables
|
||||
gen_nftset $NFTSET_LOCAL ipv4_addr 0 "-1"
|
||||
gen_nftset $NFTSET_LAN ipv4_addr 0 "-1" $(gen_lanlist)
|
||||
@@ -749,7 +749,7 @@ add_firewall_rule() {
|
||||
gen_nftset $nftset_global_white6 ipv6_addr 0 0
|
||||
|
||||
#分流规则的IP列表(使用分流节点时导入)
|
||||
gen_shunt_list ${NODE} SHUNT_LIST4 SHUNT_LIST6 ${WRITE_IPSET_DIRECT} ${nftset_global_white} ${nftset_global_white6}
|
||||
gen_shunt_list "${NODE}" SHUNT_LIST4 SHUNT_LIST6 ${WRITE_IPSET_DIRECT} ${nftset_global_white} ${nftset_global_white6}
|
||||
|
||||
# 过滤所有节点IP
|
||||
filter_vpsip > /dev/null 2>&1 &
|
||||
|
||||
@@ -444,12 +444,12 @@ local function get_subscribe_info(cfgid, value)
|
||||
end
|
||||
|
||||
-- 处理数据
|
||||
local function processData(szType, content, add_mode, add_from)
|
||||
--log(content, add_mode, add_from)
|
||||
local function processData(szType, content, add_mode, group)
|
||||
--log(content, add_mode, group)
|
||||
local result = {
|
||||
timeout = 60,
|
||||
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)
|
||||
if szType == 'ssr' then
|
||||
@@ -1544,14 +1544,14 @@ local function curl(url, file, ua, mode)
|
||||
return tonumber(result)
|
||||
end
|
||||
|
||||
local function truncate_nodes(add_from)
|
||||
local function truncate_nodes(group)
|
||||
for _, config in pairs(CONFIG) do
|
||||
if config.currentNodes and #config.currentNodes > 0 then
|
||||
local newNodes = {}
|
||||
local removeNodesSet = {}
|
||||
for k, v in pairs(config.currentNodes) do
|
||||
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
|
||||
end
|
||||
end
|
||||
@@ -1566,7 +1566,7 @@ local function truncate_nodes(add_from)
|
||||
end
|
||||
else
|
||||
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
|
||||
config.delete(config)
|
||||
elseif config.set then
|
||||
@@ -1578,13 +1578,13 @@ local function truncate_nodes(add_from)
|
||||
end
|
||||
uci:foreach(appname, "nodes", function(node)
|
||||
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'])
|
||||
end
|
||||
end
|
||||
end)
|
||||
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")
|
||||
end
|
||||
end)
|
||||
@@ -1725,7 +1725,7 @@ local function update_node(manual)
|
||||
if manual == 0 and next(group) then
|
||||
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'])
|
||||
end
|
||||
end)
|
||||
@@ -1802,7 +1802,7 @@ local function update_node(manual)
|
||||
luci.sys.call("/etc/init.d/" .. appname .. " restart > /dev/null 2>&1 &")
|
||||
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
|
||||
local nodes, szType
|
||||
local node_list = {}
|
||||
@@ -1838,17 +1838,17 @@ local function parse_link(raw, add_mode, add_from, cfgid)
|
||||
xpcall(function ()
|
||||
local result
|
||||
if szType == 'ssd' then
|
||||
result = processData(szType, v, add_mode, add_from)
|
||||
result = processData(szType, v, add_mode, group)
|
||||
elseif not szType then
|
||||
local node = api.trim(v)
|
||||
local dat = split(node, "://")
|
||||
if dat and dat[1] and dat[2] then
|
||||
if dat[1] == 'vmess' or dat[1] == 'ssr' then
|
||||
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
|
||||
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
|
||||
else
|
||||
@@ -1879,14 +1879,14 @@ local function parse_link(raw, add_mode, add_from, cfgid)
|
||||
end
|
||||
if #node_list > 0 then
|
||||
nodeResult[#nodeResult + 1] = {
|
||||
remark = add_from,
|
||||
remark = group,
|
||||
list = node_list
|
||||
}
|
||||
end
|
||||
log('成功解析【' .. add_from .. '】节点数量: ' .. #node_list)
|
||||
log('成功解析【' .. group .. '】节点数量: ' .. #node_list)
|
||||
else
|
||||
if add_mode == "2" then
|
||||
log('获取到的【' .. add_from .. '】订阅内容为空,可能是订阅地址无效,或是网络问题,请诊断!')
|
||||
log('获取到的【' .. group .. '】订阅内容为空,可能是订阅地址无效,或是网络问题,请诊断!')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user