luci-app-banip: sync with banIP-0.8.4-1
authorDirk Brenken <dev@brenken.org>
Fri, 28 Apr 2023 10:39:50 +0000 (12:39 +0200)
committerDirk Brenken <dev@brenken.org>
Fri, 28 Apr 2023 10:39:50 +0000 (12:39 +0200)
* add a custom feed editor (req. >= banIP-0.8.4-1)
* various small fixes and enhancements

Signed-off-by: Dirk Brenken <dev@brenken.org>
(cherry picked from commit 876c9b292d0a5d3915dd6e085a0a3c0dbe3f16ac)
Signed-off-by: Dirk Brenken <dev@brenken.org>
applications/luci-app-banip/htdocs/luci-static/resources/view/banip/allowlist.js
applications/luci-app-banip/htdocs/luci-static/resources/view/banip/blocklist.js
applications/luci-app-banip/htdocs/luci-static/resources/view/banip/custom.css [new file with mode: 0644]
applications/luci-app-banip/htdocs/luci-static/resources/view/banip/feeds.js [new file with mode: 0644]
applications/luci-app-banip/htdocs/luci-static/resources/view/banip/overview.js
applications/luci-app-banip/htdocs/luci-static/resources/view/banip/setreport.js
applications/luci-app-banip/root/usr/share/luci/menu.d/luci-app-banip.json
applications/luci-app-banip/root/usr/share/rpcd/acl.d/luci-app-banip.json

index c4b847026227d09794d5ee7107e3bd30ed2f5f00..e70222c0236099b0cef1372a6daddd12c8f14c4d 100644 (file)
@@ -11,17 +11,20 @@ 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;
+                               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) {
+                               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([
index e9e654effde84acd3055c77cbb418e8050578997..22391cc9823941f253a4d1d58446b2577a140ae9 100644 (file)
@@ -11,17 +11,20 @@ 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;
+                               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) {
+                               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([
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 (file)
index 0000000..4125e88
--- /dev/null
@@ -0,0 +1,3 @@
+.cbi-input-text {
+       width: 90% !important;
+}
\ No newline at end of file
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 (file)
index 0000000..672b23d
--- /dev/null
@@ -0,0 +1,234 @@
+'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');
+                       if (buttons[0] && stat.size === 0) {
+                               buttons[0].removeAttribute('disabled');
+                       } else if (buttons[1] && buttons[2] && stat.size > 0) {
+                               buttons[1].removeAttribute('disabled');
+                               buttons[2].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 === '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 || "";
+                       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;
+                       }
+               }
+               sumSubElements.push(nodeKeys[i].value, subElements);
+       }
+       exportJson = JSON.stringify(sumSubElements).replace(/,{/g, ':{').replace(/^\[/g, '{').replace(/\]$/g, '}');
+       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 fill up an initial custom feed file (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, etc. 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 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
+});
index dcc0c9518c570c84914cafe9a849d1c7acdfa7dd..ce6a0832b070ff3f0ace5ac668a7bb39f7d5ff00 100644 (file)
@@ -7,6 +7,9 @@
 'require form';
 'require tools.widgets as widgets';
 
+/*
+       button handling
+*/
 function handleAction(ev) {
        fs.exec_direct('/etc/init.d/banip', [ev])
 }
@@ -14,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')
@@ -21,7 +25,7 @@ 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. \
                        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>'));
@@ -29,110 +33,110 @@ return view.extend({
                /*
                        poll runtime information
                */
-               var buttons, rt_res, inf_stat, inf_version, inf_elements, inf_feeds, inf_devices, inf_subnets, inf_system, nft_infos, run_infos, inf_flags, last_run
+               let buttons, rtRes, infStat, infVer, infElements, infFeeds, infDevices, infSubnets, infSystem, nftInfos, runInfos, infFlags, last_run
 
                pollData: poll.add(function () {
                        return L.resolveDefault(fs.stat('/var/run/banip.lock')).then(function (stat) {
                                buttons = document.querySelectorAll('.cbi-button');
-                               inf_stat = document.getElementById('status');
+                               infStat = document.getElementById('status');
                                if (stat) {
-                                       for (var i = 0; i < buttons.length; i++) {
+                                       for (let i = 0; i < buttons.length; i++) {
                                                buttons[i].setAttribute('disabled', 'true');
                                        }
-                                       if (inf_stat && !inf_stat.classList.contains('spinning')) {
-                                               inf_stat.classList.add('spinning');
+                                       if (infStat && !infStat.classList.contains('spinning')) {
+                                               infStat.classList.add('spinning');
                                        }
                                } else {
-                                       for (var i = 0; i < buttons.length; i++) {
+                                       for (let i = 0; i < buttons.length; i++) {
                                                buttons[i].removeAttribute('disabled');
                                        }
-                                       if (inf_stat && inf_stat.classList.contains('spinning')) {
-                                               inf_stat.classList.remove('spinning');
+                                       if (infStat && infStat.classList.contains('spinning')) {
+                                               infStat.classList.remove('spinning');
                                        }
                                }
                                L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['status'])).then(function (result) {
                                        if (result) {
-                                               rt_res = result.trim().split('\n');
-                                               if (rt_res) {
-                                                       for (var i = 0; i < rt_res.length; i++) {
-                                                               if (rt_res[i].match(/^\s+\+\sstatus\s+\:\s+(.*)$/)) {
-                                                                       rt_res.status = rt_res[i].match(/^\s+\+\sstatus\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\sversion\s+\:\s+(.*)$/)) {
-                                                                       rt_res.version = rt_res[i].match(/^\s+\+\sversion\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\selement_count\s+\:\s+(.*)$/)) {
-                                                                       rt_res.element_count = rt_res[i].match(/^\s+\+\selement_count\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\sactive_feeds\s+\:\s+(.*)$/)) {
-                                                                       rt_res.active_feeds = rt_res[i].match(/^\s+\+\sactive_feeds\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\sactive_devices\s+\:\s+(.*)$/)) {
-                                                                       rt_res.active_devices = rt_res[i].match(/^\s+\+\sactive_devices\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\sactive_subnets\s+\:\s+(.*)$/)) {
-                                                                       rt_res.active_subnets = rt_res[i].match(/^\s+\+\sactive_subnets\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\snft_info\s+\:\s+(.*)$/)) {
-                                                                       rt_res.nft_info = rt_res[i].match(/^\s+\+\snft_info\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\srun_info\s+\:\s+(.*)$/)) {
-                                                                       rt_res.run_info = rt_res[i].match(/^\s+\+\srun_info\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\srun_flags\s+\:\s+(.*)$/)) {
-                                                                       rt_res.run_flags = rt_res[i].match(/^\s+\+\srun_flags\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\slast_run\s+\:\s+(.*)$/)) {
-                                                                       rt_res.last_run = rt_res[i].match(/^\s+\+\slast_run\s+\:\s+(.*)$/)[1];
-                                                               } else if (rt_res[i].match(/^\s+\+\ssystem_info\s+\:\s+(.*)$/)) {
-                                                                       rt_res.system_info = rt_res[i].match(/^\s+\+\ssystem_info\s+\:\s+(.*)$/)[1];
+                                               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_subnets\s+\:\s+(.*)$/)) {
+                                                                       rtRes.activeSubnets = rtRes[i].match(/^\s+\+\sactive_subnets\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];
                                                                }
                                                        }
                                                }
-                                               if (rt_res) {
-                                                       inf_stat = document.getElementById('status');
-                                                       if (inf_stat) {
-                                                               inf_stat.textContent = rt_res.status || '-';
+                                               if (rtRes) {
+                                                       infStat = document.getElementById('status');
+                                                       if (infStat) {
+                                                               infStat.textContent = rtRes.status || '-';
                                                        }
-                                                       inf_version = document.getElementById('version');
-                                                       if (inf_version) {
-                                                               inf_version.textContent = rt_res.version || '-';
+                                                       infVer = document.getElementById('version');
+                                                       if (infVer) {
+                                                               infVer.textContent = rtRes.version || '-';
                                                        }
-                                                       inf_elements = document.getElementById('elements');
-                                                       if (inf_elements) {
-                                                               inf_elements.textContent = rt_res.element_count || '-';
+                                                       infElements = document.getElementById('elements');
+                                                       if (infElements) {
+                                                               infElements.textContent = rtRes.elementCount || '-';
                                                        }
-                                                       inf_feeds = document.getElementById('feeds');
-                                                       if (inf_feeds) {
-                                                               inf_feeds.textContent = rt_res.active_feeds || '-';
+                                                       infFeeds = document.getElementById('feeds');
+                                                       if (infFeeds) {
+                                                               infFeeds.textContent = rtRes.activeFeeds || '-';
                                                        }
-                                                       inf_devices = document.getElementById('devices');
-                                                       if (inf_devices) {
-                                                               inf_devices.textContent = rt_res.active_devices || '-';
+                                                       infDevices = document.getElementById('devices');
+                                                       if (infDevices) {
+                                                               infDevices.textContent = rtRes.activeDevices || '-';
                                                        }
-                                                       inf_subnets = document.getElementById('subnets');
-                                                       if (inf_subnets) {
-                                                               inf_subnets.textContent = rt_res.active_subnets || '-';
+                                                       infSubnets = document.getElementById('subnets');
+                                                       if (infSubnets) {
+                                                               infSubnets.textContent = rtRes.activeSubnets || '-';
                                                        }
-                                                       nft_infos = document.getElementById('nft');
-                                                       if (nft_infos) {
-                                                               nft_infos.textContent = rt_res.nft_info || '-';
+                                                       nftInfos = document.getElementById('nft');
+                                                       if (nftInfos) {
+                                                               nftInfos.textContent = rtRes.nftInfo || '-';
                                                        }
-                                                       run_infos = document.getElementById('run');
-                                                       if (run_infos) {
-                                                               run_infos.textContent = rt_res.run_info || '-';
+                                                       runInfos = document.getElementById('run');
+                                                       if (runInfos) {
+                                                               runInfos.textContent = rtRes.runInfo || '-';
                                                        }
-                                                       inf_flags = document.getElementById('flags');
-                                                       if (inf_flags) {
-                                                               inf_flags.textContent = rt_res.run_flags || '-';
+                                                       infFlags = document.getElementById('flags');
+                                                       if (infFlags) {
+                                                               infFlags.textContent = rtRes.runFlags || '-';
                                                        }
                                                        last_run = document.getElementById('last');
                                                        if (last_run) {
-                                                               last_run.textContent = rt_res.last_run || '-';
+                                                               last_run.textContent = rtRes.lastRun || '-';
                                                        }
-                                                       inf_system = document.getElementById('system');
-                                                       if (inf_system) {
-                                                               inf_system.textContent = rt_res.system_info || '-';
+                                                       infSystem = document.getElementById('system');
+                                                       if (infSystem) {
+                                                               infSystem.textContent = rtRes.systemInfo || '-';
                                                        }
                                                }
                                        } else {
-                                               inf_stat = document.getElementById('status');
-                                               if (inf_stat) {
-                                                       inf_stat.textContent = '-';
+                                               infStat = document.getElementById('status');
+                                               if (infStat) {
+                                                       infStat.textContent = '-';
                                                        poll.stop();
-                                                       if (inf_stat.classList.contains('spinning')) {
-                                                               inf_stat.classList.remove('spinning');
+                                                       if (infStat.classList.contains('spinning')) {
+                                                               infStat.classList.remove('spinning');
                                                        }
                                                }
                                        }
@@ -193,7 +197,7 @@ return view.extend({
                                ]),
                                E('div', { class: 'right' }, [
                                        E('button', {
-                                               'class': 'btn cbi-button cbi-button-apply',
+                                               'class': 'btn cbi-button cbi-button-action',
                                                'click': ui.createHandlerFn(this, function () {
                                                        return handleAction('lookup');
                                                })
@@ -397,13 +401,13 @@ return view.extend({
                o.rawhtml = true;
                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)'));
@@ -412,14 +416,24 @@ return view.extend({
                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.'));
                        o.value('allowlist', _('local allowlist'));
                        o.value('blocklist', _('local blocklist'));
-                       for (var i = 0; i < Object.keys(feeds).length; i++) {
+                       for (let i = 0; i < Object.keys(feeds).length; i++) {
                                feed = Object.keys(feeds)[i].trim();
                                o.value(feed);
                        }
@@ -429,7 +443,7 @@ return view.extend({
                        o = s.taboption('adv_chain', form.MultiValue, 'ban_blockforwardwan', _('WAN-Forward Chain'), _('Limit certain feeds to the WAN-Forward chain.'));
                        o.value('allowlist', _('local allowlist'));
                        o.value('blocklist', _('local blocklist'));
-                       for (var i = 0; i < Object.keys(feeds).length; i++) {
+                       for (let i = 0; i < Object.keys(feeds).length; i++) {
                                feed = Object.keys(feeds)[i].trim();
                                o.value(feed);
                        }
@@ -439,7 +453,7 @@ return view.extend({
                        o = s.taboption('adv_chain', form.MultiValue, 'ban_blockforwardlan', _('LAN-Forward Chain'), _('Limit certain feeds to the LAN-Forward chain.'));
                        o.value('allowlist', _('local allowlist'));
                        o.value('blocklist', _('local blocklist'));
-                       for (var i = 0; i < Object.keys(feeds).length; i++) {
+                       for (let i = 0; i < Object.keys(feeds).length; i++) {
                                feed = Object.keys(feeds)[i].trim();
                                o.value(feed);
                        }
@@ -472,11 +486,11 @@ 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.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'));
@@ -528,15 +542,12 @@ return view.extend({
                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]);
-
+               if (feeds) {
                        o = s.taboption('feeds', form.MultiValue, 'ban_feed', _('Feed Selection'));
-                       for (var i = 0; i < Object.keys(feeds).length; i++) {
+                       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;
@@ -545,12 +556,12 @@ return view.extend({
                /*
                        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);
index acad67e289dd202a015ccc561033059a599178ae..97d8e2b24399662eb2eeb6b6e939576252fdd8d8 100644 (file)
@@ -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,17 +65,17 @@ function handleAction(report, ev) {
                document.getElementById('search').focus();
        }
        if (ev === 'survey') {
-               var content, selectO;
+               let content, selectOption;
 
                if (report[1]) {
                        content = JSON.parse(report[1]);
                } else {
                        content = "";
                }
-               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));
+               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'), [
@@ -84,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
                                        )
                                ]),
                        ]),
@@ -108,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 {
@@ -141,15 +141,15 @@ return view.extend({
        },
 
        render: function (report) {
-               var content;
+               let content, rowSets, tblSets;
 
                if (report[0]) {
                        content = JSON.parse(report[0]);
                } else {
                        content = "";
                }
-               var rows_sets = [];
-               var tbl_sets = E('table', { 'class': 'table', 'id': 'sets' }, [
+               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')),
@@ -160,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),
@@ -173,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 + ')'),
@@ -181,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' }, [
@@ -216,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')])
@@ -228,7 +227,7 @@ return view.extend({
                        E('div', { 'class': 'cbi-section' }, [
                                E('div', { 'class': 'left' }, [
                                        E('h3', _('Set details')),
-                                       tbl_sets
+                                       tblSets
                                ])
                        ])
                ]);
index 6402b04160ca62b88717d9480aa637e37ac02434..fbc998df6db78b9776b81f8bf2551a03c71c8927 100644 (file)
@@ -14,6 +14,7 @@
                                "/usr/bin/banip-service.sh": "executable",
                                "/etc/init.d/banip": "executable",
                                "/etc/banip/banip.feeds": "file",
+                               "/etc/banip/banip.custom.feeds": "file",
                                "/etc/banip/banip.allowlist": "file",
                                "/etc/banip/banip.blocklist": "file",
                                "/etc/banip/banip.countries": "file"
                        "path": "banip/blocklist"
                }
        },
+       "admin/services/banip/feeds": {
+               "title": "Edit Custom Feeds",
+               "order": 40,
+               "action": {
+                       "type": "view",
+                       "path": "banip/feeds"
+               }
+       },
        "admin/services/banip/setreport": {
                "title": "Set Reporting",
-               "order": 40,
+               "order": 50,
                "action": {
                        "type": "view",
                        "path": "banip/setreport"
@@ -57,7 +66,7 @@
        },
        "admin/services/banip/firewall_log": {
                "title": "Firewall Log",
-               "order": 50,
+               "order": 60,
                "action": {
                        "type": "view",
                        "path": "banip/firewall_log"
@@ -65,7 +74,7 @@
        },
        "admin/services/banip/processing_log": {
                "title": "Processing Log",
-               "order": 60,
+               "order": 70,
                "action": {
                        "type": "view",
                        "path": "banip/processing_log"
index 9993b10679d842b8ee3f0af83781ec0a9f38be6c..395e06aadc72099149150688c65007ab776c3a73 100644 (file)
@@ -2,9 +2,6 @@
        "luci-app-banip": {
                "description": "Grant access to LuCI app banIP",
                "write": {
-                       "uci": [
-                               "banip"
-                       ],
                        "file": {
                                "/etc/banip/*": [
                                        "read"
                                "/etc/banip/banip.blocklist": [
                                        "write"
                                ],
-                               "/etc/banip/banip.feeds": [
+                               "/etc/banip/banip.custom.feeds": [
                                        "write"
                                ]
-                       }
+                       },
+                       "uci": [
+                               "banip"
+                       ]
                },
                "read": {
                        "cgi-io": [