LUCI_TITLE:=LuCI support for Adblock
LUCI_DEPENDS:=+luci-base +adblock
-PKG_VERSION:=4.4.3
+PKG_VERSION:=4.4.4
PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
'require fs';
'require ui';
-let localFile = '/etc/adblock/adblock.allowlist';
-let notMsg, errMsg;
+const localFile = '/etc/adblock/adblock.allowlist';
+let notMsg = false, errMsg = false;
+
+const resetScroll = () => {
+ document.body.scrollTop = document.documentElement.scrollTop = 0;
+};
return view.extend({
load: function () {
},
render: function (allowlist) {
if (allowlist[0] && allowlist[0].size >= 100000) {
- document.body.scrollTop = document.documentElement.scrollTop = 0;
+ resetScroll();
ui.addNotification(null, E('p', _('The allowlist is too big, unable to save modifications.')), 'error');
}
return E('div', { 'class': 'cbi-section cbi-section-descr' }, [
]);
},
handleSave: function (ev) {
- let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n')) + '\n';
- return fs.write(localFile, value)
- .then(function () {
- document.querySelector('textarea').value = value;
- document.body.scrollTop = document.documentElement.scrollTop = 0;
- if (!notMsg) {
- ui.addNotification(null, E('p', _('Allowlist modifications have been saved, reload adblock that changes take effect.')), 'info');
- notMsg = true;
- }
- }).catch(function (e) {
- document.body.scrollTop = document.documentElement.scrollTop = 0;
- if (!errMsg) {
- ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error');
- errMsg = true;
- }
- });
+ let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/[^a-z0-9\.\-# \r\n]/g, '').replace(/\r\n?/g, '\n'));
+ return fs.write(localFile, value + "\n")
+ .then(function () {
+ document.querySelector('textarea').value = value;
+ resetScroll();
+ if (!notMsg) {
+ ui.addNotification(null, E('p', _('Allowlist modifications have been saved, reload adblock that changes take effect.')), 'info');
+ notMsg = true;
+ }
+ }).catch(function (e) {
+ resetScroll();
+ if (!errMsg) {
+ ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error');
+ errMsg = true;
+ }
+ });
},
handleSaveApply: null,
handleReset: null
'require fs';
'require ui';
-let localFile = '/etc/adblock/adblock.blocklist';
-let notMsg, errMsg;
+const localFile = '/etc/adblock/adblock.blocklist';
+let notMsg = false, errMsg = false;
+
+const resetScroll = () => {
+ document.body.scrollTop = document.documentElement.scrollTop = 0;
+};
return view.extend({
load: function () {
},
render: function (blocklist) {
if (blocklist[0] && blocklist[0].size >= 100000) {
- document.body.scrollTop = document.documentElement.scrollTop = 0;
+ resetScroll();
ui.addNotification(null, E('p', _('The blocklist is too big, unable to save modifications.')), 'error');
}
return E('div', { 'class': 'cbi-section cbi-section-descr' }, [
E('p', _('This is the local adblock blocklist to always-block certain domains.<br /> \
<em><b>Please note:</b></em> add only one domain per line. Comments introduced with \'#\' are allowed - ip addresses, wildcards and regex are not.')),
E('textarea', {
- 'style': 'width: 100% !important; padding: 5px; font-family: monospace; margin-top: .4em',
+ 'style': 'min-height: 500px; max-height: 90vh; width: 100%; padding: 5px; font-family: monospace; resize: vertical;',
'spellcheck': 'false',
'wrap': 'off',
'rows': 25
]);
},
handleSave: function (ev) {
- let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n')) + '\n';
- return fs.write(localFile, value)
- .then(function () {
- document.querySelector('textarea').value = value;
- document.body.scrollTop = document.documentElement.scrollTop = 0;
- if (!notMsg) {
- ui.addNotification(null, E('p', _('Blocklist modifications have been saved, reload adblock that changes take effect.')), 'info');
- notMsg = true;
- }
- }).catch(function (e) {
- document.body.scrollTop = document.documentElement.scrollTop = 0;
- if (!errMsg) {
- ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error');
- errMsg = true;
- }
- });
+ let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/[^a-z0-9\.\-# \r\n]/g, '').replace(/\r\n?/g, '\n'));
+ return fs.write(localFile, value + "\n")
+ .then(function () {
+ document.querySelector('textarea').value = value;
+ resetScroll();
+ if (!notMsg) {
+ ui.addNotification(null, E('p', _('Blocklist modifications have been saved, reload adblock that changes take effect.')), 'info');
+ notMsg = true;
+ }
+ }).catch(function (e) {
+ resetScroll();
+ if (!errMsg) {
+ ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error');
+ errMsg = true;
+ }
+ });
},
handleSaveApply: null,
handleReset: null
'require ui';
'require uci';
+var notMsg = false, errMsg = false;
+
/*
button handling
*/
if (res.search(pattern) === -1) {
var blocklist = res + domain + '\n';
fs.write('/etc/adblock/adblock.blocklist', blocklist);
- ui.addNotification(null, E('p', _('Blocklist modifications have been saved, reload adblock that changes take effect.')), 'info');
+ if (!notMsg) {
+ notMsg = true;
+ ui.addNotification(null, E('p', _('Blocklist modifications have been saved, reload adblock that changes take effect.')), 'info');
+ }
}
ui.hideModal();
});
if (res.search(pattern) === -1) {
var allowlist = res + domain + '\n';
fs.write('/etc/adblock/adblock.allowlist', allowlist);
- ui.addNotification(null, E('p', _('Allowlist modifications have been saved, reload adblock that changes take effect.')), 'info');
+ if (!notMsg) {
+ notMsg = true;
+ ui.addNotification(null, E('p', _('Allowlist modifications have been saved, reload adblock that changes take effect.')), 'info');
+ }
}
ui.hideModal();
});
E('button', {
'class': 'btn cbi-button-action',
'click': ui.createHandlerFn(this, function (ev) {
- var domain = document.getElementById('search').value.trim().toLowerCase().replace(/[^a-z0-9\.\-]/g, '');
+ const domain = document.getElementById('search').value.trim().toLowerCase().replace(/[^a-z0-9\.\-]/g, '');
if (domain) {
document.getElementById('run').classList.add("spinning");
document.getElementById('search').value = domain;
document.getElementById('result').textContent = 'The query is running, please wait...';
L.resolveDefault(fs.exec_direct('/etc/init.d/adblock', ['query', domain])).then(function (res) {
- var result = document.getElementById('result');
+ const result = document.getElementById('result');
if (res) {
result.textContent = res.trim();
} else {
},
render: function (dnsreport) {
- let content = [], notMsg, errMsg;
+ let content = [];
if (dnsreport) {
try {
content[0] = "";
}
- var rows_top = [];
- var tbl_top = E('table', { 'class': 'table', 'id': 'top_10' }, [
+ let rows_top = [];
+ const tbl_top = E('table', { 'class': 'table', 'id': 'top_10' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th right' }, _('Count')),
E('th', { 'class': 'th' }, _('Clients')),
])
]);
- var max = 0;
+ let max = 0;
if (content[0].top_clients && content[0].top_domains && content[0].top_blocked) {
max = Math.max(content[0].top_clients.length, content[0].top_domains.length, content[0].top_blocked.length);
}
- for (var i = 0; i < max; i++) {
- var a_cnt = '\xa0', a_addr = '\xa0', b_cnt = '\xa0', b_addr = '\xa0', c_cnt = '\xa0', c_addr = '\xa0';
+ for (let i = 0; i < max; i++) {
+ let a_cnt = '\xa0', a_addr = '\xa0', b_cnt = '\xa0', b_addr = '\xa0', c_cnt = '\xa0', c_addr = '\xa0';
if (content[0].top_clients[i]) {
a_cnt = content[0].top_clients[i].count;
}
}
cbi_update_table(tbl_top, rows_top);
- var rows_requests = [];
- var tbl_requests = E('table', { 'class': 'table', 'id': 'requests' }, [
+ let rows_requests = [];
+ const tbl_requests = E('table', { 'class': 'table', 'id': 'requests' }, [
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th' }, _('Date')),
E('th', { 'class': 'th' }, _('Time')),
max = 0;
if (content[0].requests) {
- var button;
+ let button;
max = content[0].requests.length;
- for (var i = 0; i < max; i++) {
+ for (let i = 0; i < max; i++) {
if (content[0].requests[i].rc === 'NX') {
button = E('button', {
'class': 'btn cbi-button cbi-button-positive',
'use strict';
-'require fs';
+'require rpc';
+
+const callLogRead = rpc.declare({
+ object: 'log',
+ method: 'read',
+ params: ['lines', 'stream', 'oneshot'],
+ expect: {}
+});
function Logview(logtag, name) {
return L.view.extend({
- load: function() {
- return Promise.all([
- L.resolveDefault(fs.stat('/sbin/logread'), null),
- L.resolveDefault(fs.stat('/usr/sbin/logread'), null)
- ]);
- },
+ load: () => Promise.resolve(),
- render: function(stat) {
- let logger = stat[0]?.path || stat[1]?.path || null;
+ render: () => {
+ L.Poll.add(() => {
+ return callLogRead(1000, false, true).then(res => {
+ const logEl = document.getElementById('logfile');
+ if (!logEl) return;
- if (!logger) {
- return E('div', { class: 'error' }, _('logread not found on system.'));
- }
- L.Poll.add(function() {
- return L.resolveDefault(fs.exec_direct(logger, ['-e', logtag])).then(function(res) {
- var log = document.getElementById('logfile');
- if (log) {
- log.value = res ? res.trim() : _('No %s related logs yet!').format(name);
- log.scrollTop = log.scrollHeight;
+ const entries = res?.log ?? [];
+ if (entries.length > 0) {
+ const filtered = entries
+ .filter(entry => !logtag || entry.msg.includes(logtag))
+ .map(entry => {
+ const d = new Date(entry.time);
+ const date = d.toLocaleDateString([], {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit'
+ });
+ const time = d.toLocaleTimeString([], {
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ hour12: false
+ });
+ return `[${date}-${time}] ${entry.msg}`;
+ });
+ logEl.value = filtered.join('\n');
+ } else {
+ logEl.value = _('No %s related logs yet!').format(name);
}
+ logEl.scrollTop = logEl.scrollHeight;
});
});
+
return E('div', { class: 'cbi-map' }, [
E('div', { class: 'cbi-section' }, [
- E('div', { class: 'cbi-section-descr' }, _('The syslog output, pre-filtered for messages related to: %s').format(name)),
+ E('div', { class: 'cbi-section-descr' },
+ _('The syslog output, pre-filtered for messages related to: %s').format(name)),
E('textarea', {
id: 'logfile',
style: 'min-height: 500px; max-height: 90vh; width: 100%; padding: 5px; font-family: monospace; resize: vertical;',
])
]);
},
+
handleSaveApply: null,
handleSave: null,
handleReset: null
});
}
-return L.Class.extend({
- Logview: Logview
-});
+return L.Class.extend({ Logview });
m = new form.Map('adblock', 'Adblock', _('Configuration of the adblock package to block ad/abuse domains by using DNS. \
For further information <a href="https://github.com/openwrt/packages/blob/master/net/adblock/files/README.md" target="_blank" rel="noreferrer noopener" >check the online documentation</a>'));
+ /*
+ set text content helper function
+ */
+ const setText = (id, value) => {
+ const el = document.getElementById(id);
+ if (el) {
+ el.textContent = value || '-';
+ }
+ };
+
/*
poll runtime information
*/
ui.addNotification(null, E('p', _('Unable to parse the runtime information!')), 'error');
}
if (status && info) {
- status.textContent = (info.adblock_status || '-') + ' / ' + (info.adblock_version || '-');
+ status.textContent = `${info.adblock_status || '-'} (frontend: ${info.frontend_ver || '-'} / backend: ${info.backend_ver || '-'})`;
if (info.adblock_status === "running") {
if (!status.classList.contains("spinning")) {
status.classList.add("spinning");
status.classList.remove('spinning');
}
}
- var domains = document.getElementById('domains');
- if (domains && info) {
- domains.textContent = info.blocked_domains || '-';
- }
- var feeds = document.getElementById('feeds');
- var src_array = [];
- if (feeds && info) {
- for (var i = 0; i < info.active_feeds.length; i++) {
- if (i < info.active_feeds.length - 1) {
- src_array += info.active_feeds[i] + ', ';
- } else {
- src_array += info.active_feeds[i]
- }
- }
- feeds.textContent = src_array || '-';
- }
- var backend = document.getElementById('backend');
- if (backend && info) {
- backend.textContent = info.dns_backend || '-';
- }
- var ifaces = document.getElementById('ifaces');
- if (ifaces && info) {
- ifaces.textContent = info.run_ifaces || '-';
- }
- var dirs = document.getElementById('dirs');
- if (dirs && info) {
- dirs.textContent = info.run_directories || '-';
- }
- var flags = document.getElementById('flags');
- if (flags && info) {
- flags.textContent = info.run_flags || '-';
- }
- var run = document.getElementById('run');
- if (run && info) {
- run.textContent = info.last_run || '-';
- }
- var sys = document.getElementById('sys');
- if (sys && info) {
- sys.textContent = info.system_info || '-';
+ if (info) {
+ setText('domains', info.blocked_domains);
+ setText('feeds', info.active_feeds?.join(', '));
+ setText('backend', info.dns_backend);
+ setText('ifaces', info.run_ifaces);
+ setText('dirs', info.run_directories);
+ setText('flags', info.run_flags);
+ setText('run', info.last_run);
+ setText('sys', info.system_info);
}
});
}, 2);
"luci-app-adblock": {
"description": "Grant access to LuCI app adblock",
"write": {
- "uci": [
- "adblock"
- ],
+ "uci": [ "adblock" ],
"file": {
- "/etc/adblock/*": [
- "read",
- "write"
- ],
- "/etc/adblock/adblock.allowlist": [
- "write"
- ],
- "/etc/adblock/adblock.blocklist": [
- "write"
- ],
- "/etc/adblock/adblock.custom.feeds": [
- "read",
- "write"
- ]
+ "/etc/adblock/*": [ "read", "write" ],
+ "/etc/adblock/adblock.allowlist": [ "write" ],
+ "/etc/adblock/adblock.blocklist": [ "write" ],
+ "/etc/adblock/adblock.custom.feeds": [ "read", "write" ]
}
},
"read": {
- "cgi-io": [
- "exec"
- ],
+ "cgi-io": [ "exec" ],
"file": {
- "/var/run/adblock.pid": [
- "read"
- ],
- "/var/run/adb_runtime.json": [
- "read"
- ],
- "/sbin/logread -e adblock-": [
- "exec"
- ],
- "/usr/sbin/logread -e adblock-": [
- "exec"
- ],
- "/etc/init.d/adblock reload": [
- "exec"
- ],
- "/etc/init.d/adblock restart": [
- "exec"
- ],
- "/etc/init.d/adblock suspend": [
- "exec"
- ],
- "/etc/init.d/adblock resume": [
- "exec"
- ],
- "/etc/init.d/adblock stop": [
- "exec"
- ],
- "/etc/init.d/adblock report [a-z]* [0-9]* [0-9]* *": [
- "exec"
- ],
- "/etc/init.d/adblock query *": [
- "exec"
- ]
+ "/var/run/adblock.pid": [ "read" ],
+ "/var/run/adb_runtime.json": [ "read" ],
+ "/sbin/logread -e adblock-": [ "exec" ],
+ "/usr/sbin/logread -e adblock-": [ "exec" ],
+ "/etc/init.d/adblock reload": [ "exec" ],
+ "/etc/init.d/adblock restart": [ "exec" ],
+ "/etc/init.d/adblock suspend": [ "exec" ],
+ "/etc/init.d/adblock resume": [ "exec" ],
+ "/etc/init.d/adblock stop": [ "exec" ],
+ "/etc/init.d/adblock report [a-z]* [0-9]* [0-9]* *": [ "exec" ],
+ "/etc/init.d/adblock query *": [ "exec" ]
},
- "uci": [
- "adblock"
- ]
+ "uci": [ "adblock" ],
+ "log": [ "read" ]
}
}
}
\ No newline at end of file