luci-app-passwall2: sync upstream

This commit is contained in:
actions 2024-01-29 03:30:11 +08:00
parent 29a9a84edc
commit e5ca4ee15d
15 changed files with 207 additions and 212 deletions

View File

@ -5,7 +5,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-passwall2 PKG_NAME:=luci-app-passwall2
PKG_VERSION:=1.24-1 PKG_VERSION:=1.25-1
PKG_RELEASE:= PKG_RELEASE:=
PKG_CONFIG_DEPENDS:= \ PKG_CONFIG_DEPENDS:= \

View File

@ -226,16 +226,15 @@ function ping_node()
local index = luci.http.formvalue("index") local index = luci.http.formvalue("index")
local address = luci.http.formvalue("address") local address = luci.http.formvalue("address")
local port = luci.http.formvalue("port") local port = luci.http.formvalue("port")
local type = luci.http.formvalue("type") or "icmp"
local e = {} local e = {}
e.index = index e.index = index
local nodes_ping = ucic:get(appname, "@global_other[0]", "nodes_ping") or "" if type == "tcping" and luci.sys.exec("echo -n $(command -v tcping)") ~= "" then
if nodes_ping:find("tcping") and luci.sys.exec("echo -n $(command -v tcping)") ~= "" then
if api.is_ipv6(address) then if api.is_ipv6(address) then
address = api.get_ipv6_only(address) address = api.get_ipv6_only(address)
end end
e.ping = luci.sys.exec(string.format("echo -n $(tcping -q -c 1 -i 1 -t 2 -p %s %s 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null", port, address)) e.ping = luci.sys.exec(string.format("echo -n $(tcping -q -c 1 -i 1 -t 2 -p %s %s 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null", port, address))
end else
if e.ping == nil or tonumber(e.ping) == 0 then
e.ping = luci.sys.exec("echo -n $(ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null" % address) e.ping = luci.sys.exec("echo -n $(ping -c 1 -W 1 %q 2>&1 | grep -o 'time=[0-9]*' | awk -F '=' '{print $2}') 2>/dev/null" % address)
end end
luci.http.prepare_content("application/json") luci.http.prepare_content("application/json")

View File

@ -2,6 +2,10 @@ local api = require "luci.passwall2.api"
local appname = api.appname local appname = api.appname
local sys = api.sys local sys = api.sys
local port_validate = function(self, value, t)
return value:gsub("-", ":")
end
m = Map(appname) m = Map(appname)
api.set_apply_on_parse(m) api.set_apply_on_parse(m)
@ -157,6 +161,7 @@ o.default = "default"
o:value("disable", translate("No patterns are used")) o:value("disable", translate("No patterns are used"))
o:value("default", translate("Default")) o:value("default", translate("Default"))
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
o.validate = port_validate
---- UDP No Redir Ports ---- UDP No Redir Ports
o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"), o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"),
@ -167,6 +172,7 @@ o.default = "default"
o:value("disable", translate("No patterns are used")) o:value("disable", translate("No patterns are used"))
o:value("default", translate("Default")) o:value("default", translate("Default"))
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
o.validate = port_validate
---- TCP Redir Ports ---- TCP Redir Ports
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports")) o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
@ -175,12 +181,14 @@ o:value("default", translate("Default"))
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
o:value("22,25,53,143,465,587,853,993,995,80,443", translate("Common Use")) o:value("22,25,53,143,465,587,853,993,995,80,443", translate("Common Use"))
o:value("80,443", "80,443") o:value("80,443", "80,443")
o.validate = port_validate
---- UDP Redir Ports ---- UDP Redir Ports
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports")) o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"))
o.default = "default" o.default = "default"
o:value("default", translate("Default")) o:value("default", translate("Default"))
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
o.validate = port_validate
node = s:option(ListValue, "node", "<a style='color: red'>" .. translate("Node") .. "</a>") node = s:option(ListValue, "node", "<a style='color: red'>" .. translate("Node") .. "</a>")
node.default = "default" node.default = "default"

View File

@ -50,7 +50,7 @@ o:depends("balancing_enable", true)
o = s:option(ListValue, "health_check_type", translate("Health Check Type")) o = s:option(ListValue, "health_check_type", translate("Health Check Type"))
o.default = "passwall_logic" o.default = "passwall_logic"
o:value("tcp", "TCP") o:value("tcp", "TCP")
o:value("passwall_logic", translate("Availability test") .. string.format("(passwall %s)", translate("Inner implement"))) o:value("passwall_logic", translate("URL Test") .. string.format("(passwall %s)", translate("Inner implement")))
o:depends("balancing_enable", true) o:depends("balancing_enable", true)
---- Health Check Inter ---- Health Check Inter
@ -61,7 +61,7 @@ o:depends("balancing_enable", true)
o = s:option(DummyValue, "health_check_tips", " ") o = s:option(DummyValue, "health_check_tips", " ")
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
return string.format('<span style="color: red">%s</span>', translate("When the availability test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid.")) return string.format('<span style="color: red">%s</span>', translate("When the URL test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid."))
end end
o:depends("health_check_type", "passwall_logic") o:depends("health_check_type", "passwall_logic")

View File

@ -10,15 +10,19 @@ api.set_apply_on_parse(m)
s = m:section(TypedSection, "global_other") s = m:section(TypedSection, "global_other")
s.anonymous = true s.anonymous = true
o = s:option(MultiValue, "nodes_ping", " ") o = s:option(ListValue, "auto_detection_time", translate("Automatic detection delay"))
o:value("auto_ping", translate("Auto Ping"), translate("This will automatically ping the node for latency")) o:value("0", translate("Close"))
o:value("tcping", translate("Tcping"), translate("This will use tcping replace ping detection of node")) o:value("icmp", "Ping")
o:value("info", translate("Show server address and port"), translate("Show server address and port")) o:value("tcping", "TCP Ping")
o = s:option(Flag, "show_node_info", translate("Show server address and port"))
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 nodes_ping = m:get("@global_other[0]", "nodes_ping") or "" 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 ]]-- -- [[ Node List ]]--
s = m:section(TypedSection, "nodes") s = m:section(TypedSection, "nodes")
@ -103,7 +107,7 @@ o.cfgvalue = function(t, n)
local port = m:get(n, "port") or "" local port = m:get(n, "port") or ""
str = str .. translate(type) .. "" .. remarks str = str .. translate(type) .. "" .. remarks
if address ~= "" and port ~= "" then if address ~= "" and port ~= "" then
if nodes_ping:find("info") then if show_node_info == "1" then
if datatypes.ip6addr(address) then if datatypes.ip6addr(address) then
str = str .. string.format("[%s]:%s", address, port) str = str .. string.format("[%s]:%s", address, port)
else else
@ -117,23 +121,38 @@ o.cfgvalue = function(t, n)
end end
---- Ping ---- Ping
o = s:option(DummyValue, "ping") o = s:option(DummyValue, "ping", "Ping")
o.width = "8%" o.width = "8%"
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
local result = "---" local result = "---"
if not nodes_ping:find("auto_ping") then if auto_detection_time ~= "icmp" then
result = string.format('<span class="ping"><a href="javascript:void(0)" onclick="javascript:ping_node(\'%s\',this)">Ping</a></span>', n) 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 else
result = string.format('<span class="ping_value" cbiid="%s">---</span>', n) result = string.format('<span class="ping_value" cbiid="%s">---</span>', n)
end end
return result return result
end end
o = s:option(DummyValue, "_url_test") ---- TCP Ping
o = s:option(DummyValue, "tcping", "TCPing")
o.width = "8%"
o.rawhtml = true o.rawhtml = true
o.cfgvalue = function(t, n) o.cfgvalue = function(t, n)
return string.format('<input type="button" class="cbi-button" value="%s" onclick="javascript:urltest_node(\'%s\',this)"', translate("Availability test"), 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 end
m:append(Template(appname .. "/node_list/node_list")) m:append(Template(appname .. "/node_list/node_list"))

View File

@ -7,6 +7,10 @@ local has_xray = api.finded_com("xray")
local has_fw3 = api.is_finded("fw3") local has_fw3 = api.is_finded("fw3")
local has_fw4 = api.is_finded("fw4") local has_fw4 = api.is_finded("fw4")
local port_validate = function(self, value, t)
return value:gsub("-", ":")
end
m = Map(appname) m = Map(appname)
api.set_apply_on_parse(m) api.set_apply_on_parse(m)
@ -63,6 +67,7 @@ o = s:option(Value, "tcp_no_redir_ports", translate("TCP No Redir Ports"))
o.default = "disable" o.default = "disable"
o:value("disable", translate("No patterns are used")) o:value("disable", translate("No patterns are used"))
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
o.validate = port_validate
---- UDP No Redir Ports ---- UDP No Redir Ports
o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"), o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"),
@ -72,6 +77,7 @@ o = s:option(Value, "udp_no_redir_ports", translate("UDP No Redir Ports"),
o.default = "disable" o.default = "disable"
o:value("disable", translate("No patterns are used")) o:value("disable", translate("No patterns are used"))
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
o.validate = port_validate
---- TCP Redir Ports ---- TCP Redir Ports
o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports")) o = s:option(Value, "tcp_redir_ports", translate("TCP Redir Ports"))
@ -79,11 +85,13 @@ o.default = "22,25,53,143,465,587,853,993,995,80,443"
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
o:value("22,25,53,143,465,587,853,993,995,80,443", translate("Common Use")) o:value("22,25,53,143,465,587,853,993,995,80,443", translate("Common Use"))
o:value("80,443", translate("Only Web")) o:value("80,443", translate("Only Web"))
o.validate = port_validate
---- UDP Redir Ports ---- UDP Redir Ports
o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports")) o = s:option(Value, "udp_redir_ports", translate("UDP Redir Ports"))
o.default = "1:65535" o.default = "1:65535"
o:value("1:65535", translate("All")) o:value("1:65535", translate("All"))
o.validate = port_validate
---- Use nftables ---- Use nftables
o = s:option(ListValue, "use_nft", translate("Firewall tools")) o = s:option(ListValue, "use_nft", translate("Firewall tools"))

View File

@ -41,7 +41,7 @@ o:value("trojan", translate("Trojan"))
o:value("wireguard", translate("WireGuard")) o:value("wireguard", translate("WireGuard"))
o:value("_balancing", translate("Balancing")) o:value("_balancing", translate("Balancing"))
o:value("_shunt", translate("Shunt")) o:value("_shunt", translate("Shunt"))
o:value("_iface", translate("Custom Interface") .. " (Only Support Xray)") o:value("_iface", translate("Custom Interface"))
o = s:option(Value, option_name("iface"), translate("Interface")) o = s:option(Value, option_name("iface"), translate("Interface"))
o.default = "eth1" o.default = "eth1"

View File

@ -58,7 +58,7 @@ if singbox_tags:find("with_quic") then
o:value("hysteria2", "Hysteria2") o:value("hysteria2", "Hysteria2")
end end
o:value("_shunt", translate("Shunt")) o:value("_shunt", translate("Shunt"))
o:value("_iface", translate("Custom Interface") .. " (Only Support Xray)") o:value("_iface", translate("Custom Interface"))
o = s:option(Value, option_name("iface"), translate("Interface")) o = s:option(Value, option_name("iface"), translate("Interface"))
o.default = "eth1" o.default = "eth1"

View File

@ -345,7 +345,7 @@ o = s:option(ListValue, option_name("outbound_node"), translate("outbound node")
o:value("nil", translate("Close")) o:value("nil", translate("Close"))
o:value("_socks", translate("Custom Socks")) o:value("_socks", translate("Custom Socks"))
o:value("_http", translate("Custom HTTP")) o:value("_http", translate("Custom HTTP"))
o:value("_iface", translate("Custom Interface") .. " (Only Support Xray)") o:value("_iface", translate("Custom Interface"))
for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end for k, v in pairs(nodes_table) do o:value(v.id, v.remarks) end
o.default = "nil" o.default = "nil"

View File

@ -292,7 +292,7 @@ function get_domain_from_url(url)
end end
function get_valid_nodes() function get_valid_nodes()
local nodes_ping = uci_get_type("global_other", "nodes_ping") or "" local show_node_info = uci_get_type("global_other", "show_node_info") or "0"
local nodes = {} local nodes = {}
uci:foreach(appname, "nodes", function(e) uci:foreach(appname, "nodes", function(e)
e.id = e[".name"] e.id = e[".name"]
@ -319,7 +319,7 @@ function get_valid_nodes()
end end
if is_ipv6(address) then address = get_ipv6_full(address) end if is_ipv6(address) then address = get_ipv6_full(address) end
e["remark"] = "%s[%s]" % {type, e.remarks} e["remark"] = "%s[%s]" % {type, e.remarks}
if nodes_ping:find("info") then if show_node_info == "1" then
e["remark"] = "%s[%s] %s:%s" % {type, e.remarks, address, e.port} e["remark"] = "%s[%s] %s:%s" % {type, e.remarks, address, e.port}
end end
e.node_type = "normal" e.node_type = "normal"

View File

@ -103,6 +103,8 @@ local api = require "luci.passwall2.api"
<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" 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-reset" type="button" value="<%:Reset%>" onclick="location.href='<%=REQUEST_URI%>'" />
<div id="div_node_count"></div> <div id="div_node_count"></div>
</div> </div>
</div> </div>

View File

@ -162,9 +162,10 @@ local api = require "luci.passwall2.api"
} }
} }
var url = null; var url = null;
if (v_type === "SS") { if (v_type === "SS" || v_type === "SS-Rust" || ((v_type === "sing-box" || v_type === "Xray") && opt.get(dom_prefix + "protocol").value === "shadowsocks")) {
protocol = "ss"
var v_port = opt.get(dom_prefix + "port"); var v_port = opt.get(dom_prefix + "port");
var v_method = opt.get(dom_prefix + "method"); var v_method = opt.get(dom_prefix + "method") || opt.get(dom_prefix + "ss_method");
var v_password = opt.get(dom_prefix + "password"); var v_password = opt.get(dom_prefix + "password");
url = b64encsafe(v_method.value + ":" + v_password.value) + "@" + url = b64encsafe(v_method.value + ":" + v_password.value) + "@" +
@ -172,43 +173,19 @@ local api = require "luci.passwall2.api"
v_port.value + "/?"; v_port.value + "/?";
var params = ""; var params = "";
var v_plugin = opt.get(dom_prefix + "plugin").value; var v_plugin_dom = opt.get(dom_prefix + "plugin");
if (v_plugin && v_plugin != "none") { if (v_plugin_dom) {
if (v_plugin == "simple-obfs" || v_plugin == "obfs-local") { var v_plugin = v_plugin_dom.value;
v_plugin = "obfs-local"; if (v_plugin && v_plugin != "none") {
if (v_plugin == "simple-obfs" || v_plugin == "obfs-local") {
v_plugin = "obfs-local";
}
var v_plugin_opts = opt.get(dom_prefix + "plugin_opts").value;
if (v_plugin_opts && v_plugin_opts != "") {
v_plugin += ";" + v_plugin_opts;
}
params += "&plugin=" + encodeURIComponent(v_plugin);
} }
var v_plugin_opts = opt.get(dom_prefix + "plugin_opts").value;
if (v_plugin_opts && v_plugin_opts != "") {
v_plugin += ";" + v_plugin_opts;
}
params += "&plugin=" + encodeURIComponent(v_plugin);
}
params += "&group="
params += "#" + encodeURIComponent(v_alias.value);
if (params[0] == "&") {
params = params.substring(1);
}
url += params;
} else if (v_type === "SS-Rust") {
var v_port = opt.get(dom_prefix + "port");
var v_method = opt.get(dom_prefix + "method");
var v_password = opt.get(dom_prefix + "password");
url = btoa(v_method.value + ":" + v_password.value) + "@" +
_address + ":" +
v_port.value + "/?";
var params = "";
var v_plugin = opt.get(dom_prefix + "plugin").value;
if (v_plugin && v_plugin != "none") {
if (v_plugin == "simple-obfs" || v_plugin == "obfs-local") {
v_plugin = "obfs-local";
}
var v_plugin_opts = opt.get(dom_prefix + "plugin_opts").value;
if (v_plugin_opts && v_plugin_opts != "") {
v_plugin += ";" + v_plugin_opts;
}
params += "&plugin=" + encodeURIComponent(v_plugin);
} }
params += "&group=" params += "&group="
params += "#" + encodeURIComponent(v_alias.value); params += "#" + encodeURIComponent(v_alias.value);
@ -600,11 +577,22 @@ local api = require "luci.passwall2.api"
method = userInfo.substr(0, userInfoSplitIndex); method = userInfo.substr(0, userInfoSplitIndex);
password = userInfo.substr(userInfoSplitIndex + 1); password = userInfo.substr(userInfoSplitIndex + 1);
} }
if (["2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"].includes(method)) { if (has_singbox) {
opt.set('type', "SS-Rust"); dom_prefix = "singbox_"
dom_prefix = "ssrust_" opt.set('type', "sing-box");
opt.set(dom_prefix + 'protocol', "shadowsocks");
} else if (has_xray) {
dom_prefix = "xray_"
opt.set('type', "Xray");
opt.set(dom_prefix + 'protocol', "shadowsocks");
} else { } else {
opt.set('type', "SS"); if (["2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm", "2022-blake3-chacha20-poly1305"].includes(method)) {
dom_prefix = "ssrust_"
opt.set('type', "SS-Rust");
} else {
dom_prefix = "ss_"
opt.set('type', "SS");
}
} }
opt.set(dom_prefix + 'address', server); opt.set(dom_prefix + 'address', server);
opt.set(dom_prefix + 'port', port); opt.set(dom_prefix + 'port', port);
@ -620,9 +608,22 @@ local api = require "luci.passwall2.api"
} else { } else {
var sstr = b64decsafe(url0); var sstr = b64decsafe(url0);
var team = sstr.split('@'); var team = sstr.split('@');
opt.set('type', "SS");
var part1 = team[0].split(':'); var part1 = team[0].split(':');
var part2 = team[1].split(':'); var part2 = team[1].split(':');
if (has_singbox) {
dom_prefix = "singbox_"
opt.set('type', "sing-box");
opt.set(dom_prefix + 'protocol', "shadowsocks");
} else if (has_xray) {
dom_prefix = "xray_"
opt.set('type', "Xray");
opt.set(dom_prefix + 'protocol', "shadowsocks");
} else {
dom_prefix = "ss_"
opt.set('type', "SS");
}
opt.set(dom_prefix + 'address', part2[0]); opt.set(dom_prefix + 'address', part2[0]);
opt.set(dom_prefix + 'port', part2[1]); opt.set(dom_prefix + 'port', part2[1]);
opt.set(dom_prefix + 'password', part1[1]); opt.set(dom_prefix + 'password', part1[1]);
@ -653,17 +654,17 @@ local api = require "luci.passwall2.api"
} }
} }
if (has_singbox) { if (has_singbox) {
opt.set('type', "sing-box");
dom_prefix = "singbox_" dom_prefix = "singbox_"
opt.set('type', "sing-box");
} else if (has_xray) { } else if (has_xray) {
opt.set('type', "Xray");
dom_prefix = "xray_" dom_prefix = "xray_"
opt.set('type', "Xray");
} }
opt.set(dom_prefix + 'protocol', "trojan"); opt.set(dom_prefix + 'protocol', "trojan");
opt.set(dom_prefix + 'address', m.hostname); opt.set(dom_prefix + 'address', m.hostname);
opt.set(dom_prefix + 'port', m.port || "443"); opt.set(dom_prefix + 'port', m.port || "443");
opt.set(dom_prefix + 'password', decodeURIComponent(password)); opt.set(dom_prefix + 'password', decodeURIComponent(password));
opt.set(dom_prefix + 'tls', true); opt.set(dom_prefix + 'tls', queryParam.tls === "1");
opt.set(dom_prefix + 'tls_serverName', queryParam.peer || queryParam.sni || ''); opt.set(dom_prefix + 'tls_serverName', queryParam.peer || queryParam.sni || '');
opt.set(dom_prefix + 'tls_allowInsecure', queryParam.allowinsecure === '1'); opt.set(dom_prefix + 'tls_allowInsecure', queryParam.allowinsecure === '1');
opt.set(dom_prefix + 'mux', queryParam.mux === '1'); opt.set(dom_prefix + 'mux', queryParam.mux === '1');
@ -675,12 +676,12 @@ local api = require "luci.passwall2.api"
var sstr = b64DecodeUnicode(ssu[1]); var sstr = b64DecodeUnicode(ssu[1]);
var ploc = sstr.indexOf("/?"); var ploc = sstr.indexOf("/?");
if (has_singbox) { if (has_singbox) {
opt.set('type', "sing-box");
dom_prefix = "singbox_" dom_prefix = "singbox_"
opt.set('type', "sing-box");
} }
if (has_xray) { if (has_xray) {
opt.set('type', "Xray");
dom_prefix = "xray_" dom_prefix = "xray_"
opt.set('type', "Xray");
} }
opt.set(dom_prefix + 'protocol', "vmess"); opt.set(dom_prefix + 'protocol', "vmess");
var url0, param = ""; var url0, param = "";
@ -728,12 +729,12 @@ local api = require "luci.passwall2.api"
} }
if (ssu[0] === "vless") { if (ssu[0] === "vless") {
if (has_singbox) { if (has_singbox) {
opt.set('type', "sing-box");
dom_prefix = "singbox_" dom_prefix = "singbox_"
opt.set('type', "sing-box");
} }
if (has_xray) { if (has_xray) {
opt.set('type', "Xray");
dom_prefix = "xray_" dom_prefix = "xray_"
opt.set('type', "Xray");
} }
opt.set(dom_prefix + 'protocol', "vless"); opt.set(dom_prefix + 'protocol', "vless");
var m = parseNodeUrl(ssrurl); var m = parseNodeUrl(ssrurl);
@ -897,8 +898,8 @@ local api = require "luci.passwall2.api"
} }
} }
if (has_singbox) { if (has_singbox) {
opt.set('type', "sing-box");
dom_prefix = "singbox_" dom_prefix = "singbox_"
opt.set('type', "sing-box");
opt.set(dom_prefix + 'protocol', "hysteria2"); opt.set(dom_prefix + 'protocol', "hysteria2");
opt.set(dom_prefix + 'hysteria2_auth_password', decodeURIComponent(password)); opt.set(dom_prefix + 'hysteria2_auth_password', decodeURIComponent(password));
if (queryParam["obfs-password"]) { if (queryParam["obfs-password"]) {

View File

@ -53,6 +53,7 @@ table td, .table .td {
<script type="text/javascript"> <script type="text/javascript">
//<![CDATA[ //<![CDATA[
let auto_detection_time = "<%=api.uci_get_type("global_other", "auto_detection_time", "0")%>"
var node_list = {}; var node_list = {};
var node_count = 0; var node_count = 0;
@ -246,8 +247,8 @@ table td, .table .td {
function urltest_node(cbi_id, dom) { function urltest_node(cbi_id, dom) {
if (cbi_id != null) { if (cbi_id != null) {
dom.disabled = true; dom.onclick = null
dom.value = "<%:Check...%>"; dom.innerText = "<%:Check...%>";
XHR.get('<%=api.url("urltest_node")%>', { XHR.get('<%=api.url("urltest_node")%>', {
id: cbi_id id: cbi_id
}, },
@ -258,6 +259,7 @@ table td, .table .td {
} else { } else {
var color = "red"; var color = "red";
var use_time = result.use_time; var use_time = result.use_time;
use_time = parseInt(use_time) + 1;
if (use_time < 1000) { if (use_time < 1000) {
color = "green"; color = "green";
} else if (use_time < 2000) { } else if (use_time < 2000) {
@ -265,20 +267,25 @@ table td, .table .td {
} else { } else {
color = "red"; color = "red";
} }
dom.outerHTML = "<font style='color:" + color + "'>" + result.use_time + " ms" + "</font>"; dom.outerHTML = "<font style='color:" + color + "'>" + use_time + " ms" + "</font>";
} }
} else {
dom.outerHTML = "<font style='color:red'><%:Error%></font>";
} }
} }
); );
} }
} }
function ping_node(cbi_id, dom) { function ping_node(cbi_id, dom, type) {
var full = get_address_full(cbi_id); var full = get_address_full(cbi_id);
if (full != null) { if (full != null) {
dom.onclick = null
dom.innerText = "<%:Check...%>";
XHR.get('<%=api.url("ping_node")%>', { XHR.get('<%=api.url("ping_node")%>', {
address: full.address, address: full.address,
port: full.port port: full.port,
type: type
}, },
function(x, result) { function(x, result) {
if(x && x.status == 200) { if(x && x.status == 200) {
@ -299,131 +306,87 @@ table td, .table .td {
} }
} }
/* 自动Ping */
var nodes = [];
const ping_value = document.getElementsByClassName('ping_value');
for (var i = 0; i < ping_value.length; i++) {
var cbi_id = ping_value[i].getAttribute("cbiid");
var full = get_address_full(cbi_id);
if (full != null) {
var flag = false;
//当有多个相同地址和端口时合在一起
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;
flag = true;
break;
}
}
if (flag)
continue;
nodes.push({
indexs: i + "",
address: full.address,
port: full.port
});
}
}
get_now_use_node(); get_now_use_node();
const _xhr = (index) => { /* 自动Ping */
return new Promise((res) => { if (auto_detection_time == "icmp" || auto_detection_time == "tcping") {
const dom = nodes[index]; var nodes = [];
if (!dom) res() const ping_value = document.getElementsByClassName(auto_detection_time == "tcping" ? 'tcping_value' : 'ping_value');
ajax.post('<%=api.url("ping_node")%>', { for (var i = 0; i < ping_value.length; i++) {
index: dom.indexs, var cbi_id = ping_value[i].getAttribute("cbiid");
address: dom.address, var full = get_address_full(cbi_id);
port: dom.port if (full != null) {
}, var flag = false;
function(x, result) { //当有多个相同地址和端口时合在一起
if (x && x.status == 200) { for (var j = 0; j < nodes.length; j++) {
var strs = dom.indexs.split(","); if (nodes[j].address == full.address && nodes[j].port == full.port) {
for (var i = 0; i < strs.length; i++) { nodes[j].indexs = nodes[j].indexs + "," + i;
if (result.ping == null || result.ping.trim() == "") { flag = true;
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>"; break;
} else { }
var ping = parseInt(result.ping); }
if (ping < 100) if (flag)
ping_value[strs[i]].innerHTML = "<font style='color:green'>" + result.ping + " ms" + "</font>"; continue;
else if (ping < 200) nodes.push({
ping_value[strs[i]].innerHTML = "<font style='color:#fb9a05'>" + result.ping + " ms" + "</font>"; indexs: i + "",
else if (ping >= 200) address: full.address,
ping_value[strs[i]].innerHTML = "<font style='color:red'>" + result.ping + " ms" + "</font>"; port: full.port
});
}
}
const _xhr = (index) => {
return new Promise((res) => {
const dom = nodes[index];
if (!dom) res()
ajax.post('<%=api.url("ping_node")%>', {
index: dom.indexs,
address: dom.address,
port: dom.port,
type: auto_detection_time
},
function(x, result) {
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();
res(); },
}, 5000,
5000, function(x) {
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>";
}
res();
}
);
})
}
let task = -1;
const thread = () => {
task = task + 1
if (nodes[task]) {
_xhr(task).then(thread);
}
}
for (let i = 0; i < 20; i++) {
thread()
}
/* 递归单请求方法
var index = 0;
function auto_ping() {
if (index >= nodes.length) {
return;
}
var indexs = nodes[index].indexs;
var address = nodes[index].address;
var port = nodes[index].port;
ajax.post('<%=api.url("ping_node")%>', {
index: indexs,
address: address,
port: port
},
function(x, result) {
if (x && x.status == 200) {
var strs = 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>"; 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();
} }
} );
index++; })
return auto_ping(); }
},
function(x) { let task = -1;
var strs = indexs.split(","); const thread = () => {
for (var i = 0; i < strs.length; i++) { task = task + 1
ping_value[strs[i]].innerHTML = "<font style='color:red'><%:Timeout%></font>"; if (nodes[task]) {
} _xhr(task).then(thread);
index++; }
return auto_ping(); }
}, for (let i = 0; i < 20; i++) {
); thread()
}
} }
auto_ping();
*/
var edit_btn = document.getElementById("cbi-passwall2-nodes").getElementsByClassName("cbi-button cbi-button-edit"); var edit_btn = document.getElementById("cbi-passwall2-nodes").getElementsByClassName("cbi-button cbi-button-edit");
for (var i = 0; i < edit_btn.length; i++) { for (var i = 0; i < edit_btn.length; i++) {

View File

@ -502,23 +502,17 @@ msgstr "加密"
msgid "Latency" msgid "Latency"
msgstr "延迟" msgstr "延迟"
msgid "Show Add Mode" msgid "Automatic detection delay"
msgstr "显示添加方式" msgstr "自动检测延迟"
msgid "Show Group"
msgstr "显示组"
msgid "Group"
msgstr "组"
msgid "Auto Ping"
msgstr "自动Ping"
msgid "Show server address and port" msgid "Show server address and port"
msgstr "显示服务器地址和端口" msgstr "显示服务器地址和端口"
msgid "Availability test" msgid "URL Test"
msgstr "可用性测试" msgstr "URL 测试"
msgid "Test"
msgstr "测试"
msgid "Node num" msgid "Node num"
msgstr "节点数量" msgstr "节点数量"
@ -709,8 +703,8 @@ msgstr "内置实现"
msgid "Health Check Inter" msgid "Health Check Inter"
msgstr "健康检查节点间隔时间" msgstr "健康检查节点间隔时间"
msgid "When the availability test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid." msgid "When the URL test is used, the load balancing node will be converted into a Socks node. when node list set customizing, must be a Socks node, otherwise the health check will be invalid."
msgstr "当使用可用性测试时负载均衡节点将转换成Socks节点。下面的节点列表自定义时必须为Socks节点否则健康检查将无效。" msgstr "当使用URL测试时负载均衡节点将转换成Socks节点。下面的节点列表自定义时必须为Socks节点否则健康检查将无效。"
msgid "Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group." msgid "Add a node, Export Of Multi WAN Only support Multi Wan. Load specific gravity range 1-256. Multiple primary servers can be load balanced, standby will only be enabled when the primary server is offline! Multiple groups can be set, Haproxy port same one for each group."
msgstr "添加节点指定出口功能是为多WAN用户准备的。负载比重范围1-256。多个主服务器可以负载均衡备用只有在主服务器离线时才会启用可以设置多个组负载均衡端口相同则为一组。" msgstr "添加节点指定出口功能是为多WAN用户准备的。负载比重范围1-256。多个主服务器可以负载均衡备用只有在主服务器离线时才会启用可以设置多个组负载均衡端口相同则为一组。"

View File

@ -39,7 +39,8 @@ config global_xray
option route_only '0' option route_only '0'
config global_other config global_other
option nodes_ping 'auto_ping tcping' option auto_detection_time 'tcping'
option show_node_info '0'
config global_rules config global_rules
option auto_update '0' option auto_update '0'