diff options
author | Dirk Brenken <dev@brenken.org> | 2020-03-28 14:35:10 +0100 |
---|---|---|
committer | Dirk Brenken <dev@brenken.org> | 2020-03-28 14:35:10 +0100 |
commit | 0f18b873d893a30564a2684e0dcc7f4fb68ed296 (patch) | |
tree | ad80bf79f72e4a9935bcd74266afd4074d038ef9 /applications/luci-app-adblock/htdocs/luci-static/resources | |
parent | 0adf93de3b78fae8a19843906852abad6c7855ae (diff) |
luci-app-adblock: release 4.0.0
* complete rewrite, migrated to client side JS
* tested with mainline 19.07 and current master
* tested with latest Firefox & Chrome and all
standard themes (not OpenWrt2020!)
Pre-tested by many forum users, see here:
https://forum.openwrt.org/t/adblock-4-pre-releases/57101
* sync translations
Signed-off-by: Dirk Brenken <dev@brenken.org>
Diffstat (limited to 'applications/luci-app-adblock/htdocs/luci-static/resources')
5 files changed, 934 insertions, 0 deletions
diff --git a/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/blacklist.js b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/blacklist.js new file mode 100644 index 000000000..7e053c619 --- /dev/null +++ b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/blacklist.js @@ -0,0 +1,35 @@ +'use strict'; +'require fs'; +'require ui'; + +return L.view.extend({ + load: function() { + return L.resolveDefault(fs.read_direct('/etc/adblock/adblock.blacklist'), ''); + }, + handleSave: function(ev) { + var value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n').replace(/[^a-z0-9\.\-\#\n]/g, '')) + '\n'; + return fs.write('/etc/adblock/adblock.blacklist', value) + .then(function(rc) { + document.querySelector('textarea').value = value; + ui.addNotification(null, E('p', _('Blacklist changes have been saved. Refresh your adblock lists that changes take effect.')), 'info'); + }).catch(function(e) { + ui.addNotification(null, E('p', _('Unable to save changes: %s').format(e.message))); + }); + }, + render: function(blacklist) { + return E([ + E('p', {}, + _('This is the local adblock blacklist to always-deny certain (sub) domains.<br /> \ + Please note: add only one domain per line. Comments introduced with \'#\' are allowed - ip addresses, wildcards and regex are not.')), + E('p', {}, + E('textarea', { + 'style': 'width: 100% !important; padding: 5px; font-family: monospace', + 'wrap': 'off', + 'rows': 25 + }, [ blacklist != null ? blacklist : '' ]) + ) + ]); + }, + handleSaveApply: null, + handleReset: null +}); diff --git a/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/dnsreport.js b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/dnsreport.js new file mode 100644 index 000000000..370a6906c --- /dev/null +++ b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/dnsreport.js @@ -0,0 +1,339 @@ +'use strict'; +'require fs'; +'require ui'; + +/* + button handling +*/ +function handleAction(ev) { + if (ev.target && ev.target.getAttribute('name') === 'blacklist') { + L.ui.showModal(_('Add Blacklist Domain'), [ + E('p', {}, _('Add this (sub-)domain to your local blacklist.')), + E('div', { 'class': 'left' }, [ + E('label', { 'class': 'cbi-input-text', 'style': 'float:left; padding-top:.5em' }, [ + E('input', { 'class': 'cbi-input-text', 'style': 'width:300px', 'id': 'blacklist', 'value': ev.target.getAttribute('value') }, []) + ]) + ]), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn', + 'click': L.hideModal + }, _('Cancel')), + ' ', + E('button', { + 'class': 'btn cbi-button-action', + 'click': ui.createHandlerFn(this, function(ev) { + L.resolveDefault(fs.read_direct('/etc/adblock/adblock.blacklist'), '') + .then(function(res) { + var domain = document.getElementById('blacklist').value.trim().toLowerCase().replace(/[^a-z0-9\.\-]/g,''); + var pattern = new RegExp('^' + domain.replace(/[\.]/g,'\\.') + '$', 'm'); + if (res.search(pattern) === -1) { + var blacklist = res + domain + '\n'; + fs.write('/etc/adblock/adblock.blacklist', blacklist); + ui.addNotification(null, E('p', _('Blacklist changes have been saved. Refresh your adblock lists that changes take effect.')), 'info'); + } + L.hideModal(); + }); + }) + }, _('Save')) + ]) + ]); + document.getElementById('blacklist').focus(); + } + + if (ev.target && ev.target.getAttribute('name') === 'whitelist') { + L.ui.showModal(_('Add Whitelist Domain'), [ + E('p', {}, _('Add this (sub-)domain to your local whitelist.')), + E('div', { 'class': 'left' }, [ + E('label', { 'class': 'cbi-input-text', 'style': 'float:left; padding-top:.5em' }, [ + E('input', { 'class': 'cbi-input-text', 'style': 'width:300px', 'id': 'whitelist', 'value': ev.target.getAttribute('value') }, []) + ]) + ]), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn', + 'click': L.hideModal + }, _('Cancel')), + ' ', + E('button', { + 'class': 'btn cbi-button-action', + 'click': ui.createHandlerFn(this, function(ev) { + L.resolveDefault(fs.read_direct('/etc/adblock/adblock.whitelist'), '') + .then(function(res) { + var domain = document.getElementById('whitelist').value.trim().toLowerCase().replace(/[^a-z0-9\.\-]/g,''); + var pattern = new RegExp('^' + domain.replace(/[\.]/g,'\\.') + '$', 'm'); + if (res.search(pattern) === -1) { + var whitelist = res + domain + '\n'; + fs.write('/etc/adblock/adblock.whitelist', whitelist); + ui.addNotification(null, E('p', _('Whitelist changes have been saved. Refresh your adblock lists that changes take effect.')), 'info'); + } + L.hideModal(); + }); + }) + }, _('Save')) + ]) + ]); + document.getElementById('whitelist').focus(); + } + + if (ev === 'query') { + L.ui.showModal(_('Blocklist Query'), [ + E('p', {}, _('Query active blocklists and backups for a specific domain.')), + E('div', { 'class': 'left' }, [ + E('label', { 'style': 'float:left; padding-top:.5em', 'id': 'run' }, [ + E('input', { + 'class': 'cbi-input-text', + 'placeholder': 'google.com', + 'style': 'width:300px', + 'id': 'search' + }) + ]) + ]), + E('div', { 'class': 'left' }, [ + E('h5', _('Result')), + E('textarea', { + 'id': 'result', + 'style': 'width: 100% !important; padding: 5px; font-family: monospace', + 'readonly': 'readonly', + 'wrap': 'off', + 'rows': 20 + }) + ]), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn', + 'click': L.hideModal + }, _('Cancel')), + ' ', + 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,''); + 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'); + if (res) { + result.textContent = res.trim(); + } else { + result.textContent = _('No Query results!'); + } + document.getElementById('run').classList.remove("spinning"); + document.getElementById('search').value = ''; + }) + } + document.getElementById('search').focus(); + }) + }, _('Query')) + ]) + ]); + document.getElementById('search').focus(); + } + + if (ev === 'refresh') { + L.ui.showModal(_('Refresh DNS Report'), [ + E('div', { 'class': 'left' }, [ + E('select', { 'class': 'cbi-input-select', 'id': 'count' }, [ + E('option', { 'value': '50' }, '50'), + E('option', { 'value': '100' }, '100'), + E('option', { 'value': '150' }, '150'), + E('option', { 'value': '250' }, '250'), + E('option', { 'value': '500' }, '500') + ]), + '\xa0\xa0\xa0', + _('max. result set size') + ]), + E('label', { 'class': 'cbi-input-text', 'style': 'float:left; padding-top:.5em' }, [ + E('input', { 'class': 'cbi-input-text', 'id': 'search' }, [ + ]), + '\xa0\xa0\xa0', + _('Filter criteria like date, domain or client (optional)') + ]), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn', + 'click': L.hideModal + }, _('Cancel')), + ' ', + E('button', { + 'class': 'btn cbi-button-action', + 'id': 'refresh', + 'click': ui.createHandlerFn(this, async function(ev) { + var count = document.getElementById('count').value + var search = document.getElementById('search').value.trim().replace(/[^a-z0-9\.\-]/g,'') || '+'; + L.resolveDefault(fs.exec_direct('/etc/init.d/adblock', ['report', search, count, 'true', 'json']),''); + var running = 1; + while (running === 1) { + await new Promise(r => setTimeout(r, 1000)); + L.resolveDefault(fs.read_direct('/var/run/adblock.pid')).then(function(res) { + if (!res) { + running = 0; + } + }) + } + L.hideModal(); + location.reload(); + }) + }, _('Refresh')) + ]) + ]); + document.getElementById('refresh').focus(); + } +} + +return L.view.extend({ + load: function() { + return L.resolveDefault(fs.exec_direct('/etc/init.d/adblock', ['report', '+', '50', 'false', 'json']),''); + }, + + render: function(dnsreport) { + if (!dnsreport) { + dnsreport = '{ "data": "" }'; + }; + var content; + content = JSON.parse(dnsreport); + + var rows_top = []; + var tbl_top = E('div', { 'class': 'table', 'id': 'top_10' }, [ + E('div', { 'class': 'tr table-titles' }, [ + E('div', { 'class': 'th right' }, _('Count')), + E('div', { 'class': 'th' }, _('Name / IP Address')), + E('div', { 'class': 'th right' }, _('Count')), + E('div', { 'class': 'th' }, _('Domain')), + E('div', { 'class': 'th right' }, _('Count')), + E('div', { 'class': 'th' }, _('Blocked Domain')) + ]) + ]); + + var max = 0; + if (content.data.top_clients && content.data.top_domains && content.data.top_blocked) { + max = Math.max(content.data.top_clients.length, content.data.top_domains.length, content.data.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'; + if (content.data.top_clients[i]) { + a_cnt = content.data.top_clients[i].count; + } + if (content.data.top_clients[i]) { + a_addr = content.data.top_clients[i].address; + } + if (content.data.top_domains[i]) { + b_cnt = content.data.top_domains[i].count; + } + if (content.data.top_domains[i]) { + b_addr = content.data.top_domains[i].address; + } + if (content.data.top_blocked[i]) { + c_cnt = content.data.top_blocked[i].count; + } + if (content.data.top_blocked[i]) { + c_addr = content.data.top_blocked[i].address; + } + rows_top.push([ + a_cnt, + a_addr, + b_cnt, + b_addr, + c_cnt, + c_addr + ]); + } + cbi_update_table(tbl_top, rows_top); + + var rows_requests = []; + var tbl_requests = E('div', { 'class': 'table', 'id': 'requests' }, [ + E('div', { 'class': 'tr table-titles' }, [ + E('div', { 'class': 'th' }, _('Date')), + E('div', { 'class': 'th' }, _('Time')), + E('div', { 'class': 'th' }, _('Client')), + E('div', { 'class': 'th' }, _('Domain')), + E('div', { 'class': 'th' }, _('Answer')), + E('div', { 'class': 'th' }, _('Action')) + ]) + ]); + + max = 0; + if (content.data.requests) { + var button; + max = content.data.requests.length; + for (var i = 0; i < max; i++) { + if (content.data.requests[i].rc === 'NX') { + button = E('button', { + 'class': 'cbi-button cbi-button-apply', + 'style': 'word-break: inherit', + 'name': 'whitelist', + 'value': content.data.requests[i].domain, + 'click': handleAction + }, [ _('Whitelist...') ]); + } else { + button = E('button', { + 'class': 'cbi-button cbi-button-apply', + 'style': 'word-break: inherit', + 'name': 'blacklist', + 'value': content.data.requests[i].domain, + 'click': handleAction + }, [ _('Blacklist...') ]); + } + rows_requests.push([ + content.data.requests[i].date, + content.data.requests[i].time, + content.data.requests[i].client, + content.data.requests[i].domain, + content.data.requests[i].rc, + button + ]); + } + } + cbi_update_table(tbl_requests, rows_requests); + + return E('div', { 'class': 'cbi-map', 'id': 'map' }, [ + E('div', { 'class': 'cbi-section' }, [ + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Start Date')), + E('div', { 'class': 'cbi-value-field', 'id': 'start', 'style': 'margin-bottom:5px;margin-left:200px;color:#37c' }, (content.data.start_date || '-') + ', ' + (content.data.start_time || '-'))]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('End Date')), + E('div', { 'class': 'cbi-value-field', 'id': 'end', 'style': 'margin-bottom:5px;margin-left:200px;color:#37c' }, (content.data.end_date || '-') + ', ' + (content.data.end_time || '-'))]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('DNS Requests (total)')), + E('div', { 'class': 'cbi-value-field', 'id': 'total', 'style': 'margin-bottom:5px;margin-left:200px;color:#37c' }, content.data.total || '-')]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('DNS Requests (blocked)')), + E('div', { 'class': 'cbi-value-field', 'id': 'blocked', 'style': 'margin-bottom:5px;margin-left:200px;color:#37c' }, (content.data.blocked || '-') + ' (' + (content.data.percent || '-') + ')')]), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': ui.createHandlerFn(this, function() { + return handleAction('query'); + }) + }, [ _('Blocklist Query...') ]), + '\xa0\xa0\xa0', + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': ui.createHandlerFn(this, function() { + return handleAction('refresh'); + }) + }, [ _('Refresh...') ]) + ]), + ]), + E('div', { 'class': 'cbi-section' }, [ + E('div', { 'class': 'left' }, [ + E('h3', _('Top 10 Statistics')), + tbl_top + ]) + ]), + E('br'), + E('div', { 'class': 'cbi-section' }, [ + E('div', { 'class': 'left' }, [ + E('h3', _('Latest DNS Requests')), + tbl_requests + ]) + ]) + ]); + }, + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/logread.js b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/logread.js new file mode 100644 index 000000000..64f23b14c --- /dev/null +++ b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/logread.js @@ -0,0 +1,39 @@ +'use strict'; +'require fs'; + +return L.view.extend({ + load: function() { + return Promise.all([ + L.resolveDefault(fs.stat('/sbin/logread'), null), + L.resolveDefault(fs.stat('/usr/sbin/logread'), null) + ]); + }, + render: function(stat) { + var logger = stat[0] ? stat[0].path : stat[1] ? stat[1].path : null; + L.Poll.add(function() { + return L.resolveDefault(fs.exec_direct(logger, ['-e', 'adblock-'])).then(function(res) { + var log = document.getElementById("logfile"); + if (res) { + log.value = res.trim(); + } else { + log.value = _('No adblock related logs yet!'); + } + log.scrollTop = log.scrollHeight; + }); + }); + return E('div', { class: 'cbi-map' }, + E('div', { class: 'cbi-section' }, [ + E('div', { class: 'cbi-section-descr' }, _('The syslog output, pre-filtered for adblock related messages only.')), + E('textarea', { + 'id': 'logfile', + 'style': 'width: 100% !important; padding: 5px; font-family: monospace', + 'readonly': 'readonly', + 'wrap': 'off', + 'rows': 25 + }) + ])); + }, + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/overview.js b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/overview.js new file mode 100644 index 000000000..f5b7319cd --- /dev/null +++ b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/overview.js @@ -0,0 +1,486 @@ +'use strict'; +'require fs'; +'require ui'; +'require uci'; +'require form'; +'require tools.widgets as widgets'; + +/* + button handling +*/ +async function handleAction(ev) { + if (ev === 'timer') { + L.ui.showModal(_('Refresh Timer'), [ + E('p', {}, _('To keep your adblock lists up-to-date, you should setup an automatic update job for these lists.')), + E('div', { 'class': 'left' }, [ + E('h5', _('Existing job(s)')), + E('textarea', { + 'id': 'cronView', + 'style': 'width: 100% !important; padding: 5px; font-family: monospace', + 'readonly': 'readonly', + 'wrap': 'off', + 'rows': 5 + }) + ]), + E('div', { 'class': 'left' }, [ + E('label', { 'class': 'cbi-input-select', 'style': 'float:left; padding-top:.5em' }, [ + E('h5', _('Set/Replace a new adblock job')), + E('select', { 'class': 'cbi-input-select', 'id': 'timerA' }, [ + E('option', { 'value': 'start' }, 'Start'), + E('option', { 'value': 'reload' }, 'Reload'), + E('option', { 'value': 'restart' }, 'Restart') + ]), + '\xa0\xa0\xa0', + _('Adblock action') + ]), + E('label', { 'class': 'cbi-input-text', 'style': 'float:left; padding-top:.5em' }, [ + E('input', { 'class': 'cbi-input-text', 'id': 'timerH', 'maxlength': '2' }, [ + ]), + '\xa0\xa0\xa0', + _('The hours portition (req., range: 0-23)') + ]), + E('label', { 'class': 'cbi-input-text', 'style': 'float:left; padding-top:.5em' }, [ + E('input', { 'class': 'cbi-input-text', 'id': 'timerM', 'maxlength': '2' }), + '\xa0\xa0\xa0', + _('The minutes portion (opt., range: 0-59)') + ]), + E('label', { 'class': 'cbi-input-text', 'style': 'float:left; padding-top:.5em' }, [ + E('input', { 'class': 'cbi-input-text', 'id': 'timerD', 'maxlength': '13' }), + '\xa0\xa0\xa0', + _('The day of the week (opt., values: 1-7 possibly sep. by , or -)') + ]) + ]), + E('div', { 'class': 'right' }, [ + E('button', { + 'class': 'btn', + 'click': L.hideModal + }, _('Cancel')), + ' ', + E('button', { + 'class': 'btn cbi-button-action', + 'click': ui.createHandlerFn(this, function(ev) { + var action = document.getElementById('timerA').value; + var hours = document.getElementById('timerH').value; + var minutes = document.getElementById('timerM').value || '0'; + var days = document.getElementById('timerD').value || '*'; + if (hours) { + L.resolveDefault(fs.exec_direct('/etc/init.d/adblock', ['timer', action, hours, minutes, days])) + .then(function(res) { + if (res) { + ui.addNotification(null, E('p', _('The Refresh Timer could not been updated.')), 'error'); + } else { + ui.addNotification(null, E('p', _('The Refresh Timer has been updated.')), 'info'); + } + }); + } else { + document.getElementById('timerH').focus(); + return + } + L.hideModal(); + }) + }, _('Save')) + ]) + ]); + L.resolveDefault(fs.read_direct('/etc/crontabs/root'), ' ') + .then(function(res) { + document.getElementById('cronView').value = res.trim(); + }); + document.getElementById('timerH').focus(); + return + } + + if (ev === 'suspend') { + if (document.getElementById('status') && document.getElementById('btn_suspend') && document.getElementById('status').textContent.substr(0,6) === 'paused') { + document.querySelector('#btn_suspend').textContent = 'Suspend'; + ev = 'resume'; + } else if (document.getElementById('status') && document.getElementById('btn_suspend')) { + document.querySelector('#btn_suspend').textContent = 'Resume'; + } + } + + L.Poll.start(); + fs.exec_direct('/etc/init.d/adblock', [ev]) + var running = 1; + while (running === 1) { + await new Promise(r => setTimeout(r, 1000)); + L.resolveDefault(fs.read_direct('/var/run/adblock.pid')).then(function(res) { + if (!res) { + running = 0; + } + }) + } + L.Poll.stop(); +} + +return L.view.extend({ + load: function() { + return Promise.all([ + L.resolveDefault(fs.exec_direct('/etc/init.d/adblock', ['list']), {}), + uci.load('adblock') + ]); + }, + + render: function(result) { + var m, s, o; + + 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>')); + + /* + poll runtime information + */ + pollData: L.Poll.add(function() { + return L.resolveDefault(fs.read_direct('/tmp/adb_runtime.json'), 'null').then(function(res) { + var info = JSON.parse(res); + var status = document.getElementById('status'); + if (status && info) { + status.textContent = (info.data.adblock_status || '-') + ' / ' + (info.data.adblock_version || '-'); + if (info.data.adblock_status === "running") { + if (!status.classList.contains("spinning")) { + status.classList.add("spinning"); + } + } else { + if (status.classList.contains("spinning")) { + status.classList.remove("spinning"); + L.Poll.stop(); + } + } + if (status.textContent.substr(0,6) === 'paused' && document.getElementById('btn_suspend')) { + document.querySelector('#btn_suspend').textContent = 'Resume'; + } + } else if (status) { + status.textContent = '-'; + if (status.classList.contains("spinning")) { + status.classList.remove("spinning"); + } + } + var domains = document.getElementById('domains'); + if (domains && info) { + domains.textContent = parseInt(info.data.blocked_domains, 10).toLocaleString() || '-'; + } + var sources = document.getElementById('sources'); + var src_array = []; + if (sources && info) { + for (var i = 0; i < info.data.active_sources.length; i++) { + if (i < info.data.active_sources.length-1) { + src_array += info.data.active_sources[i].source + ', '; + } else { + src_array += info.data.active_sources[i].source + } + } + sources.textContent = src_array || '-'; + } + var backend = document.getElementById('backend'); + if (backend && info) { + backend.textContent = info.data.dns_backend || '-'; + } + var utils = document.getElementById('utils'); + if (utils && info) { + utils.textContent = info.data.run_utils || '-'; + } + var ifaces = document.getElementById('ifaces'); + if (ifaces && info) { + ifaces.textContent = info.data.run_ifaces || '-'; + } + var dirs = document.getElementById('dirs'); + if (dirs && info) { + dirs.textContent = info.data.run_directories || '-'; + } + var flags = document.getElementById('flags'); + if (flags && info) { + flags.textContent = info.data.run_flags || '-'; + } + var run = document.getElementById('run'); + if (run && info) { + run.textContent = info.data.last_run || '-'; + } + }); + }, 1); + + /* + runtime information and buttons + */ + s = m.section(form.NamedSection, 'global'); + s.render = L.bind(function(view, section_id) { + return E('div', { 'class': 'cbi-section' }, [ + E('h3', _('Information')), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Status / Version')), + E('div', { 'class': 'cbi-value-field spinning', 'id': 'status', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'\xa0')]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Blocked Domains')), + E('div', { 'class': 'cbi-value-field', 'id': 'domains', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Active Sources')), + E('div', { 'class': 'cbi-value-field', 'id': 'sources', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('DNS Backend')), + E('div', { 'class': 'cbi-value-field', 'id': 'backend', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Utils')), + E('div', { 'class': 'cbi-value-field', 'id': 'utils', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Interfaces')), + E('div', { 'class': 'cbi-value-field', 'id': 'ifaces', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Directories')), + E('div', { 'class': 'cbi-value-field', 'id': 'dirs', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Run Flags')), + E('div', { 'class': 'cbi-value-field', 'id': 'flags', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), + E('div', { 'class': 'cbi-value', 'style': 'margin-bottom:5px' }, [ + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Last Run')), + E('div', { 'class': 'cbi-value-field', 'id': 'run', 'style': 'font-weight: bold;margin-bottom:5px;color:#37c' },'-')]), + E('div', { class: 'right' }, [ + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': ui.createHandlerFn(this, function() { + return handleAction('timer'); + }) + }, [ _('Refresh Timer...') ]), + '\xa0\xa0\xa0', + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'id': 'btn_suspend', + 'click': ui.createHandlerFn(this, function() { + return handleAction('suspend'); + }) + }, [ _('Suspend') ]), + '\xa0\xa0\xa0', + E('button', { + 'class': 'cbi-button cbi-button-apply', + 'click': ui.createHandlerFn(this, function() { + return handleAction('start'); + }) + }, [ _('Refresh') ]) + ]) + ]); + }, o, this); + this.pollData; + + /* + tabbed config section + */ + s = m.section(form.NamedSection, 'global', 'adblock', _('Settings')); + s.addremove = false; + s.tab('general', _('General Settings')); + s.tab('additional', _('Additional Settings')); + s.tab('adv_dns', _('Advanced DNS Settings')); + s.tab('adv_report', _('Advanced Report Settings')); + s.tab('adv_email', _('Advanced E-Mail Settings')); + s.tab('sources', _('Blocklist Sources'), _('List of supported and fully pre-configured adblock sources, already active sources are pre-selected.<br /> \ + <b><em>To avoid OOM errors, please do not select too many lists!</em></b><br /> \ + List size information with the respective domain ranges as follows:<br /> \ + • <b>S</b> (-10k), <b>M</b> (10k-30k) and <b>L</b> (30k-80k) should work for 128 MByte devices,<br /> \ + • <b>XL</b> (80k-200k) should work for 256-512 MByte devices,<br /> \ + • <b>XXL</b> (200k-) needs more RAM and Multicore support, e.g. x86 or raspberry devices.<br /> \ + <p> </p>')); + + /* + general settings tab + */ + o = s.taboption('general', form.Flag, 'adb_enabled', _('Enabled'), _('Enable the adblock service.')); + o.rmempty = false; + + o = s.taboption('general', widgets.NetworkSelect, 'adb_trigger', _('Startup Trigger Interface'), _('List of available network interfaces to trigger the adblock start. \ + Choose \'unspecified\' to use a classic startup timeout instead of a network trigger.')); + o.unspecified = true; + o.nocreate = true; + o.rmempty = true; + + o = s.taboption('general', form.Flag, 'adb_forcedns', _('Force Local DNS'), _('Redirect all DNS queries from \'lan\' zone to the local DNS resolver, applies to UDP and TCP protocol.')); + o.rmempty = false; + + o = s.taboption('general', form.Value, 'adb_portlist', _('Local DNS Ports'), _('Space separated list of DNS-related firewall ports which should be forced locally.')); + o.depends('adb_forcedns', '1'); + o.placeholder = '53 853 5353'; + o.rmempty = true; + + o = s.taboption('general', form.Flag, 'adb_safesearch', _('Enable SafeSearch'), _('Enforcing SafeSearch for google, bing, duckduckgo, yandex, youtube and pixabay.')); + o.rmempty = false; + + o = s.taboption('general', form.Flag, 'adb_safesearchmod', _('SafeSearch Moderate'), _('Enable moderate SafeSearch filters for youtube.')); + o.depends('adb_safesearch', '1'); + o.rmempty = true; + + o = s.taboption('general', form.Flag, 'adb_report', _('DNS Report'), _('Gather DNS related network traffic via tcpdump and provide a DNS Report on demand. \ + Please note: this needs additional \'tcpdump-mini\' package installation and a full adblock service restart to take effect.')); + o.rmempty = false; + + o = s.taboption('general', form.Flag, 'adb_mail', _('E-Mail Notification'), _('Send adblock related notification e-mails. \ + Please note: this needs additional \'msmtp\' package installation.')); + o.rmempty = false; + + o = s.taboption('general', form.Value, 'adb_mailreceiver', _('E-Mail Receiver Address'), _('Receiver address for adblock notification e-mails.')); + o.depends('adb_mail', '1'); + o.placeholder = 'name@example.com'; + o.rmempty = true; + + /* + additional settings tab + */ + o = s.taboption('additional', form.Flag, 'adb_debug', _('Verbose Debug Logging'), _('Enable verbose debug logging in case of any processing errors.')); + o.rmempty = false; + + o = s.taboption('additional', form.Flag, 'adb_nice', _('Low Priority Service'), _('Reduce the priority of the adblock background processing to take fewer resources from the system. \ + Please note: This change requires a full adblock service restart to take effect.')); + o.enabled = '10'; + o.rmempty = true; + + o = s.taboption('additional', form.Value, 'adb_triggerdelay', _('Trigger Delay'), _('Additional trigger delay in seconds before adblock processing begins.')); + o.placeholder = '2'; + o.datatype = 'range(1,120)'; + o.rmempty = true; + + o = s.taboption('additional', form.ListValue, 'adb_maxqueue', _('Download Queue'), _('Size of the download queue for download processing (incl. sorting, merging etc.) in parallel.')); + o.value('4'); + o.value('8'); + o.value('16'); + o.value('32'); + o.rmempty = false; + + o = s.taboption('additional', form.Value, 'adb_tmpbase', _('Base Temp Directory'), _('Base Temp Directory for all adblock related runtime operations, \ + e.g. downloading, sorting, merging etc.')); + o.placeholder = '/tmp'; + o.rmempty = true; + + o = s.taboption('additional', form.Flag, 'adb_backup', _('Blocklist Backup'), _('Create compressed blocklist backups, they will be used in case of download errors or during startup.')); + o.default = 1 + o.rmempty = false; + + o = s.taboption('additional', form.Value, 'adb_backupdir', _('Backup Directory'), _('Target directory for blocklist backups. \ + Default is \'/tmp\', please use preferably an usb stick or another local disk.')); + o.depends('adb_backup', '1'); + o.placeholder = '/tmp'; + o.rmempty = true; + + o = s.taboption('additional', form.ListValue, 'adb_fetchutil', _('Download Utility'), _('List of supported and fully pre-configured download utilities.')); + o.value('uclient-fetch'); + o.value('wget'); + o.value('curl'); + o.value('aria2c'); + o.rmempty = false; + + o = s.taboption('additional', form.Value, 'adb_fetchparm', _('Download Parameters'), _('Special config options for the selected download utility.')) + o.value('--timeout=20 -O'); + o.value('--connect-timeout 20 --silent --show-error --location -o'); + o.value('--no-cache --no-cookies --max-redirect=0 --timeout=20 -O'); + o.value('--timeout=20 --allow-overwrite=true --auto-file-renaming=false --check-certificate=true --dir=" " -o'); + o.default = false; + o.rmempty = true; + + /* + advanced dns settings tab + */ + o = s.taboption('adv_dns', form.ListValue, 'adb_dns', _('DNS Backend'), _('List of supported DNS backends with their default list directory. \ + To overwrite the default path use the \'DNS Directory\' option.')); + o.value('dnsmasq', _('dnsmasq (/tmp/dnsmasq.d)')); + o.value('unbound', _('unbound (/var/lib/unbound)')); + o.value('named', _('named (/var/lib/bind)')); + o.value('kresd', _('kresd (/etc/kresd)')); + o.value('raw', _('raw (/tmp)')); + o.rmempty = false; + + o = s.taboption('adv_dns', form.Value, 'adb_dnsdir', _('DNS Directory'), _('Target directory for the generated blocklist \'adb_list.overall\'.')); + o.placeholder = '/tmp'; + o.rmempty = true; + + o = s.taboption('adv_dns', form.Value, 'adb_dnstimeout', _('DNS Restart Timeout'), _('Timeout to wait for a successful DNS backend restart.')); + o.placeholder = '20'; + o.datatype = 'range(1,60)'; + o.rmempty = true; + + o = s.taboption('adv_dns', form.Value, 'adb_lookupdomain', _('External DNS Lookup Domain'), _('External domain to check for a successful DNS backend restart. \ + Please note: To disable this check set this option to \'false\'.')); + o.placeholder = 'example.com'; + o.rmempty = true; + + o = s.taboption('adv_dns', form.Flag, 'adb_dnsfilereset', _('DNS File Reset'), _('Resets the final DNS blocklist \'adb_list.overall\' after DNS backend loading. \ + Please note: This option starts a small ubus/adblock monitor in the background.')); + o.rmempty = false; + + o = s.taboption('adv_dns', form.Flag, 'adb_dnsflush', _('Flush DNS Cache'), _('Flush the DNS Cache before adblock processing as well.')); + o.rmempty = true; + + o = s.taboption('adv_dns', form.Flag, 'adb_dnsallow', _('Disable DNS Allow'), _('Disable selective DNS whitelisting (RPZ pass through).')); + o.rmempty = true; + + o = s.taboption('adv_dns', form.Flag, 'adb_jail', _('Additional Jail Blocklist'), _('Builds an additional DNS blocklist to block access to all domains except those listed in the whitelist. \ + Please note: You can use this restrictive blocklist e.g. for guest wifi or kidsafe configurations.')); + o.rmempty = true; + + o = s.taboption('adv_dns', form.Value, 'adb_jaildir', _('Jail Directory'), _('Target directory for the generated jail blocklist \'adb_list.jail\'.')); + o.depends('adb_jail', '1'); + o.placeholder = '/tmp'; + o.rmempty = true; + + o = s.taboption('adv_dns', form.Flag, 'adb_dnsinotify', _('Disable DNS Restarts'), _('Disable adblock triggered restarts for dns backends with autoload/inotify functions.')); + o.depends('adb_dnsflush', '0'); + o.rmempty = true; + + /* + advanced report settings tab + */ + o = s.taboption('adv_report', widgets.DeviceSelect, 'adb_repiface', _('Report Interface'), _('List of available network devices used by tcpdump.')); + o.unspecified = true; + o.nocreate = false; + o.rmempty = true; + + o = s.taboption('adv_report', form.Value, 'adb_reportdir', _('Report Directory'), _('Target directory for DNS related report files. \ + Default is \'/tmp\', please use preferably an usb stick or another local disk.')); + o.placeholder = '/tmp'; + o.rmempty = true; + + o = s.taboption('adv_report', form.Value, 'adb_repchunkcnt', _('Report Chunk Count'), _('Report chunk count used by tcpdump.')); + o.placeholder = '5'; + o.datatype = 'range(1,10)'; + o.rmempty = true; + + o = s.taboption('adv_report', form.Value, 'adb_repchunksize', _('Report Chunk Size'), _('Report chunk size used by tcpdump in MByte.')); + o.placeholder = '1'; + o.datatype = 'range(1,10)'; + o.rmempty = true; + + o = s.taboption('adv_report', form.Value, 'adb_replisten', _('Report Ports'), _('Space separated list of ports used by tcpdump.')); + o.placeholder = '53'; + o.rmempty = true; + + /* + advanced email settings tab + */ + o = s.taboption('adv_email', form.Value, 'adb_mailsender', _('E-Mail Sender Address'), _('Sender address for adblock notification E-Mails.')); + o.placeholder = 'no-reply@adblock'; + o.rmempty = true; + + o = s.taboption('adv_email', form.Value, 'adb_mailtopic', _('E-Mail Topic'), _('Topic for adblock notification E-Mails.')); + o.placeholder = 'adblock notification'; + o.rmempty = true; + + o = s.taboption('adv_email', form.Value, 'adb_mailprofile', _('E-Mail Profile'), _('Profile used by \'msmtp\' for adblock notification E-Mails.')); + o.placeholder = 'adb_notify'; + o.rmempty = true; + + o = s.taboption('adv_email', form.Value, 'adb_mailcnt', _('E-Mail Notification Count'), _('Raise the notification count, to get E-Mails if the overall blocklist count is less or equal to the given limit.')); + o.placeholder = '0'; + o.datatype = 'min(0)'; + o.rmempty = true; + + /* + blocklist sources tab + */ + o = s.taboption('sources', form.MultiValue, 'adb_sources', _('Sources (Size, Focus)')); + var lines, name, size, focus; + lines = result[0].trim().split('\n'); + for (var i = 0; i < lines.length; i++) { + if (lines[i].match(/^\s+\+/)) { + name = lines[i].match(/^\s+\+\s(\w+)\s/)[1] || '-'; + size = lines[i].match(/^\s+\+\s\w+[\sx]+(\w+)/)[1] || '-'; + focus = lines[i].match(/^\s+\+\s\w+[\sx]+\w+\s+([\w\+]+)/)[1] || '-'; + o.value(name, name + ' (' + size + ', ' + focus + ')'); + } + } + o.rmempty = false; + return m.render(); + }, + handleReset: null +}); diff --git a/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/whitelist.js b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/whitelist.js new file mode 100644 index 000000000..26ca7bfd2 --- /dev/null +++ b/applications/luci-app-adblock/htdocs/luci-static/resources/view/adblock/whitelist.js @@ -0,0 +1,35 @@ +'use strict'; +'require fs'; +'require ui'; + +return L.view.extend({ + load: function() { + return L.resolveDefault(fs.read_direct('/etc/adblock/adblock.whitelist'), ''); + }, + handleSave: function(ev) { + var value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n').replace(/[^a-z0-9\.\-\#\n]/g, '')) + '\n'; + return fs.write('/etc/adblock/adblock.whitelist', value) + .then(function(rc) { + document.querySelector('textarea').value = value; + ui.addNotification(null, E('p', _('Whitelist changes have been saved. Refresh your adblock lists that changes take effect.')), 'info'); + }).catch(function(e) { + ui.addNotification(null, E('p', _('Unable to save changes: %s').format(e.message))); + }); + }, + render: function(whitelist) { + return E([ + E('p', {}, + _('This is the local adblock whitelist to always allow certain (sub) domains.<br /> \ + Please note: add only one domain per line. Comments introduced with \'#\' are allowed - ip addresses, wildcards and regex are not.')), + E('p', {}, + E('textarea', { + 'style': 'width: 100% !important; padding: 5px; font-family: monospace', + 'wrap': 'off', + 'rows': 25 + }, [ whitelist != null ? whitelist : '' ]) + ) + ]); + }, + handleSaveApply: null, + handleReset: null +}); |