luci-app-adblock: release 4.5.3-1

* sync with base package

Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
Dirk Brenken
2026-03-15 19:42:25 +01:00
parent 86bc7f71eb
commit b015dfa745
7 changed files with 266 additions and 273 deletions

View File

@@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk
LUCI_TITLE:=LuCI support for Adblock
LUCI_DEPENDS:=+luci-base +luci-lib-uqr +adblock
PKG_VERSION:=4.5.2
PKG_RELEASE:=3
PKG_VERSION:=4.5.3
PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>

View File

@@ -4,7 +4,8 @@
'require ui';
const localFile = '/etc/adblock/adblock.allowlist';
let notMsg = false, errMsg = false;
const maxSize = 100000;
let notMsg = false;
const resetScroll = () => {
document.body.scrollTop = document.documentElement.scrollTop = 0;
@@ -12,19 +13,24 @@ const resetScroll = () => {
return view.extend({
load: function () {
return L.resolveDefault(fs.stat(localFile), "")
return L.resolveDefault(fs.stat(localFile), null)
.then(function (stat) {
if (!stat) {
return fs.write(localFile, "");
}
return Promise.all([
L.resolveDefault(fs.stat(localFile), ""),
L.resolveDefault(fs.read_direct(localFile), "")
]);
});
if (!stat) {
return fs.write(localFile, "").then(() => [{ size: 0 }, ""]);
}
return Promise.all([
Promise.resolve(stat),
L.resolveDefault(fs.read_direct(localFile), "")
]);
});
},
render: function (allowlist) {
if (allowlist[0] && allowlist[0].size >= 100000) {
const size = allowlist[0] ? allowlist[0].size : 0;
const content = allowlist[1] != null ? allowlist[1] : '';
const tooBig = size >= maxSize;
if (tooBig) {
resetScroll();
ui.addNotification(null, E('p', _('The allowlist is too big, unable to save modifications.')), 'error');
}
@@ -35,28 +41,29 @@ return view.extend({
'style': 'width: 100% !important; padding: 5px; font-family: monospace; margin-top: .4em',
'spellcheck': 'false',
'wrap': 'off',
'rows': 25
}, [allowlist[1] != null ? allowlist[1] : ''])
'rows': 25,
'readonly': tooBig ? 'readonly' : null,
'input': function () { notMsg = false; }
}, [content])
]);
},
handleSave: function (ev) {
let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/[^a-z0-9\.\-# \r\n]/g, '').replace(/\r\n?/g, '\n'));
handleSave: function (_ev) {
const 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) {
.then(function () {
document.querySelector('textarea').value = value + "\n";
resetScroll();
if (!notMsg) {
notMsg = true;
ui.addNotification(null, E('p', _('Allowlist modifications have been saved, reload adblock that changes take effect.')), 'info');
}
}).catch(function (e) {
resetScroll();
ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error');
errMsg = true;
}
});
});
},
handleSaveApply: null,
handleReset: null
});
});

View File

@@ -4,7 +4,8 @@
'require ui';
const localFile = '/etc/adblock/adblock.blocklist';
let notMsg = false, errMsg = false;
const maxSize = 100000;
let notMsg = false;
const resetScroll = () => {
document.body.scrollTop = document.documentElement.scrollTop = 0;
@@ -12,19 +13,24 @@ const resetScroll = () => {
return view.extend({
load: function () {
return L.resolveDefault(fs.stat(localFile), "")
return L.resolveDefault(fs.stat(localFile), null)
.then(function (stat) {
if (!stat) {
return fs.write(localFile, "");
}
return Promise.all([
L.resolveDefault(fs.stat(localFile), ""),
L.resolveDefault(fs.read_direct(localFile), "")
]);
});
if (!stat) {
return fs.write(localFile, "").then(() => [{ size: 0 }, ""]);
}
return Promise.all([
Promise.resolve(stat),
L.resolveDefault(fs.read_direct(localFile), "")
]);
});
},
render: function (blocklist) {
if (blocklist[0] && blocklist[0].size >= 100000) {
const size = blocklist[0] ? blocklist[0].size : 0;
const content = blocklist[1] != null ? blocklist[1] : '';
const tooBig = size >= maxSize;
if (tooBig) {
resetScroll();
ui.addNotification(null, E('p', _('The blocklist is too big, unable to save modifications.')), 'error');
}
@@ -32,31 +38,32 @@ return view.extend({
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': 'min-height: 500px; max-height: 90vh; width: 100%; padding: 5px; font-family: monospace; resize: vertical;',
'style': 'width: 100% !important; padding: 5px; font-family: monospace; margin-top: .4em',
'spellcheck': 'false',
'wrap': 'off',
'rows': 25
}, [blocklist[1] != null ? blocklist[1] : ''])
'rows': 25,
'readonly': tooBig ? 'readonly' : null,
'input': function () { notMsg = false; }
}, [content])
]);
},
handleSave: function (ev) {
let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/[^a-z0-9\.\-# \r\n]/g, '').replace(/\r\n?/g, '\n'));
handleSave: function (_ev) {
const 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) {
.then(function () {
document.querySelector('textarea').value = value + "\n";
resetScroll();
if (!notMsg) {
notMsg = true;
ui.addNotification(null, E('p', _('Blocklist modifications have been saved, reload adblock that changes take effect.')), 'info');
}
}).catch(function (e) {
resetScroll();
ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error');
errMsg = true;
}
});
});
},
handleSaveApply: null,
handleReset: null
});
});

View File

@@ -4,7 +4,9 @@
'require ui';
'require uci';
var notMsg = false, errMsg = false;
/* separate flags per notification context */
let listNotMsg = false;
let mapNotMsg = false;
/*
button handling
@@ -29,13 +31,13 @@ function handleAction(ev) {
'click': ui.createHandlerFn(this, function (ev) {
L.resolveDefault(fs.read_direct('/etc/adblock/adblock.blocklist'), '')
.then(function (res) {
var domain = document.getElementById('blocklist').value.trim().toLowerCase().replace(/[^a-z0-9\.\-]/g, '');
var pattern = new RegExp('^' + domain.replace(/[\.]/g, '\\.') + '$', 'm');
const domain = document.getElementById('blocklist').value.trim().toLowerCase().replace(/[^a-z0-9.\-]/g, '');
const pattern = new RegExp('^' + domain.replace(/[.]/g, '\\.') + '$', 'm');
if (res.search(pattern) === -1) {
var blocklist = res + domain + '\n';
const blocklist = res + domain + '\n';
fs.write('/etc/adblock/adblock.blocklist', blocklist);
if (!notMsg) {
notMsg = true;
if (!listNotMsg) {
listNotMsg = true;
ui.addNotification(null, E('p', _('Blocklist modifications have been saved, reload adblock that changes take effect.')), 'info');
}
}
@@ -67,13 +69,13 @@ function handleAction(ev) {
'click': ui.createHandlerFn(this, function (ev) {
L.resolveDefault(fs.read_direct('/etc/adblock/adblock.allowlist'), '')
.then(function (res) {
var domain = document.getElementById('allowlist').value.trim().toLowerCase().replace(/[^a-z0-9\.\-]/g, '');
var pattern = new RegExp('^' + domain.replace(/[\.]/g, '\\.') + '$', 'm');
const domain = document.getElementById('allowlist').value.trim().toLowerCase().replace(/[^a-z0-9.\-]/g, '');
const pattern = new RegExp('^' + domain.replace(/[.]/g, '\\.') + '$', 'm');
if (res.search(pattern) === -1) {
var allowlist = res + domain + '\n';
const allowlist = res + domain + '\n';
fs.write('/etc/adblock/adblock.allowlist', allowlist);
if (!notMsg) {
notMsg = true;
if (!listNotMsg) {
listNotMsg = true;
ui.addNotification(null, E('p', _('Allowlist modifications have been saved, reload adblock that changes take effect.')), 'info');
}
}
@@ -120,7 +122,7 @@ function handleAction(ev) {
E('button', {
'class': 'btn cbi-button-action',
'click': ui.createHandlerFn(this, function (ev) {
const 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;
@@ -134,7 +136,7 @@ function handleAction(ev) {
}
document.getElementById('run').classList.remove("spinning");
document.getElementById('search').value = '';
})
});
}
document.getElementById('search').focus();
})
@@ -173,8 +175,7 @@ function handleAction(ev) {
])
]),
E('label', { 'class': 'cbi-input-text', 'style': 'padding-top:.5em' }, [
E('input', { 'class': 'cbi-input-text', 'spellcheck': 'false', 'id': 'search' }, [
]),
E('input', { 'class': 'cbi-input-text', 'spellcheck': 'false', 'id': 'search' }, []),
'\xa0\xa0\xa0',
_('Filter criteria like date, domain or client (optional)')
]),
@@ -190,16 +191,16 @@ function handleAction(ev) {
'click': function () {
document.querySelectorAll('.cbi-page-actions button').forEach(function (btn) {
btn.disabled = true;
})
});
this.blur();
this.classList.add('spinning');
const top_count = document.getElementById('top_count').value;
const res_count = document.getElementById('res_count').value;
const search = document.getElementById('search').value.trim().replace(/[^\w\.\-\:]/g, '') || '+';
const search = document.getElementById('search').value.trim().replace(/[^\w.\-:]/g, '') || '+';
L.resolveDefault(fs.exec_direct('/etc/init.d/adblock', ['report', 'gen', top_count, res_count, search]), '')
.then(function () {
location.reload();
})
});
}
}, _('Refresh'))
])
@@ -284,30 +285,17 @@ return view.extend({
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;
}
if (content[0].top_clients[i]) {
a_addr = content[0].top_clients[i].address;
}
if (content[0].top_domains[i]) {
b_cnt = content[0].top_domains[i].count;
}
if (content[0].top_domains[i]) {
b_addr = '<a href="https://ip-api.com/#' + encodeURIComponent(content[0].top_domains[i].address) + '" target="_blank" rel="noreferrer noopener" title="Domain Lookup">' + content[0].top_domains[i].address + '</a>';
}
if (content[0].top_blocked[i]) {
c_cnt = content[0].top_blocked[i].count;
}
if (content[0].top_blocked[i]) {
c_addr = '<a href="https://ip-api.com/#' + encodeURIComponent(content[0].top_blocked[i].address) + '" target="_blank" rel="noreferrer noopener" title="Domain Lookup">' + content[0].top_blocked[i].address + '</a>';
}
rows_top.push([
a_cnt,
a_addr,
b_cnt,
b_addr,
c_cnt,
c_addr
]);
rows_top.push([a_cnt, a_addr, b_cnt, b_addr, c_cnt, c_addr]);
}
cbi_update_table(tbl_top, rows_top);
@@ -325,11 +313,10 @@ return view.extend({
])
]);
max = 0;
if (content[0].requests) {
let button;
max = content[0].requests.length;
for (let i = 0; i < max; i++) {
let button;
if (content[0].requests[i].rc === 'NX') {
button = E('button', {
'class': 'btn cbi-button cbi-button-positive',
@@ -365,7 +352,7 @@ return view.extend({
const page = E('div', { 'class': 'cbi-map', 'id': 'map' }, [
E('div', { 'class': 'cbi-section' }, [
E('p', _('This tab displays the most recently generated DNS report. Use the \Refresh\ button to update it.')),
E('p', _('This tab displays the most recently generated DNS report. Use the \'Refresh\' button to update it.')),
E('div', { 'class': 'cbi-value', 'style': 'position:relative;min-height:220px' }, [
E('div', {
'style': 'position:absolute; top:0; right:0; text-align:center'
@@ -408,7 +395,7 @@ return view.extend({
'style': 'float:none;margin-right:.4em;',
'id': 'btnTest',
'title': 'Adblock Test',
'click': function() {
'click': function () {
window.open('https://adblock.turtlecute.org/', '_blank', 'noopener,noreferrer');
}
}, [_('Adblock Test')]),
@@ -419,13 +406,12 @@ return view.extend({
'title': 'Map',
'disabled': 'disabled',
'click': ui.createHandlerFn(this, function () {
if (content[1] && content[1].length > 1) {
if (Array.isArray(content[1]) && content[1].length > 1) {
sessionStorage.setItem('mapData', JSON.stringify(content[1]));
return handleAction('map');
}
else {
if (!notMsg) {
notMsg = true;
} else {
if (!mapNotMsg) {
mapNotMsg = true;
return ui.addNotification(null, E('p', _('No GeoIP Map data!')), 'info');
}
}
@@ -449,40 +435,38 @@ return view.extend({
}, [_('Refresh...')])
])
]);
if (uci.get('adblock', 'global', 'adb_map') === '1') {
const btn = page.querySelector('#btnMap');
if (btn) {
btn.removeAttribute('disabled');
}
}
/* Draw Pie Chart with Tooltip */
const tooltip = E('div', {
const tooltipEl = E('div', {
id: 'dnsPieTooltip',
style: 'position:absolute; padding:6px 10px; background:#333; color:#fff; border-radius:4px; font-size:12px; pointer-events:none; opacity:0; transition:opacity .15s; z-index:9999'
});
document.body.appendChild(tooltip);
setTimeout(function() {
document.body.appendChild(tooltipEl);
setTimeout(function () {
const total = Number(content[0].total || 0);
const blocked = Number(content[0].blocked || 0);
const allowed = Math.max(total - blocked, 0);
const canvas = document.getElementById('dnsPie');
if (!canvas || total <= 0)
return;
if (!canvas || total <= 0) return;
const ctx = canvas.getContext('2d');
const colors = {
blocked: '#b04a4a',
allowed: '#6a8f6a'
};
const colors = { blocked: '#b04a4a', allowed: '#6a8f6a' };
let finalRot = 0;
function drawPie(rotation = 0) {
function drawPie(rotation) {
const w = canvas.clientWidth;
canvas.width = w;
canvas.height = w;
const cx = w / 2;
const cy = w / 2;
const r = (w / 2) - 4;
const cx = w / 2, cy = w / 2, r = (w / 2) - 4;
const blockedAngle = (blocked / total) * 2 * Math.PI;
const allowedAngle = (allowed / total) * 2 * Math.PI;
@@ -505,43 +489,48 @@ return view.extend({
ctx.lineWidth = 2;
ctx.stroke();
}
let rot = 0;
function animate() {
rot += 0.10;
drawPie(rot);
if (rot < Math.PI * 2)
if (rot < Math.PI * 2) {
requestAnimationFrame(animate);
} else {
finalRot = rot % (2 * Math.PI);
drawPie(finalRot);
}
}
animate();
window.addEventListener('resize', function() {
drawPie(rot);
window.addEventListener('resize', function () {
drawPie(finalRot);
});
const tooltip = document.getElementById('dnsPieTooltip');
canvas.addEventListener('mousemove', function(ev) {
const blockedAngle = (blocked / total) * 2 * Math.PI;
canvas.addEventListener('mousemove', function (ev) {
const rect = canvas.getBoundingClientRect();
const x = ev.clientX - rect.left;
const y = ev.clientY - rect.top;
const cx = canvas.width / 2;
const cy = canvas.height / 2;
const dx = x - cx;
const dy = y - cy;
const dist = Math.sqrt(dx*dx + dy*dy);
if (dist > canvas.width/2 - 4) {
const cx = canvas.width / 2, cy = canvas.height / 2;
const dx = x - cx, dy = y - cy;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist > canvas.width / 2 - 4) {
tooltip.style.opacity = 0;
return;
}
let angle = Math.atan2(dy, dx);
/* normalise angle relative to finalRot so it matches the drawn slices */
let angle = Math.atan2(dy, dx) - finalRot;
if (angle < 0) angle += 2 * Math.PI;
const blockedAngle = (blocked / total) * 2 * Math.PI;
let label, abs, pct;
if (angle < blockedAngle) {
label = 'Blocked';
abs = blocked;
label = 'Blocked'; abs = blocked;
pct = ((blocked / total) * 100).toFixed(1) + '%';
} else {
label = 'Allowed';
abs = allowed;
label = 'Allowed'; abs = allowed;
pct = ((allowed / total) * 100).toFixed(1) + '%';
}
tooltip.textContent = `${label}: ${abs} (${pct})`;
@@ -549,13 +538,15 @@ return view.extend({
tooltip.style.top = ev.pageY + 12 + 'px';
tooltip.style.opacity = 1;
});
canvas.addEventListener('mouseleave', function() {
canvas.addEventListener('mouseleave', function () {
tooltip.style.opacity = 0;
});
}, 0);
return page;
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});
});

View File

@@ -13,6 +13,26 @@ document.querySelector('head').appendChild(E('link', {
'href': L.resource('view/adblock/custom.css')
}));
/*
module-level file size set during render, read by observer
*/
let fileSize = 0;
/*
button state helper
*/
function updateButtons() {
const buttons = document.querySelectorAll('#btnClear, #btnCreate, #btnSave, #btnUpload, #btnDownload');
if (fileSize === 0) {
if (buttons[1]) buttons[1].removeAttribute('disabled');
if (buttons[2]) buttons[2].removeAttribute('disabled');
} else {
if (buttons[0]) buttons[0].removeAttribute('disabled');
if (buttons[3]) buttons[3].removeAttribute('disabled');
if (buttons[4]) buttons[4].removeAttribute('disabled');
}
}
/*
observe DOM changes
*/
@@ -29,17 +49,7 @@ const observer = new MutationObserver(function (mutations) {
labels.forEach(function (label) {
label.setAttribute("style", "font-weight: bold !important; color: #595 !important;");
})
L.resolveDefault(fs.stat('/etc/adblock/adblock.custom.feeds'), '').then(function (stat) {
const buttons = document.querySelectorAll('#btnClear, #btnCreate, #btnSave, #btnUpload, #btnDownload');
if (buttons[1] && buttons[2] && stat.size === 0) {
buttons[1].removeAttribute('disabled');
buttons[2].removeAttribute('disabled');
} else if (buttons[0] && buttons[3] && buttons[4] && stat.size > 0) {
buttons[0].removeAttribute('disabled');
buttons[3].removeAttribute('disabled');
buttons[4].removeAttribute('disabled');
}
});
updateButtons();
}
});
@@ -59,28 +69,21 @@ function handleEdit(ev) {
if (ev === 'upload') {
return ui.uploadFile('/etc/adblock/adblock.custom.feeds').then(function () {
L.resolveDefault(fs.read_direct('/etc/adblock/adblock.custom.feeds', 'json'), "").then(function (data) {
if (data) {
let dataLength = Object.keys(data).length || 0;
if (dataLength > 0) {
for (let i = 0; i < dataLength; i++) {
let feed = Object.keys(data)[i];
let descr = data[feed].descr;
if (feed && descr) {
continue;
}
fs.write('/etc/adblock/adblock.custom.feeds', null).then(function () {
return ui.addNotification(null, E('p', _('Upload of the custom feed file failed.')), 'error');
});
if (data && Object.keys(data).length > 0) {
for (let i = 0; i < Object.keys(data).length; i++) {
let feed = Object.keys(data)[i];
let descr = data[feed].descr;
if (feed && descr) {
continue;
}
} else {
fs.write('/etc/adblock/adblock.custom.feeds', null).then(function () {
return ui.addNotification(null, E('p', _('Upload of the custom feed file failed.')), 'error');
return fs.write('/etc/adblock/adblock.custom.feeds', null).then(function () {
ui.addNotification(null, E('p', _('Upload of the custom feed file failed.')), 'error');
});
}
location.reload();
} else {
fs.write('/etc/adblock/adblock.custom.feeds', null).then(function () {
return ui.addNotification(null, E('p', _('Upload of the custom feed file failed.')), 'error');
return fs.write('/etc/adblock/adblock.custom.feeds', null).then(function () {
ui.addNotification(null, E('p', _('Upload of the custom feed file failed.')), 'error');
});
}
});
@@ -118,9 +121,9 @@ function handleEdit(ev) {
}
}
/*
gather all input data
gather all input data and fall through from 'save'
*/
let sumSubElements = [];
const exportObj = {};
const nodeKeys = document.querySelectorAll('[id^="widget.cbid.json"][id$="name"]');
for (const keyNode of nodeKeys) {
const keyValue = keyNode.value?.trim();
@@ -142,40 +145,39 @@ function handleEdit(ev) {
sub[key] = value;
}
}
if (sub.descr) {
sumSubElements.push(keyValue, sub);
/* require at least descr and url to produce a valid feed entry */
if (sub.descr && sub.url) {
exportObj[keyValue] = sub;
}
}
/*
construct json object
*/
let exportObj = {};
for (let i = 0; i < sumSubElements.length; i += 2) {
const key = sumSubElements[i];
const value = sumSubElements[i + 1];
exportObj[key] = value;
}
const exportJson = JSON.stringify(exportObj, null, 4);
/*
save to file and reload
*/
const exportJson = JSON.stringify(exportObj, null, 4);
return fs.write('/etc/adblock/adblock.custom.feeds', exportJson)
.then(() => location.reload());
}
return view.extend({
load: function () {
return L.resolveDefault(fs.stat('/etc/adblock/adblock.custom.feeds'), "")
return L.resolveDefault(fs.stat('/etc/adblock/adblock.custom.feeds'), null)
.then(function (stat) {
if (!stat) {
return fs.write('/etc/adblock/adblock.custom.feeds', "");
}
return L.resolveDefault(fs.read_direct('/etc/adblock/adblock.custom.feeds', 'json'), "");
});
if (!stat) {
return fs.write('/etc/adblock/adblock.custom.feeds', "").then(function () {
return { size: 0, data: null };
});
}
return L.resolveDefault(fs.read_direct('/etc/adblock/adblock.custom.feeds', 'json'), "")
.then(function (data) {
return { size: stat.size, data: data };
});
});
},
render: function (data) {
render: function (result) {
let m, s, o, feed, url, rule, size, descr;
const data = result.data;
fileSize = result.size;
m = new form.JSONMap(data, null, _('With this editor you can upload your local custom feed file or fill up an initial one (a 1:1 copy of the version shipped with the package). \
The file is located at \'/etc/adblock/adblock.custom.feeds\'. \
@@ -209,7 +211,7 @@ return view.extend({
if (!value) {
return true;
}
if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-\?\&\+_@%=:~#]+$/)) {
if (!value.match(/^https?:\/\/[A-Za-z0-9\[\]\/.\-?&+_@%=:~#]+$/)) {
return _('Protocol/URL format not supported');
}
return true;
@@ -219,7 +221,7 @@ return view.extend({
o.value('feed 1', _('<Domain>'));
o.value('feed 127.0.0.1 2', _('127.0.0.1 <Domain>'));
o.value('feed 0.0.0.0 2', _('0.0.0.0 <Domain>'));
o.value('feed 3 [|^]', _('<Adblock Plus Syntax>'));
o.value('feed || 3 [|^]', _('<Adblock Plus Syntax>'));
o.optional = true;
o.rmempty = true;
@@ -294,11 +296,11 @@ return view.extend({
return handleEdit('save');
})
}, [_('Save')]),
])
]);
});
return m.render();
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});
});

View File

@@ -12,37 +12,39 @@ function Logview(logtag, name) {
return L.view.extend({
load: () => Promise.resolve(),
render: () => {
L.Poll.add(() => {
render: function () {
const pollFn = () => {
return callLogRead(1000, false, true).then(res => {
const logEl = document.getElementById('logfile');
if (!logEl) return;
const filtered = (res?.log ?? [])
.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'
.filter(entry => !logtag || entry.msg.includes(logtag))
.map(entry => {
const d = new Date(entry.time * 1000);
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}`;
});
const time = d.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
return `[${date}-${time}] ${entry.msg}`;
});
if (filtered.length > 0) {
logEl.value = filtered.join('\n');
} else {
logEl.value = _('No %s related logs yet!').format(name);
}
logEl.value = filtered.length > 0
? filtered.join('\n')
: _('No %s related logs yet!').format(name);
logEl.scrollTop = logEl.scrollHeight;
});
});
};
this._pollFn = pollFn;
L.Poll.add(pollFn);
return E('div', { class: 'cbi-map' }, [
E('div', { class: 'cbi-section' }, [
@@ -58,10 +60,17 @@ function Logview(logtag, name) {
]);
},
unload: function () {
if (this._pollFn) {
L.Poll.remove(this._pollFn);
this._pollFn = null;
}
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});
}
return L.Class.extend({ Logview });
return L.Class.extend({ Logview });

View File

@@ -24,7 +24,7 @@ function handleAction(ev) {
btn.blur();
});
return fs.exec_direct('/etc/init.d/adblock', [ev]);
})
});
} else {
if (ev !== 'stop') {
document.querySelectorAll('.cbi-page-actions button').forEach(function (btn) {
@@ -49,6 +49,7 @@ return view.extend({
`https://${window.location.hostname}/cgi-bin/adblock`
]);
},
render: function (result) {
/*
config check
@@ -78,6 +79,7 @@ return view.extend({
/*
poll runtime information
*/
let parseErrCount = 0;
poll.add(function () {
return L.resolveDefault(fs.stat('/var/run/adb_runtime.json'), null).then(function (stat) {
if (!stat) {
@@ -89,15 +91,17 @@ return view.extend({
let info = null;
try {
info = JSON.parse(res);
parseErrCount = 0;
} catch (e) {
info = null;
parseErrCount++;
if (status) {
status.textContent = '-';
if (status.classList.contains('spinning')) {
buttons.forEach(function (btn) {
btn.disabled = false;
})
status.classList.remove('spinning');
buttons.forEach(function (btn) {
btn.disabled = false;
});
status.classList.remove('spinning');
if (parseErrCount >= 3) {
ui.addNotification(null, E('p', _('Unable to parse the adblock runtime information!')), 'error');
poll.stop();
}
@@ -110,7 +114,7 @@ return view.extend({
buttons.forEach(function (btn) {
btn.disabled = true;
btn.blur();
})
});
if (!status.classList.contains("spinning")) {
status.classList.add("spinning");
}
@@ -126,7 +130,7 @@ return view.extend({
}
buttons.forEach(function (btn) {
btn.disabled = false;
})
});
}
}
if (info) {
@@ -180,7 +184,7 @@ return view.extend({
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Last Run')),
E('div', { 'class': 'cbi-value-field', 'id': 'last', 'style': 'margin-bottom:- 5px; color:#37c; ' }, ' - ')
E('div', { 'class': 'cbi-value-field', 'id': 'last', 'style': 'margin-bottom:-5px;color:#37c;' }, '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('System Info')),
@@ -224,7 +228,7 @@ return view.extend({
o.rmempty = true;
o = s.taboption('general', form.Flag, 'adb_tld', _('TLD Compression'), _('The top level domain compression removes thousands of needless host entries from the final DNS blocklist.'));
o.default = 1
o.default = 1;
o.rmempty = true;
o = s.taboption('general', form.Flag, 'adb_safesearch', _('Enable SafeSearch'), _('Enforcing SafeSearch for google, bing, brave, duckduckgo, yandex, youtube and pixabay.'));
@@ -303,13 +307,13 @@ return view.extend({
o.rmempty = true;
o = s.taboption('additional', form.Flag, 'adb_fetchinsecure', _('Download Insecure'), _('Don\'t check SSL server certificates during download.'));
o.default = 0
o.default = 0;
o.rmempty = true;
/*
firewall settings tab
*/
o = s.taboption('firewall', form.DummyValue, '_sub');
o = s.taboption('firewall', form.DummyValue, '_fw_sub1');
o.rawhtml = true;
o.default = '<em style="color:#37c;font-weight:bold;">' + _('Changes on this tab needs an adblock service restart to take effect.') + '</em>'
+ '<hr style="width: 200px; height: 1px;" />'
@@ -357,7 +361,7 @@ return view.extend({
o.default = '2a13:1001::86:54:11:100';
o.rmempty = true;
o = s.taboption('firewall', form.DummyValue, '_sub');
o = s.taboption('firewall', form.DummyValue, '_fw_sub2');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('External Filtered DNS Policy (MAC-/Interfacebased DNS bypass)') + '</em>';
@@ -421,7 +425,7 @@ return view.extend({
o.default = '2a13:1001::86:54:11:13';
o.rmempty = true;
o = s.taboption('firewall', form.DummyValue, '_sub');
o = s.taboption('firewall', form.DummyValue, '_fw_sub3');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('External Remote DNS Policy (temporary MACbased remote DNS bypass)') + '</em>';
@@ -481,12 +485,12 @@ return view.extend({
blackColor: 'black'
};
const svg = uqr.renderSVG(url, options);
o = s.taboption('firewall', form.DummyValue, '_sub', _('QRCode for Remote Access'));
o = s.taboption('firewall', form.DummyValue, '_fw_qr', _('QRCode for Remote Access'));
o.rawhtml = true;
o.default = svg;
}
o = s.taboption('firewall', form.DummyValue, '_sub');
o = s.taboption('firewall', form.DummyValue, '_fw_sub4');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('External DNS Bridge (ZeroDowntime during DNS Restarts)') + '</em>';
@@ -547,7 +551,7 @@ return view.extend({
o.default = '2a13:1001::86:54:11:13';
o.rmempty = true;
o = s.taboption('firewall', form.DummyValue, '_sub');
o = s.taboption('firewall', form.DummyValue, '_fw_sub5');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('Local DNS Enforcement') + '</em>';
@@ -721,12 +725,9 @@ return view.extend({
/*
prepare category data
*/
var code, category, list, path, categories = [];
if (result[2]) {
categories = result[2].trim().split('\n');
}
const categories = result[2] ? result[2].trim().split('\n') : [];
o = s.taboption('feeds', form.DummyValue, '_sub');
o = s.taboption('feeds', form.DummyValue, '_feeds1');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('1Hosts List Selection') + '</em>';
@@ -734,19 +735,14 @@ return view.extend({
for (let i = 0; i < categories.length; i++) {
const cat = categories[i].match(/^(\w+);(.*?);(.*)$/);
if (!cat) continue;
const code = cat[1].trim();
const list = cat[2].trim();
const path = cat[3].trim();
if (code === 'hst') {
o.value(path, list);
if (cat[1].trim() === 'hst') {
o.value(cat[3].trim(), cat[2].trim());
}
}
o.optional = true;
o.rmempty = true;
o = s.taboption('feeds', form.DummyValue, '_sub');
o = s.taboption('feeds', form.DummyValue, '_feeds2');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('Hagezi List Selection') + '</em>';
@@ -754,19 +750,14 @@ return view.extend({
for (let i = 0; i < categories.length; i++) {
const cat = categories[i].match(/^(\w+);(.*?);(.*)$/);
if (!cat) continue;
const code = cat[1].trim();
const list = cat[2].trim();
const path = cat[3].trim();
if (code === 'hag') {
o.value(path, list);
if (cat[1].trim() === 'hag') {
o.value(cat[3].trim(), cat[2].trim());
}
}
o.optional = true;
o.rmempty = true;
o = s.taboption('feeds', form.DummyValue, '_sub');
o = s.taboption('feeds', form.DummyValue, '_feeds3');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('IPFire List Selection') + '</em>';
@@ -774,19 +765,14 @@ return view.extend({
for (let i = 0; i < categories.length; i++) {
const cat = categories[i].match(/^(\w+);(.*?);(.*)$/);
if (!cat) continue;
const code = cat[1].trim();
const list = cat[2].trim();
const path = cat[3].trim();
if (code === 'ipf') {
o.value(path, list);
if (cat[1].trim() === 'ipf') {
o.value(cat[3].trim(), cat[2].trim());
}
}
o.optional = true;
o.rmempty = true;
o = s.taboption('feeds', form.DummyValue, '_sub');
o = s.taboption('feeds', form.DummyValue, '_feeds4');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('StevenBlack List Selection') + '</em>';
@@ -794,19 +780,14 @@ return view.extend({
for (let i = 0; i < categories.length; i++) {
const cat = categories[i].match(/^(\w+);(.*?);(.*)$/);
if (!cat) continue;
const code = cat[1].trim();
const list = cat[2].trim();
const path = cat[3].trim();
if (code === 'stb') {
o.value(path, list);
if (cat[1].trim() === 'stb') {
o.value(cat[3].trim(), cat[2].trim());
}
}
o.optional = true;
o.rmempty = true;
o = s.taboption('feeds', form.DummyValue, '_sub');
o = s.taboption('feeds', form.DummyValue, '_feeds5');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('UTCapitole Archive Selection') + '</em>';
@@ -814,12 +795,8 @@ return view.extend({
for (let i = 0; i < categories.length; i++) {
const cat = categories[i].match(/^(\w+);(.*)$/);
if (!cat) continue;
const code = cat[1].trim();
const category = cat[2].trim();
if (code === 'utc') {
o.value(category);
if (cat[1].trim() === 'utc') {
o.value(cat[2].trim());
}
}
o.optional = true;
@@ -861,14 +838,14 @@ return view.extend({
'style': 'float:none',
'title': 'Save & Restart',
'click': function () {
handleAction('restart');
return handleAction('restart');
}
}, [_('Save & Restart')])
])
]);
});
return m.render();
},
handleSaveApply: null,
handleSave: null,
handleReset: null
});
});