diff options
Diffstat (limited to 'applications/luci-app-banip/htdocs')
6 files changed, 612 insertions, 202 deletions
diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/allowlist.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/allowlist.js index 07175a4fce..6b54f2946e 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/allowlist.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/allowlist.js @@ -11,23 +11,26 @@ return view.extend({ ]); }, handleSave: function (ev) { - var value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n')) + '\n'; + let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n')) + '\n'; return fs.write('/etc/banip/banip.allowlist', value) - .then(function (rc) { + .then(function () { document.querySelector('textarea').value = value; - ui.addNotification(null, E('p', _('Allowlist modifications have been saved, restart banIP that changes take effect.')), 'info'); + document.body.scrollTop = document.documentElement.scrollTop = 0; + ui.addNotification(null, E('p', _('Allowlist modifications have been saved, start the Domain Lookup or restart banIP that changes take effect.')), 'info'); }).catch(function (e) { - ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message))); + document.body.scrollTop = document.documentElement.scrollTop = 0; + ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error'); }); }, render: function (allowlist) { if (allowlist[0].size >= 100000) { + document.body.scrollTop = document.documentElement.scrollTop = 0; ui.addNotification(null, E('p', _('The allowlist is too big, unable to save modifications.')), 'error'); } return E([ E('p', {}, - _('This is the local banIP allowlist that will permit certain MAC/IP/CIDR addresses.<br /> \ - <em><b>Please note:</b></em> add only exactly one MAC/IPv4/IPv6 address or domain name per line.')), + _('This is the local banIP allowlist that will permit certain MAC-, IP-addresses or domain names.<br /> \ + <em><b>Please note:</b></em> add only exactly one MAC/IPv4/IPv6 address or domain name per line. Ranges in CIDR notation and MAC/IP-bindings are allowed.')), E('p', {}, E('textarea', { 'style': 'width: 100% !important; padding: 5px; font-family: monospace', diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/blocklist.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/blocklist.js index 75560fd6e1..8dede44e52 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/blocklist.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/blocklist.js @@ -11,23 +11,26 @@ return view.extend({ ]); }, handleSave: function (ev) { - var value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n')) + '\n'; + let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n/g, '\n')) + '\n'; return fs.write('/etc/banip/banip.blocklist', value) - .then(function (rc) { + .then(function () { document.querySelector('textarea').value = value; - ui.addNotification(null, E('p', _('Blocklist modifications have been saved, restart banIP that changes take effect.')), 'info'); + document.body.scrollTop = document.documentElement.scrollTop = 0; + ui.addNotification(null, E('p', _('Blocklist modifications have been saved, start the Domain Lookup or restart banIP that changes take effect.')), 'info'); }).catch(function (e) { - ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message))); + document.body.scrollTop = document.documentElement.scrollTop = 0; + ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error'); }); }, render: function (blocklist) { if (blocklist[0].size >= 100000) { + document.body.scrollTop = document.documentElement.scrollTop = 0; ui.addNotification(null, E('p', _('The blocklist is too big, unable to save modifications.')), 'error'); } return E([ E('p', {}, - _('This is the local banIP blocklist that will prevent certain MAC/IP/CIDR addresses.<br /> \ - <em><b>Please note:</b></em> add only exactly one MAC/IPv4/IPv6 address or domain name per line.')), + _('This is the local banIP blocklist that will prevent certain MAC-, IP-addresses or domain names.<br /> \ + <em><b>Please note:</b></em> add only exactly one MAC/IPv4/IPv6 address or domain name per line. Ranges in CIDR notation and MAC/IP-bindings are allowed.')), E('p', {}, E('textarea', { 'style': 'width: 100% !important; padding: 5px; font-family: monospace', diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/custom.css b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/custom.css new file mode 100644 index 0000000000..23c60c683d --- /dev/null +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/custom.css @@ -0,0 +1,3 @@ +.cbi-input-text { + width: 90% !important; +} diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js new file mode 100644 index 0000000000..0e4e682986 --- /dev/null +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js @@ -0,0 +1,305 @@ +'use strict'; +'require view'; +'require form'; +'require fs'; +'require ui'; + +/* + include custom CSS +*/ +document.querySelector('head').appendChild(E('link', { + 'rel': 'stylesheet', + 'type': 'text/css', + 'href': L.resource('view/banip/custom.css') +})); + +/* + observe DOM changes +*/ +const observer = new MutationObserver(function (mutations) { + if (mutations) { + const inputs = document.querySelectorAll('input'); + inputs.forEach(function (input) { + input.setAttribute('autocomplete', 'off') + input.setAttribute('autocorrect', 'off') + input.setAttribute('autocapitalize', 'off') + input.setAttribute('spellcheck', false) + }) + const labels = document.querySelectorAll('label[for^="widget.cbid.json"][for$="name"]'); + labels.forEach(function (label) { + label.setAttribute("style", "font-weight: bold !important; color: #595 !important;"); + }) + L.resolveDefault(fs.stat('/etc/banip/banip.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'); + } + }); + } +}); + +const targetNode = document.getElementById('view'); +const observerConfig = { + childList: true, + subtree: true, + attributes: false, + characterData: false +}; +observer.observe(targetNode, observerConfig); + +/* + button handling +*/ +function handleEdit(ev) { + if (ev === 'upload') { + return ui.uploadFile('/etc/banip/banip.custom.feeds').then(function () { + L.resolveDefault(fs.read_direct('/etc/banip/banip.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/banip/banip.custom.feeds', null).then(function () { + ui.addNotification(null, E('p', _('Upload of the custom feed file failed.')), 'error'); + }); + return; + } + } else { + fs.write('/etc/banip/banip.custom.feeds', null).then(function () { + ui.addNotification(null, E('p', _('Upload of the custom feed file failed.')), 'error'); + }); + return; + } + location.reload(); + } else { + fs.write('/etc/banip/banip.custom.feeds', null).then(function () { + ui.addNotification(null, E('p', _('Upload of the custom feed file failed.')), 'error'); + }); + } + }); + }).catch(function () { }); + } + if (ev === 'download') { + return fs.read_direct('/etc/banip/banip.custom.feeds', 'blob').then(function (blob) { + let url = window.URL.createObjectURL(blob), + date = new Date(), + name = 'banip.custom.feeds_%04d-%02d-%02d.json'.format(date.getFullYear(), date.getMonth() + 1, date.getDate()), + link = E('a', { 'style': 'display:none', 'href': url, 'download': name }); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(url); + }).catch(function () { }); + } + if (ev === 'create') { + return fs.read_direct('/etc/banip/banip.feeds', 'json').then(function (content) { + fs.write('/etc/banip/banip.custom.feeds', JSON.stringify(content)).then(function () { + location.reload(); + }); + }); + } + if (ev === 'clear') { + return fs.write('/etc/banip/banip.custom.feeds', null).then(function () { + location.reload(); + }); + } + if (ev === 'save') { + const invalid = document.querySelectorAll('.cbi-input-invalid'); + if (invalid.length > 0) { + document.body.scrollTop = document.documentElement.scrollTop = 0; + return ui.addNotification(null, E('p', _('Invalid input values, unable to save modifications.')), 'error'); + } + } + let sumSubElements = [], exportJson; + const nodeKeys = document.querySelectorAll('[id^="widget.cbid.json"][id$="name"]'); + for (let i = 0; i < nodeKeys.length; i++) { + let subElements = {}; + let elements = document.querySelectorAll('[id^="widget.cbid.json.' + nodeKeys[i].id.split('.')[3] + '\."]'); + for (const element of elements) { + let key = element.id.split('.')[4]; + let value = element.value || ""; + if (value === "") { + continue; + } + switch (key) { + case 'url_4': + subElements.url_4 = value; + break; + case 'rule_4': + subElements.rule_4 = value; + break; + case 'url_6': + subElements.url_6 = value; + break; + case 'rule_6': + subElements.rule_6 = value; + break; + case 'descr': + subElements.descr = value; + break; + case 'flag': + subElements.flag = value; + break; + } + } + if (nodeKeys[i].value !== "" && subElements.descr !== "") { + sumSubElements.push(nodeKeys[i].value, subElements); + } + } + if (sumSubElements.length > 0) { + exportJson = JSON.stringify(sumSubElements).replace(/^\[/, '{\n').replace(/\}]$/, '\n\t}\n}\n').replace(/,{"/g, ':{\n\t"').replace(/"},"/g, '"\n\t},\n"').replace(/","/g, '",\n\t"'); + } + return fs.write('/etc/banip/banip.custom.feeds', exportJson).then(function () { + location.reload(); + }); +} + +return view.extend({ + load: function () { + return L.resolveDefault(fs.read_direct('/etc/banip/banip.custom.feeds', 'json'), ""); + }, + + render: function (data) { + let m, s, o, feed, url_4, url_6, rule_4, rule_6, descr, flag; + + m = new form.JSONMap(data, _('Custom Feed Editor'), _('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/banip/banip.custom.feeds\'. \ + Then you can edit this file, delete entries, add new ones or make a local backup. To go back to the maintainers version just empty the custom feed file again (do not delete it!).')); + for (let i = 0; i < Object.keys(m.data.data).length; i++) { + feed = Object.keys(m.data.data)[i]; + url_4 = m.data.data[feed].url_4; + rule_4 = m.data.data[feed].rule_4; + url_6 = m.data.data[feed].url_6; + rule_6 = m.data.data[feed].rule_6; + descr = m.data.data[feed].descr; + flag = m.data.data[feed].flag; + + s = m.section(form.TypedSection, feed, null); + s.addremove = true; + s.anonymous = true; + + o = s.option(form.Value, 'name', _('Feed Name')); + o.ucioption = '.name'; + o.datatype = 'and(minlength(3),maxlength(15))'; + o.validate = function (section_id, value) { + if (!value) { + return _('Empty field not allowed'); + } + if (!value.match(/^[a-z0-9]+$/)) { + return _('Invalid characters'); + } + return true; + } + + o = s.option(form.Value, 'url_4', _('URLv4')); + o.validate = function (section_id, value) { + if (!value) { + return true; + } + if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-\?\&\+_@%=:~#]+$/)) { + return _('Protocol/URL format not supported'); + } + return true; + } + + o = s.option(form.Value, 'rule_4', _('Rulev4')); + + o = s.option(form.Value, 'url_6', _('URLv6')); + o.validate = function (section_id, value) { + if (!value) { + return true; + } + if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-\?\&\+_@%=:~#]+$/)) { + return _('Protocol/URL format not supported'); + } + return true; + } + + o = s.option(form.Value, 'rule_6', _('Rulev6')); + + o = s.option(form.Value, 'descr', _('Description')); + o.datatype = 'and(minlength(3),maxlength(30))'; + o.validate = function (section_id, value) { + if (!value) { + return _('Empty field not allowed'); + } + return true; + } + + o = s.option(form.Value, 'flag', _('Flag')); + o.datatype = 'and(minlength(2),maxlength(2))'; + o.validate = function (section_id, value) { + if (!value) { + return true; + } + if (!value.match(/^gz$/)) { + return _('Flag not supported'); + } + return true; + } + } + + s = m.section(form.NamedSection, 'global'); + s.render = L.bind(function () { + return E('div', { class: 'right' }, [ + E('button', { + 'class': 'btn cbi-button cbi-button-action', + 'id': 'btnDownload', + 'disabled': 'disabled', + 'click': ui.createHandlerFn(this, function () { + return handleEdit('download'); + }) + }, [_('Download Custom Feeds')]), + '\xa0\xa0\xa0', + E('button', { + 'class': 'btn cbi-button cbi-button-action', + 'id': 'btnUpload', + 'disabled': 'disabled', + 'click': ui.createHandlerFn(this, function () { + return handleEdit('upload'); + }) + }, [_('Upload Custom Feeds')]), + '\xa0\xa0\xa0\xa0\xa0\xa0', + E('button', { + 'class': 'btn cbi-button cbi-button-action important', + 'id': 'btnCreate', + 'disabled': 'disabled', + 'click': ui.createHandlerFn(this, function () { + return handleEdit('create'); + }) + }, [_('Fill Custom Feeds')]), + '\xa0\xa0\xa0', + E('button', { + 'class': 'btn cbi-button cbi-button-negative important', + 'id': 'btnClear', + 'disabled': 'disabled', + 'click': ui.createHandlerFn(this, function () { + return handleEdit('clear'); + }) + }, [_('Clear Custom Feeds')]), + '\xa0\xa0\xa0', + E('button', { + 'class': 'btn cbi-button cbi-button-positive important', + 'id': 'btnSave', + 'disabled': 'disabled', + 'click': ui.createHandlerFn(this, function () { + return handleEdit('save'); + }) + }, [_('Save Custom Feeds')]) + ]) + }); + return m.render(); + }, + handleSaveApply: null, + handleSave: null, + handleReset: null +}); diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js index 2b8899dc85..adefc3b18d 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js @@ -17,6 +17,7 @@ function handleAction(ev) { return view.extend({ load: function () { return Promise.all([ + L.resolveDefault(fs.read_direct('/etc/banip/banip.custom.feeds'), ''), L.resolveDefault(fs.read_direct('/etc/banip/banip.feeds'), ''), L.resolveDefault(fs.read_direct('/etc/banip/banip.countries'), ''), uci.load('banip') @@ -24,118 +25,124 @@ return view.extend({ }, render: function (result) { - var m, s, o; + let m, s, o; - m = new form.Map('banip', 'banIP', _('Configuration of the banIP package to ban incoming and outgoing ip addresses/subnets via sets in nftables. \ + m = new form.Map('banip', 'banIP', _('Configuration of the banIP package to ban incoming and outgoing IPs via named nftables Sets. \ For further information <a href="https://github.com/openwrt/packages/blob/master/net/banip/files/README.md" target="_blank" rel="noreferrer noopener" >check the online documentation</a>')); /* poll runtime information */ - var rt_res, inf_stat, inf_version, inf_elements, inf_feeds, inf_feedarray, inf_devices, inf_devicearray - var inf_subnets, inf_subnetarray, nft_infos, run_infos, inf_flags, last_run, inf_system + let buttons, rtRes, infStat, infVer, infElements, infFeeds, infDevices, infUplink, infSystem, nftInfos, runInfos, infFlags, last_run pollData: poll.add(function () { - return L.resolveDefault(fs.read_direct('/var/run/banip_runtime.json'), 'null').then(function (res) { - rt_res = JSON.parse(res); - inf_stat = document.getElementById('status'); - if (inf_stat && rt_res) { - L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['status', 'update'])).then(function (update_res) { - inf_stat.textContent = (rt_res.status + ' (' + update_res.trim() + ')' || '-'); - }); - if (rt_res.status === "processing") { - if (!inf_stat.classList.contains("spinning")) { - inf_stat.classList.add("spinning"); - } - } else { - if (inf_stat.classList.contains("spinning")) { - inf_stat.classList.remove("spinning"); - } + return L.resolveDefault(fs.stat('/var/run/banip.lock')).then(function (stat) { + buttons = document.querySelectorAll('.cbi-button'); + infStat = document.getElementById('status'); + if (stat) { + for (let i = 0; i < buttons.length; i++) { + buttons[i].setAttribute('disabled', 'true'); } - } else if (inf_stat) { - inf_stat.textContent = '-'; - if (inf_stat.classList.contains("spinning")) { - inf_stat.classList.remove("spinning"); + if (infStat && !infStat.classList.contains('spinning')) { + infStat.classList.add('spinning'); } - } - inf_version = document.getElementById('version'); - if (inf_version && rt_res) { - inf_version.textContent = rt_res.version || '-'; - } - inf_elements = document.getElementById('elements'); - if (inf_elements && rt_res) { - inf_elements.textContent = rt_res.element_count || '-'; - } - inf_feeds = document.getElementById('feeds'); - inf_feedarray = []; - if (inf_feeds && rt_res) { - for (var i = 0; i < rt_res.active_feeds.length; i++) { - if (i < rt_res.active_feeds.length - 1) { - inf_feedarray += rt_res.active_feeds[i].feed + ', '; - } else { - inf_feedarray += rt_res.active_feeds[i].feed - } + } else { + for (let i = 0; i < buttons.length; i++) { + buttons[i].removeAttribute('disabled'); + } + if (infStat && infStat.classList.contains('spinning')) { + infStat.classList.remove('spinning'); } - inf_feeds.textContent = inf_feedarray || '-'; } - inf_devices = document.getElementById('devices'); - inf_devicearray = []; - if (inf_devices && rt_res && rt_res.active_devices.length > 1) { - for (var i = 0; i < rt_res.active_devices.length; i++) { - if (i === 0 && rt_res.active_devices[i].device && rt_res.active_devices[i+1].interface) { - inf_devicearray += rt_res.active_devices[i].device + ' ::: ' + rt_res.active_devices[i+1].interface; - i++; - } - else if (i === 0) { - inf_devicearray += rt_res.active_devices[i].device - } - else if (i > 0 && rt_res.active_devices[i].device && rt_res.active_devices[i+1].interface) { - inf_devicearray += ', ' + rt_res.active_devices[i].device + ' ::: ' + rt_res.active_devices[i+1].interface; - i++; - } - else if (i > 0 && rt_res.active_devices[i].device) { - inf_devicearray += ', ' + rt_res.active_devices[i].device; + L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['status'])).then(function (result) { + if (result) { + rtRes = result.trim().split('\n'); + if (rtRes) { + for (let i = 0; i < rtRes.length; i++) { + if (rtRes[i].match(/^\s+\+\sstatus\s+\:\s+(.*)$/)) { + rtRes.status = rtRes[i].match(/^\s+\+\sstatus\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\sversion\s+\:\s+(.*)$/)) { + rtRes.version = rtRes[i].match(/^\s+\+\sversion\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\selement_count\s+\:\s+(.*)$/)) { + rtRes.elementCount = rtRes[i].match(/^\s+\+\selement_count\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\sactive_feeds\s+\:\s+(.*)$/)) { + rtRes.activeFeeds = rtRes[i].match(/^\s+\+\sactive_feeds\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\sactive_devices\s+\:\s+(.*)$/)) { + rtRes.activeDevices = rtRes[i].match(/^\s+\+\sactive_devices\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\sactive_uplink\s+\:\s+(.*)$/)) { + rtRes.activeUplink = rtRes[i].match(/^\s+\+\sactive_uplink\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\snft_info\s+\:\s+(.*)$/)) { + rtRes.nftInfo = rtRes[i].match(/^\s+\+\snft_info\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\srun_info\s+\:\s+(.*)$/)) { + rtRes.runInfo = rtRes[i].match(/^\s+\+\srun_info\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\srun_flags\s+\:\s+(.*)$/)) { + rtRes.runFlags = rtRes[i].match(/^\s+\+\srun_flags\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\slast_run\s+\:\s+(.*)$/)) { + rtRes.lastRun = rtRes[i].match(/^\s+\+\slast_run\s+\:\s+(.*)$/)[1]; + } else if (rtRes[i].match(/^\s+\+\ssystem_info\s+\:\s+(.*)$/)) { + rtRes.systemInfo = rtRes[i].match(/^\s+\+\ssystem_info\s+\:\s+(.*)$/)[1]; + } + } } - else if (i > 0 && rt_res.active_devices[i].interface) { - inf_devicearray += ', ' + rt_res.active_devices[i].interface; + if (rtRes) { + infStat = document.getElementById('status'); + if (infStat) { + infStat.textContent = rtRes.status || '-'; + } + infVer = document.getElementById('version'); + if (infVer) { + infVer.textContent = rtRes.version || '-'; + } + infElements = document.getElementById('elements'); + if (infElements) { + infElements.textContent = rtRes.elementCount || '-'; + } + infFeeds = document.getElementById('feeds'); + if (infFeeds) { + infFeeds.textContent = rtRes.activeFeeds || '-'; + } + infDevices = document.getElementById('devices'); + if (infDevices) { + infDevices.textContent = rtRes.activeDevices || '-'; + } + infUplink = document.getElementById('uplink'); + if (infUplink) { + infUplink.textContent = rtRes.activeUplink || '-'; + } + nftInfos = document.getElementById('nft'); + if (nftInfos) { + nftInfos.textContent = rtRes.nftInfo || '-'; + } + runInfos = document.getElementById('run'); + if (runInfos) { + runInfos.textContent = rtRes.runInfo || '-'; + } + infFlags = document.getElementById('flags'); + if (infFlags) { + infFlags.textContent = rtRes.runFlags || '-'; + } + last_run = document.getElementById('last'); + if (last_run) { + last_run.textContent = rtRes.lastRun || '-'; + } + infSystem = document.getElementById('system'); + if (infSystem) { + infSystem.textContent = rtRes.systemInfo || '-'; + } } - } - inf_devices.textContent = inf_devicearray || '-'; - } - inf_subnets = document.getElementById('subnets'); - inf_subnetarray = []; - if (inf_subnets && rt_res) { - for (var i = 0; i < rt_res.active_subnets.length; i++) { - if (i < rt_res.active_subnets.length - 1) { - inf_subnetarray += rt_res.active_subnets[i].subnet + ', '; - } else { - inf_subnetarray += rt_res.active_subnets[i].subnet + } else { + infStat = document.getElementById('status'); + if (infStat) { + infStat.textContent = '-'; + poll.stop(); + if (infStat.classList.contains('spinning')) { + infStat.classList.remove('spinning'); + } } } - inf_subnets.textContent = inf_subnetarray || '-'; - } - nft_infos = document.getElementById('nft'); - if (nft_infos && rt_res) { - nft_infos.textContent = rt_res.nft_info || '-'; - } - run_infos = document.getElementById('run'); - if (run_infos && rt_res) { - run_infos.textContent = rt_res.run_info || '-'; - } - inf_flags = document.getElementById('flags'); - if (inf_flags && rt_res) { - inf_flags.textContent = rt_res.run_flags || '-'; - } - last_run = document.getElementById('last'); - if (last_run && rt_res) { - last_run.textContent = rt_res.last_run || '-'; - } - inf_system = document.getElementById('system'); - if (inf_system && rt_res) { - inf_system.textContent = rt_res.system_info || '-'; - } + }); }); - }, 1); + }, 2); /* runtime information and buttons @@ -165,8 +172,8 @@ return view.extend({ E('div', { 'class': 'cbi-value-field', 'id': 'devices', 'style': 'color:#37c' }, '-') ]), E('div', { 'class': 'cbi-value' }, [ - E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Active Subnets')), - E('div', { 'class': 'cbi-value-field', 'id': 'subnets', 'style': 'color:#37c' }, '-') + E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('Active Uplink')), + E('div', { 'class': 'cbi-value-field', 'id': 'uplink', 'style': 'color:#37c' }, '-') ]), E('div', { 'class': 'cbi-value' }, [ E('label', { 'class': 'cbi-value-title', 'style': 'padding-top:0rem' }, _('NFT Information')), @@ -190,6 +197,13 @@ return view.extend({ ]), E('div', { class: 'right' }, [ E('button', { + 'class': 'btn cbi-button cbi-button-action', + 'click': ui.createHandlerFn(this, function () { + return handleAction('lookup'); + }) + }, [_('Domain Lookup')]), + '\xa0\xa0\xa0', + E('button', { 'class': 'btn cbi-button cbi-button-negative', 'click': ui.createHandlerFn(this, function () { return handleAction('stop'); @@ -224,7 +238,7 @@ return view.extend({ s.tab('adv_chain', _('Chain/Set Settings')); s.tab('adv_log', _('Log Settings')); s.tab('adv_email', _('E-Mail Settings')); - s.tab('feeds', _('Blocklist Feeds')); + s.tab('feeds', _('Feed Selection')); /* general settings tab @@ -250,23 +264,20 @@ return view.extend({ o = s.taboption('general', widgets.DeviceSelect, 'ban_dev', _('Network Devices'), _('Select the WAN network device(s).')); o.depends('ban_autodetect', '0'); - o.unspecified = true; o.multiple = true; o.nocreate = true; o.optional = true; o.retain = true; - o = s.taboption('general', widgets.NetworkSelect, 'ban_ifv4', _('Network Interfaces'), _('Select the logical WAN IPv4 network interface(s).')); + o = s.taboption('general', widgets.NetworkSelect, 'ban_ifv4', _('IPv4 Network Interfaces'), _('Select the logical WAN IPv4 network interface(s).')); o.depends('ban_autodetect', '0'); - o.unspecified = true; o.multiple = true; o.nocreate = true; o.optional = true; o.retain = true; - o = s.taboption('general', widgets.NetworkSelect, 'ban_ifv6', _('Network Interfaces'), _('Select the logical WAN IPv6 network interface(s).')); + o = s.taboption('general', widgets.NetworkSelect, 'ban_ifv6', _('IPv6 Network Interfaces'), _('Select the logical WAN IPv6 network interface(s).')); o.depends('ban_autodetect', '0'); - o.unspecified = true; o.multiple = true; o.nocreate = true; o.optional = true; @@ -286,38 +297,34 @@ return view.extend({ o.optional = true; o.retain = true; - o = s.taboption('general', widgets.NetworkSelect, 'ban_trigger', _('Startup Trigger Interface'), _('List of available network interfaces to trigger the banIP start.')); - o.unspecified = true; + o = s.taboption('general', widgets.NetworkSelect, 'ban_trigger', _('Reload Trigger Interface'), _('List of available reload trigger interface(s).')); o.multiple = true; o.nocreate = true; o.rmempty = true; - o = s.taboption('general', form.Value, 'ban_triggerdelay', _('Trigger Delay'), _('Additional trigger delay in seconds before banIP processing actually starts.')); + o = s.taboption('general', form.Value, 'ban_triggerdelay', _('Trigger Delay'), _('Additional trigger delay in seconds during interface reload and boot.')); o.placeholder = '10'; o.datatype = 'range(1,300)'; o.rmempty = true; - o = s.taboption('general', form.Flag, 'ban_deduplicate', _('Deduplicate IPs'), _('Deduplicate IP addresses across all active sets and and tidy up the local blocklist.')); - o.default = 1 - o.rmempty = false; - - o = s.taboption('general', form.Flag, 'ban_loginput', _('Log WAN-Input'), _('Log suspicious incoming WAN packets (dropped).')); - o.default = 1 - o.rmempty = false; - - o = s.taboption('general', form.Flag, 'ban_logforwardwan', _('Log WAN-Forward'), _('Log suspicious forwarded WAN packets (dropped).')); - o.default = 1 - o.rmempty = false; + o = s.taboption('general', form.ListValue, 'ban_fetchretry', _('Download Retries'), _('Number of download attempts in case of an error (not supported by uclient-fetch).')); + o.value('1', _('1')); + o.value('3', _('3')); + o.value('5', _('5 (default)')); + o.value('10', _('10')); + o.value('20', _('20')); + o.optional = true; + o.rmempty = true; - o = s.taboption('general', form.Flag, 'ban_logforwardlan', _('Log LAN-Forward'), _('Log suspicious forwarded LAN packets (rejected).')); - o.rmempty = false; + o = s.taboption('general', form.Flag, 'ban_fetchinsecure', _('Download Insecure'), _('Don\'t check SSL server certificates during download.')); + o.rmempty = true; /* additional settings tab */ o = s.taboption('advanced', form.DummyValue, '_sub'); o.rawhtml = true; - o.default = '<em><b>Changes on this tab needs a banIP service restart to take effect.</b></em>'; + o.default = '<em><b>' + _('Changes on this tab needs a banIP service restart to take effect.') + '</b></em>'; o = s.taboption('advanced', form.ListValue, 'ban_nicelimit', _('Nice Level'), _('The selected priority will be used for banIP background processing.')); o.value('-20', _('Highest Priority')); @@ -328,7 +335,7 @@ return view.extend({ o.optional = true; o.rmempty = true; - o = s.taboption('advanced', form.ListValue, 'ban_filelimit', _('Max Open Files'), _('Increase the maximal number of open files, e.g. to handle the amount of temporary split files while loading the sets.')); + o = s.taboption('advanced', form.ListValue, 'ban_filelimit', _('Max Open Files'), _('Increase the maximal number of open files, e.g. to handle the amount of temporary split files while loading the Sets.')); o.value('512', _('512')); o.value('1024', _('1024 (default)')); o.value('2048', _('2048')); @@ -345,7 +352,7 @@ return view.extend({ o.optional = true; o.rmempty = true; - o = s.taboption('advanced', form.ListValue, 'ban_splitsize', _('Set Split Size'), _('Split external set loading after every n members to save RAM.')); + o = s.taboption('advanced', form.ListValue, 'ban_splitsize', _('Set Split Size'), _('Split external Set loading after every n members to save RAM.')); o.value('256'); o.value('512'); o.value('1024'); @@ -366,27 +373,28 @@ return view.extend({ o.placeholder = '/tmp/banIP-report'; o.rmempty = true; + o = s.taboption('advanced', form.Flag, 'ban_deduplicate', _('Deduplicate IPs'), _('Deduplicate IP addresses across all active Sets and tidy up the local blocklist.')); + o.default = 1 + o.rmempty = false; + o = s.taboption('advanced', form.Flag, 'ban_reportelements', _('Report Elements'), _('List Set elements in the status and report, disable this to reduce the CPU load.')); o.default = 1 o.optional = true; - o = s.taboption('advanced', form.Flag, 'ban_fetchinsecure', _('Download Insecure'), _('Don\'t check SSL server certificates during download.')); - o.rmempty = true; - /* advanced chain/set settings tab */ o = s.taboption('adv_chain', form.DummyValue, '_sub'); o.rawhtml = true; - o.default = '<em><b>Changes on this tab needs a banIP service restart to take effect.</b></em>'; + o.default = '<em><b>' + _('Changes on this tab needs a banIP service restart to take effect.') + '</b></em>'; - o = s.taboption('adv_chain', form.ListValue, 'ban_nftpolicy', _('Set Policy'), _('Set the nft policy for banIP-related sets.')); + o = s.taboption('adv_chain', form.ListValue, 'ban_nftpolicy', _('NFT Set Policy'), _('Set the nft policy for banIP-related Sets.')); o.value('memory', _('memory (default)')); o.value('performance', _('performance')); o.optional = true; o.rmempty = true; - o = s.taboption('adv_chain', form.ListValue, 'ban_nftpriority', _('Chain Priority'), _('Set the nft chain priority within the banIP table. Please note: lower values means higher priority.')); + o = s.taboption('adv_chain', form.ListValue, 'ban_nftpriority', _('NFT Chain Priority'), _('Set the nft chain priority within the banIP table. Please note: lower values means higher priority.')); o.value('0', _('0')); o.value('-100', _('-100')); o.value('-200', _('-200 (default)')); @@ -395,12 +403,42 @@ return view.extend({ o.optional = true; o.rmempty = true; + o = s.taboption('adv_chain', widgets.DeviceSelect, 'ban_vlanallow', _('Allow VLAN Forwards'), _('Always allow certain VLAN forwards.')); + o.multiple = true; + o.nocreate = true; + o.optional = true; + o.rmempty = true; + + o = s.taboption('adv_chain', widgets.DeviceSelect, 'ban_vlanblock', _('Block VLAN Forwards'), _('Always block certain VLAN forwards.')); + o.multiple = true; + o.nocreate = true; + o.optional = true; + o.rmempty = true; + + o = s.taboption('adv_chain', form.ListValue, 'ban_blocktype', _('Block Type'), _('Drop packets silently or actively reject the traffic on WAN-Input and WAN-Forward chains.')); + o.value('drop', _('drop (default)')); + o.value('reject', _('reject')); + o.optional = true; + o.rmempty = true; + + o = s.taboption('adv_chain', form.ListValue, 'ban_blockpolicy', _('Default Block Policy'), _('By default each feed is active in all supported chains. Limit the default block policy to a certain chain.')); + o.value('input', _('WAN-Input Chain')); + o.value('forwardwan', _('WAN-Forward Chain')); + o.value('forwardlan', _('LAN-Forward Chain')); + o.optional = true; + o.rmempty = true; + + let feed, feeds, descr; if (result[0]) { - var feed, feeds; feeds = JSON.parse(result[0]); - + } else if (result[1]) { + feeds = JSON.parse(result[1]); + } + if (feeds) { o = s.taboption('adv_chain', form.MultiValue, 'ban_blockinput', _('WAN-Input Chain'), _('Limit certain feeds to the WAN-Input chain.')); - for (var i = 0; i < Object.keys(feeds).length; i++) { + o.value('allowlist', _('local allowlist')); + o.value('blocklist', _('local blocklist')); + for (let i = 0; i < Object.keys(feeds).length; i++) { feed = Object.keys(feeds)[i].trim(); o.value(feed); } @@ -408,7 +446,9 @@ return view.extend({ o.rmempty = true; o = s.taboption('adv_chain', form.MultiValue, 'ban_blockforwardwan', _('WAN-Forward Chain'), _('Limit certain feeds to the WAN-Forward chain.')); - for (var i = 0; i < Object.keys(feeds).length; i++) { + o.value('allowlist', _('local allowlist')); + o.value('blocklist', _('local blocklist')); + for (let i = 0; i < Object.keys(feeds).length; i++) { feed = Object.keys(feeds)[i].trim(); o.value(feed); } @@ -416,7 +456,9 @@ return view.extend({ o.rmempty = true; o = s.taboption('adv_chain', form.MultiValue, 'ban_blockforwardlan', _('LAN-Forward Chain'), _('Limit certain feeds to the LAN-Forward chain.')); - for (var i = 0; i < Object.keys(feeds).length; i++) { + o.value('allowlist', _('local allowlist')); + o.value('blocklist', _('local blocklist')); + for (let i = 0; i < Object.keys(feeds).length; i++) { feed = Object.keys(feeds)[i].trim(); o.value(feed); } @@ -424,23 +466,14 @@ return view.extend({ o.rmempty = true; } - o = s.taboption('adv_chain', form.ListValue, 'ban_nftexpiry', _('Blocklist Expiry'), _('Expiry time for auto added blocklist set members.')); - o.value('10s'); - o.value('1m'); - o.value('5m'); - o.value('1h'); - o.value('2h'); - o.optional = true; - o.rmempty = true; - /* advanced log settings tab */ o = s.taboption('adv_log', form.DummyValue, '_sub'); o.rawhtml = true; - o.default = '<em><b>Changes on this tab needs a banIP service restart to take effect.</b></em>'; + o.default = '<em><b>' + _('Changes on this tab needs a banIP service restart to take effect.') + '</b></em>'; - o = s.taboption('adv_log', form.ListValue, 'ban_nftloglevel', _('Log Level'), _('Set the syslog level for NFT logging.')); + o = s.taboption('adv_log', form.ListValue, 'ban_nftloglevel', _('NFT Log Level'), _('Set the syslog level for NFT logging.')); o.value('emerg', _('emerg')); o.value('alert', _('alert')); o.value('crit', _('crit')); @@ -449,11 +482,26 @@ return view.extend({ o.value('notice', _('notice')); o.value('info', _('info')); o.value('debug', _('debug')); - o.value('audit', _('audit')); o.optional = true; o.rmempty = true; - o = s.taboption('adv_log', form.ListValue, 'ban_loglimit', _('Log Limit'), _('Parse only the last stated number of log entries for suspicious events.')); + o = s.taboption('adv_log', form.Flag, 'ban_loginput', _('Log WAN-Input'), _('Log suspicious incoming WAN packets (dropped).')); + o.default = 1 + o.rmempty = false; + + o = s.taboption('adv_log', form.Flag, 'ban_logforwardwan', _('Log WAN-Forward'), _('Log suspicious forwarded WAN packets (dropped).')); + o.default = 1 + o.rmempty = false; + + o = s.taboption('adv_log', form.Flag, 'ban_logforwardlan', _('Log LAN-Forward'), _('Log suspicious forwarded LAN packets (rejected).')); + o.rmempty = false; + + o = s.taboption('adv_log', form.Value, 'ban_logreadfile', _('Logfile Location'), _('Location for parsing the log file, e.g. via syslog-ng, to deactivate the standard parsing via logread.')); + o.placeholder = '/var/log/messages'; + o.rmempty = true; + + o = s.taboption('adv_log', form.ListValue, 'ban_loglimit', _('Log Limit'), _('Parse only the last stated number of log entries for suspicious events. To disable the log monitor at all set it to \'0\'.')); + o.value('0', _('0 (disable)')); o.value('50', _('50')); o.value('100', _('100 (default)')); o.value('250', _('250')); @@ -476,7 +524,10 @@ return view.extend({ */ o = s.taboption('adv_email', form.DummyValue, '_sub'); o.rawhtml = true; - o.default = '<em><b>To enable email notifications, set up the \'msmtp\' package and specify a vaild E-Mail receiver address.</b></em>'; + o.default = '<em><b>' + _('To enable email notifications, set up the \'msmtp\' package and specify a vaild E-Mail receiver address.') + '</b></em>'; + + o = s.taboption('adv_email', form.Flag, 'ban_mailnotification', _('E-Mail Notification'), _('Receive E-Mail notifications with every banIP run.')); + o.rmempty = true; o = s.taboption('adv_email', form.Value, 'ban_mailreceiver', _('E-Mail Receiver Address'), _('Receiver address for banIP notification E-Mails, this information is required to enable E-Mail functionality.')); o.placeholder = 'name@example.com'; @@ -496,35 +547,29 @@ return view.extend({ o.rmempty = true; /* - blocklist feeds tab + feeds tab */ o = s.taboption('feeds', form.DummyValue, '_sub'); o.rawhtml = true; - o.default = '<em><b>List of supported and fully pre-configured banIP feeds.</b></em>'; - - if (result[0]) { - var focus, feed, feeds; - feeds = JSON.parse(result[0]); + o.default = '<em><b>' + _('External blocklist feeds') + '</b></em>'; - o = s.taboption('feeds', form.MultiValue, 'ban_feed', _('Feed Selection')); - for (var i = 0; i < Object.keys(feeds).length; i++) { + if (feeds) { + o = s.taboption('feeds', form.MultiValue, 'ban_feed', _('Blocklist Feed Selection')); + for (let i = 0; i < Object.keys(feeds).length; i++) { feed = Object.keys(feeds)[i].trim(); - focus = feeds[feed].focus.trim(); - o.value(feed, feed + ' (' + focus + ')'); + descr = feeds[feed].descr.trim() || '-'; + o.value(feed, feed + ' (' + descr + ')'); } o.optional = true; o.rmempty = true; } - /* - prepare country data - */ - var code, country, countries = []; - if (result[1]) { - countries = result[1].trim().split('\n'); + let code, country, countries = []; + if (result[2]) { + countries = result[2].trim().split('\n'); o = s.taboption('feeds', form.MultiValue, 'ban_country', _('Countries')); - for (var i = 0; i < countries.length; i++) { + for (let i = 0; i < countries.length; i++) { code = countries[i].match(/^(\w+);/)[1].trim(); country = countries[i].match(/^\w+;(.*$)/)[1].trim(); o.value(code, country); @@ -538,14 +583,58 @@ return view.extend({ o.optional = true; o.rmempty = true; - o = s.taboption('feeds', form.Flag, 'ban_autoallowlist', _('Auto Allowlist'), _('Automatically transfers uplink IPs to the banIP allowlist.')); + o = s.taboption('feeds', form.DummyValue, '_feeds'); + o.rawhtml = true; + o.default = '<hr style="width: 200px; height: 1px;" /><em><b>' + _('External allowlist feeds') + '</b></em>'; + + o = s.taboption('feeds', form.DynamicList, 'ban_allowurl', _('Allowlist Feed Selection')); + o.optional = true; + o.rmempty = true; + o.validate = function (section_id, value) { + if (!value) { + return true; + } + if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-_\?\&\+=:~#]+$/)) { + return _('Protocol/URL format not supported'); + } + return true; + } + + o = s.taboption('feeds', form.DummyValue, '_feeds'); + o.rawhtml = true; + o.default = '<hr style="width: 200px; height: 1px;" /><em><b>' + _('Local feed settings') + '</b></em>'; + + o = s.taboption('feeds', form.Flag, 'ban_autoallowlist', _('Auto Allowlist'), _('Automatically add resolved domains and uplink IPs to the local banIP allowlist.')); o.default = 1 o.rmempty = false; - o = s.taboption('feeds', form.Flag, 'ban_autoblocklist', _('Auto Blocklist'), _('Automatically transfers suspicious IPs to the banIP blocklist.')); + o = s.taboption('feeds', form.ListValue, 'ban_autoallowuplink', _('Auto Allow Uplink'), _('Limit the uplink autoallow function.')); + o.depends('ban_autoallowlist', '1'); + o.value('disable', _('Disable')); + o.value('subnet', _('Subnet (default)')); + o.value('ip', _('IP')); + o.optional = true; + o.rmempty = true; + + o = s.taboption('feeds', form.Flag, 'ban_autoblocklist', _('Auto Blocklist'), _('Automatically add resolved domains and suspicious IPs to the local banIP blocklist.')); o.default = 1 o.rmempty = false; + o = s.taboption('feeds', form.Flag, 'ban_autoblocksubnet', _('Auto Block Subnet'), _('Automatically add entire subnets to the blocklist Set based on an additional RDAP request with the suspicious IP.')); + o.default = 0 + o.optional = true; + o.rmempty = true; + + o = s.taboption('feeds', form.ListValue, 'ban_nftexpiry', _('Blocklist Set Expiry'), _('Expiry time for auto added blocklist Set members.')); + o.value('10s'); + o.value('1m'); + o.value('5m'); + o.value('1h'); + o.value('2h'); + o.value('1d'); + o.optional = true; + o.rmempty = true; + o = s.taboption('feeds', form.Flag, 'ban_allowlistonly', _('Allowlist Only'), _('Restrict the internet access from/to a small number of secure IPs.')); o.rmempty = false; diff --git a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js index 2d39586435..97d8e2b243 100644 --- a/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js +++ b/applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js @@ -41,13 +41,13 @@ function handleAction(report, ev) { E('button', { 'class': 'btn cbi-button-action', 'click': ui.createHandlerFn(this, function (ev) { - var ip = document.getElementById('search').value.trim().toLowerCase(); + let ip = document.getElementById('search').value.trim().toLowerCase(); if (ip) { document.getElementById('run').classList.add("spinning"); document.getElementById('search').value = ip; document.getElementById('result').textContent = 'The search is running, please wait...'; L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['search', ip])).then(function (res) { - var result = document.getElementById('result'); + let result = document.getElementById('result'); if (res) { result.textContent = res.trim(); } else { @@ -65,13 +65,17 @@ function handleAction(report, ev) { document.getElementById('search').focus(); } if (ev === 'survey') { - var content, selectO; + let content, selectOption; - content = JSON.parse(report[1]); - selectO = [E('option', { value: '' }, [_('-- Set Selection --')])]; - for (var i = 0; i < Object.keys(content.nftables).length; i++) { - if (content.nftables[i].set !== undefined && content.nftables[i].set.name !== undefined) { - selectO.push(E('option', { 'value': content.nftables[i].set.name }, content.nftables[i].set.name)); + if (report[1]) { + content = JSON.parse(report[1]); + } else { + content = ""; + } + selectOption = [E('option', { value: '' }, [_('-- Set Selection --')])]; + for (let i = 0; i < Object.keys(content.nftables).length; i++) { + if (content.nftables[i].set && content.nftables[i].set.name !== undefined && content.nftables[i].set.table !== undefined && content.nftables[i].set.table === 'banIP') { + selectOption.push(E('option', { 'value': content.nftables[i].set.name }, content.nftables[i].set.name)); } } L.ui.showModal(_('Set Survey'), [ @@ -80,7 +84,7 @@ function handleAction(report, ev) { E('label', { 'class': 'cbi-input-select', 'style': 'padding-top:.5em', 'id': 'run' }, [ E('h5', _('Set')), E('select', { 'class': 'cbi-input-select', 'id': 'set' }, - selectO + selectOption ) ]), ]), @@ -104,12 +108,12 @@ function handleAction(report, ev) { E('button', { 'class': 'btn cbi-button-action', 'click': ui.createHandlerFn(this, function (ev) { - var set = document.getElementById('set').value; + let set = document.getElementById('set').value; if (set) { document.getElementById('run').classList.add("spinning"); document.getElementById('result').textContent = 'The survey is running, please wait...'; L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['survey', set])).then(function (res) { - var result = document.getElementById('result'); + let result = document.getElementById('result'); if (res) { result.textContent = res.trim(); } else { @@ -131,17 +135,21 @@ function handleAction(report, ev) { return view.extend({ load: function () { return Promise.all([ - L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['report', 'json']), '{}'), - L.resolveDefault(fs.exec_direct('/usr/sbin/nft', ['-tj', 'list', 'ruleset']), '{}') + L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['report', 'json']), ''), + L.resolveDefault(fs.exec_direct('/usr/sbin/nft', ['-tj', 'list', 'ruleset']), '') ]); }, render: function (report) { - var content; - content = JSON.parse(report[0]); + let content, rowSets, tblSets; - var rows_sets = []; - var tbl_sets = E('table', { 'class': 'table', 'id': 'sets' }, [ + if (report[0]) { + content = JSON.parse(report[0]); + } else { + content = ""; + } + rowSets = []; + tblSets = E('table', { 'class': 'table', 'id': 'sets' }, [ E('tr', { 'class': 'tr table-titles' }, [ E('th', { 'class': 'th' }, _('Set')), E('th', { 'class': 'th right', 'style': 'padding-right: 20px' }, _('Elements')), @@ -152,12 +160,12 @@ return view.extend({ ]); if (content.sets) { - var cnt1, cnt2, cnt3; + let cnt1, cnt2, cnt3; Object.keys(content.sets).forEach(function (key) { cnt1 = content.sets[key].cnt_input ? ': (' + content.sets[key].cnt_input + ')' : ''; cnt2 = content.sets[key].cnt_forwardwan ? ': (' + content.sets[key].cnt_forwardwan + ')' : ''; cnt3 = content.sets[key].cnt_forwardlan ? ': (' + content.sets[key].cnt_forwardlan + ')' : ''; - rows_sets.push([ + rowSets.push([ E('em', key), E('em', { 'style': 'padding-right: 20px' }, content.sets[key].cnt_elements), E('em', content.sets[key].input + cnt1), @@ -165,7 +173,7 @@ return view.extend({ E('em', content.sets[key].lan_forward + cnt3) ]); }); - rows_sets.push([ + rowSets.push([ E('em', { 'style': 'font-weight: bold' }, content.sum_sets), E('em', { 'style': 'font-weight: bold; padding-right: 20px' }, content.sum_setelements), E('em', { 'style': 'font-weight: bold' }, content.sum_setinput + ' (' + content.sum_cntinput + ')'), @@ -173,7 +181,7 @@ return view.extend({ E('em', { 'style': 'font-weight: bold' }, content.sum_setforwardlan + ' (' + content.sum_cntforwardlan + ')') ]); } - cbi_update_table(tbl_sets, rows_sets); + cbi_update_table(tblSets, rowSets); return E('div', { 'class': 'cbi-map', 'id': 'map' }, [ E('div', { 'class': 'cbi-section' }, [ @@ -208,8 +216,7 @@ return view.extend({ '\xa0\xa0\xa0', E('button', { 'class': 'btn cbi-button cbi-button-positive', - 'click': ui.createHandlerFn(this, async function () { - L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['report', 'json']), ''); + 'click': ui.createHandlerFn(this, function () { location.reload(); }) }, [_('Refresh')]) @@ -220,7 +227,7 @@ return view.extend({ E('div', { 'class': 'cbi-section' }, [ E('div', { 'class': 'left' }, [ E('h3', _('Set details')), - tbl_sets + tblSets ]) ]) ]); |