🦄 Sync 2026-07-26 23:49:39

This commit is contained in:
github-actions[bot]
2026-07-26 23:49:39 +08:00
parent 2450ea7cca
commit bf03fd23d8
20 changed files with 482 additions and 145 deletions
@@ -259,18 +259,48 @@ end
function get_redir_log()
local name = http.formvalue("name")
local proto = http.formvalue("proto")
local proto = http.formvalue("proto"):upper()
local path = "/tmp/etc/passwall/acl/" .. name
proto = proto:upper()
if proto == "UDP" and (uci:get(appname, "@global[0]", "udp_node") or "nil") == "tcp" and not fs.access(path .. "/" .. proto .. ".log") then
proto = "TCP"
local function alert(msg)
http.write(string.format("<script>alert('%s');window.close();</script>", i18n.translate(msg)))
end
if name == "default" then
if proto == "UDP" and (uci:get(appname, "@global[0]", "udp_node") or "nil") == "tcp" and not fs.access(path .. "/" .. proto .. ".log") then
proto = "TCP"
end
else
local global_tcp = uci:get(appname, "@global[0]", "tcp_node") or "nil"
local global_udp = uci:get(appname, "@global[0]", "udp_node") or "nil"
local acl_tcp = uci:get(appname, name, "tcp_node") or "nil"
local acl_udp = uci:get(appname, name, "udp_node") or "nil"
local global_enabled = uci:get(appname, "@global[0]", "enabled") == "1"
if proto == "TCP" and acl_tcp == global_tcp and global_enabled then
path = "/tmp/etc/passwall/acl/default"
if uci:get(appname, "@global[0]", "log_tcp") ~= "1" then
alert("The access control node is the same as the global node. Please enable global logging.")
return
end
end
if proto == "UDP" and acl_udp == global_udp and global_enabled then
path = "/tmp/etc/passwall/acl/default"
if uci:get(appname, "@global[0]", "log_udp") ~= "1" then
alert("The access control node is the same as the global node. Please enable global logging.")
return
end
end
if proto == "UDP" and acl_udp == "tcp" and not fs.access(path .. "/" .. proto .. ".log") then
proto = "TCP"
end
end
if fs.access(path .. "/" .. proto .. ".log") then
local content = luci.sys.exec("tail -n 19999 ".. path .. "/" .. proto .. ".log")
content = content:gsub("\n", "<br />")
http.write(content)
else
http.write(string.format("<script>alert('%s');window.close();</script>", i18n.translate("Not enabled log")))
alert("Not enabled log")
end
end
@@ -289,6 +319,18 @@ end
function get_chinadns_log()
local flag = http.formvalue("flag")
local path = "/tmp/etc/passwall/acl/" .. flag .. "/chinadns_ng.log"
if flag ~= "default" then
local global_tcp = uci:get(appname, "@global[0]", "tcp_node") or "nil"
local acl_tcp = uci:get(appname, flag, "tcp_node") or "nil"
if acl_tcp == global_tcp and uci:get(appname, "@global[0]", "enabled") == "1" then
path = "/tmp/etc/passwall/acl/default/chinadns_ng.log"
if uci:get(appname, "@global[0]", "log_chinadns_ng") ~= "1" then
http.write(string.format("<script>alert('%s');window.close();</script>", i18n.translate("The access control node is the same as the global node. Please enable global logging.")))
return
end
end
end
if fs.access(path) then
local content = luci.sys.exec("tail -n 5000 ".. path)
content = content:gsub("\n", "<br />")
@@ -7,7 +7,8 @@ m = Map(appname)
m.redirect = api.url("acl")
api.set_apply_on_parse(m)
if not arg[1] or not m:get(arg[1]) then
local cfgid = arg[1]
if not cfgid or not m:get(cfgid) then
luci.http.redirect(m.redirect)
end
@@ -69,7 +70,7 @@ local dynamicList_write = function(self, section, value)
end
-- [[ ACLs Settings ]]--
s = m:section(NamedSection, arg[1], translate("ACLs"), translate("ACLs"))
s = m:section(NamedSection, cfgid, translate("ACLs"), translate("ACLs"))
s.addremove = false
s.dynamic = false
@@ -80,9 +81,22 @@ o.rmempty = false
---- Remarks
o = s:option(Value, "remarks", translate("Remarks"))
o.default = arg[1]
o.default = cfgid
o.rmempty = false
---- Log
o = s:option(Flag, "log", translate("Log"))
o.default = 0
o.rmempty = false
o = s:option(ListValue, "loglevel", "Sing-Box/Xray " .. translate("Log Level"))
o.default = "warning"
o:value("debug")
o:value("info")
o:value("warning")
o:value("error")
o:depends("log", "1")
o = s:option(Value, "interface", translate("Source Interface"))
o:value("", translate("All"))
local iface = api.get_network_devices()
@@ -238,8 +252,10 @@ o.template = appname .. "/cbi/nodes_listvalue"
o.group = {"",""}
o.remove = function(self, section)
local v = s.fields["shunt_udp_node"]:formvalue(section)
if not v then
if not v or v == "close" then
return m:del(section, self.option)
else
return m:set(section, self.option, "tcp")
end
end
@@ -373,9 +389,6 @@ o:value("dnsmasq", "Dnsmasq")
o:value("chinadns-ng", translate("ChinaDNS-NG (recommended)"))
o:depends({ _tcp_node_bool = "1" })
o = s:option(DummyValue, "view_chinadns_log", " ")
o.template = appname .. "/acl/view_chinadns_log"
o = s:option(Flag, "filter_proxy_ipv6", translate("Filter Proxy Host IPv6"), translate("Experimental feature."))
o.default = "0"
o:depends({ _tcp_node_bool = "1" })
@@ -603,4 +616,9 @@ for k, v in pairs(nodes_table) do
end
end
local footer = Template(appname .. "/acl/config_footer")
footer.api = api
footer.cfgid = cfgid
m:append(footer)
return api.return_map(m)
@@ -124,8 +124,10 @@ o.group = {"",""}
o:depends("_node_sel_other", "1")
o.remove = function(self, section)
local v = s.fields["shunt_udp_node"]:formvalue(section)
if not v then
if not v or v == "close" then
return m:del(section, self.option)
else
return m:set(section, self.option, "tcp")
end
end
@@ -0,0 +1,120 @@
<%
local api = self.api
local cfgid = self.cfgid
-%>
<script type="text/javascript">
//<![CDATA[
function to_edit_node(btn) {
if (!btn) return;
const idReg = /^cbid\..*\..*node$/;
let hidden_select = null;
const selects = document.querySelectorAll('select[id^="cbid."][id*="."][id$="node"]');
for (const sel of selects) {
if ( idReg.test(sel.id) && getComputedStyle(sel).display === "none" && (sel.compareDocumentPosition(btn) & Node.DOCUMENT_POSITION_FOLLOWING)) {
hidden_select = sel;
}
}
if (!hidden_select) return;
let node_select_value = hidden_select?.options[0]?.value;
if (!node_select_value || node_select_value.indexOf("tcp") === 0) {
return;
}
let to_url = '<%=api.url("node_config")%>/' + node_select_value;
if (node_select_value.indexOf("Socks_") === 0) {
to_url = '<%=api.url("socks_config")%>/' + node_select_value.substring("Socks_".length);
}
location.href = to_url;
}
document.addEventListener('DOMContentLoaded', function () {
function go() {
const node = document.querySelector(".cbi-section-node");
if (!node) return false;
let changed = false;
const all_node = node.querySelectorAll("[id]");
const reg1 = /^cbid\..*\.(tcp_node|udp_node)\.main$/;
for (const el of all_node) {
if (!reg1.test(el.id)) continue;
if (el.querySelector(".node-actions")) continue;
const cbid = el.id.replace(/\.main$/, "");
const hidden_select = document.getElementById(cbid);
const node_select_value = hidden_select?.options[0]?.value;
if (!node_select_value || node_select_value.indexOf("tcp") === 0) {
continue;
}
let html = '<a href="#" onclick="return to_edit_node(this);"><%:Edit%></a>';
const m = cbid.match(/\.(tcp|udp)_node$/);
if (m && (m[1] === "tcp" || m[1] === "udp")) {
html += '<a href="#" onclick="window.open(\'' + '<%=api.url("get_redir_log") .. "?name=" .. cfgid%>&proto=' + m[1] + '\', \'_blank\')"><%:Log%></a>';
}
html = '<div class="node-actions" style="display:inline-flex; align-items:center; gap:4px; flex-wrap:wrap; margin-left:4px;">' + html + '</div>'
el.insertAdjacentHTML("beforeend", html);
changed = true;
}
return changed;
}
const target = document.querySelector('form') || document.body;
const observer = new MutationObserver(() => go() ? observer.disconnect() : 0);
observer.observe(target, { childList: true, subtree: true });
const timer = setInterval(() => go() ? (clearInterval(timer), observer.disconnect()) : 0, 300);
setTimeout(() => { clearInterval(timer); observer.disconnect(); }, 5000);
});
(function () {
const startTime = Date.now();
const TIMEOUT = 3000;
const waitForDnsSelect = () => {
const dns_select = document.querySelector("select[id*='dns_shunt']");
if (dns_select) {
initDnsSelect(dns_select);
return;
}
if (Date.now() - startTime >= TIMEOUT) {
return;
}
requestAnimationFrame(waitForDnsSelect);
};
waitForDnsSelect();
const initDnsSelect = (dns_select) => {
if (dns_select.value === "chinadns-ng") {
addLogLink(dns_select);
}
if (dns_select._dnsLogBinded) return;
dns_select._dnsLogBinded = true;
dns_select.addEventListener("change", () => {
const existingLogLink = dns_select.parentElement.querySelector("a.dns-log-link");
if (existingLogLink) {
existingLogLink.remove();
}
if (dns_select.value === "chinadns-ng") {
addLogLink(dns_select);
}
});
};
const addLogLink = (select) => {
if (select.parentElement.querySelector("a.dns-log-link")) {
return;
}
const logLink = document.createElement("a");
logLink.innerHTML = "<%:Log%>";
logLink.href = "#";
logLink.className = "dns-log-link";
logLink.style.marginLeft = "10px";
logLink.setAttribute("onclick", "window.open('" + '<%=api.url("get_chinadns_log") .. "?flag=" .. cfgid%>' + "', '_blank')");
select.insertAdjacentElement("afterend", logLink);
};
})();
//]]>
</script>
@@ -1,55 +0,0 @@
<%
local api = require "luci.passwall.api"
-%>
<script type="text/javascript">
//<![CDATA[
(function () {
const startTime = Date.now();
const TIMEOUT = 3000;
const waitForDnsSelect = () => {
const dns_select = document.querySelector("select[id*='dns_shunt']");
if (dns_select) {
initDnsSelect(dns_select);
return;
}
if (Date.now() - startTime >= TIMEOUT) {
return;
}
requestAnimationFrame(waitForDnsSelect);
};
waitForDnsSelect();
const initDnsSelect = (dns_select) => {
if (dns_select.value === "chinadns-ng") {
addLogLink(dns_select);
}
if (dns_select._dnsLogBinded) return;
dns_select._dnsLogBinded = true;
dns_select.addEventListener("change", () => {
const existingLogLink = dns_select.parentElement.querySelector("a.dns-log-link");
if (existingLogLink) {
existingLogLink.remove();
}
if (dns_select.value === "chinadns-ng") {
addLogLink(dns_select);
}
});
};
const addLogLink = (select) => {
if (select.parentElement.querySelector("a.dns-log-link")) {
return;
}
const logLink = document.createElement("a");
logLink.innerHTML = "<%:Log%>";
logLink.href = "#";
logLink.className = "dns-log-link";
logLink.style.marginLeft = "10px";
logLink.setAttribute("onclick", "window.open('" + '<%=api.url("get_chinadns_log") .. "?flag=" .. section%>' + "', '_blank')");
select.insertAdjacentElement("afterend", logLink);
};
})();
//]]>
</script>