]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Last Run')),
- E('div', { 'class': 'cbi-value-field', 'id': 'last', 'style': 'margin - bottom:- 5px; color:#37c; ' }, ' - ')
+ E('div', { 'class': 'cbi-value-field', 'id': 'last', 'style': 'margin-bottom:- 5px; color:#37c; ' }, ' - ')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('System Info')),
LUCI_TITLE:=LuCI support for banIP
LUCI_DEPENDS:=+luci-base +banip
-PKG_VERSION:=1.8.0
-PKG_RELEASE:=3
+PKG_VERSION:=1.8.1
+PKG_RELEASE:=1
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
'require ui';
const localFile = '/etc/banip/banip.allowlist';
-let notMsg = false, errMsg = false;
+const maxSize = 100000;
+let notMsg = false;
const resetScroll = () => {
document.body.scrollTop = document.documentElement.scrollTop = 0;
return view.extend({
load: function () {
- return L.resolveDefault(fs.stat(localFile), "")
+ return L.resolveDefault(fs.stat(localFile), null)
.then(function (stat) {
- if (!stat) {
- return fs.write(localFile, "");
- }
- return Promise.all([
- L.resolveDefault(fs.stat(localFile), ""),
- L.resolveDefault(fs.read_direct(localFile), "")
- ]);
- });
+ if (!stat) {
+ return fs.write(localFile, "").then(() => [{ size: 0 }, ""]);
+ }
+ return Promise.all([
+ Promise.resolve(stat),
+ L.resolveDefault(fs.read_direct(localFile), "")
+ ]);
+ });
},
+
render: function (allowlist) {
- if (allowlist[0] && allowlist[0].size >= 100000) {
+ const size = allowlist[0] ? allowlist[0].size : 0;
+ const content = allowlist[1] != null ? allowlist[1] : '';
+ const tooBig = size >= maxSize;
+
+ if (tooBig) {
resetScroll();
ui.addNotification(null, E('p', _('The allowlist is too big, unable to save modifications.')), 'error');
}
'style': 'width: 100% !important; padding: 5px; font-family: monospace; margin-top: .4em',
'spellcheck': 'false',
'wrap': 'off',
- 'rows': 25
- }, [allowlist[1] != null ? allowlist[1] : ''])
+ 'rows': 25,
+ 'readonly': tooBig ? 'readonly' : null,
+ 'input': function () { notMsg = false; }
+ }, [content])
]);
},
- handleSave: function (ev) {
- let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n?/g, '\n'));
+
+ handleSave: function (_ev) {
+ const value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n?/g, '\n'));
return fs.write(localFile, value + "\n")
- .then(function () {
- document.querySelector('textarea').value = value;
- resetScroll();
- if (!notMsg) {
- ui.addNotification(null, E('p', _('Allowlist modifications have been saved, reload banIP that changes take effect.')), 'info');
- notMsg = true;
- }
- }).catch(function (e) {
- resetScroll();
- if (!errMsg) {
+ .then(function () {
+ document.querySelector('textarea').value = value + "\n";
+ resetScroll();
+ if (!notMsg) {
+ notMsg = true;
+ ui.addNotification(null, E('p', _('Allowlist modifications have been saved, reload banIP that changes take effect.')), 'info');
+ }
+ }).catch(function (e) {
+ resetScroll();
ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error');
- errMsg = true;
- }
- });
+ });
},
+
handleSaveApply: null,
handleReset: null
-});
+});
\ No newline at end of file
'require ui';
const localFile = '/etc/banip/banip.blocklist';
-let notMsg = false, errMsg = false;
+const maxSize = 100000;
+let notMsg = false;
const resetScroll = () => {
document.body.scrollTop = document.documentElement.scrollTop = 0;
return view.extend({
load: function () {
- return L.resolveDefault(fs.stat(localFile), "")
+ return L.resolveDefault(fs.stat(localFile), null)
.then(function (stat) {
- if (!stat) {
- return fs.write(localFile, "");
- }
- return Promise.all([
- L.resolveDefault(fs.stat(localFile), ""),
- L.resolveDefault(fs.read_direct(localFile), "")
- ]);
- });
+ if (!stat) {
+ return fs.write(localFile, "").then(() => [{ size: 0 }, ""]);
+ }
+ return Promise.all([
+ Promise.resolve(stat),
+ L.resolveDefault(fs.read_direct(localFile), "")
+ ]);
+ });
},
+
render: function (blocklist) {
- if (blocklist[0] && blocklist[0].size >= 100000) {
+ const size = blocklist[0] ? blocklist[0].size : 0;
+ const content = blocklist[1] != null ? blocklist[1] : '';
+ const tooBig = size >= maxSize;
+
+ if (tooBig) {
resetScroll();
ui.addNotification(null, E('p', _('The blocklist is too big, unable to save modifications.')), 'error');
}
'style': 'width: 100% !important; padding: 5px; font-family: monospace; margin-top: .4em',
'spellcheck': 'false',
'wrap': 'off',
- 'rows': 25
- }, [blocklist[1] != null ? blocklist[1] : ''])
+ 'rows': 25,
+ 'readonly': tooBig ? 'readonly' : null,
+ 'input': function () { notMsg = false; }
+ }, [content])
]);
},
- handleSave: function (ev) {
- let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n?/g, '\n'));
+
+ handleSave: function (_ev) {
+ const value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\r\n?/g, '\n'));
return fs.write(localFile, value + "\n")
- .then(function () {
- document.querySelector('textarea').value = value;
- resetScroll();
- if (!notMsg) {
- ui.addNotification(null, E('p', _('Blocklist modifications have been saved, reload banIP that changes take effect.')), 'info');
- notMsg = true;
- }
- }).catch(function (e) {
- resetScroll();
- if (!errMsg) {
+ .then(function () {
+ document.querySelector('textarea').value = value + "\n";
+ resetScroll();
+ if (!notMsg) {
+ notMsg = true;
+ ui.addNotification(null, E('p', _('Blocklist modifications have been saved, reload banIP that changes take effect.')), 'info');
+ }
+ }).catch(function (e) {
+ resetScroll();
ui.addNotification(null, E('p', _('Unable to save modifications: %s').format(e.message)), 'error');
- errMsg = true;
- }
- });
+ });
},
+
handleSaveApply: null,
handleReset: null
-});
+});
\ No newline at end of file
'href': L.resource('view/banip/custom.css')
}));
+/*
+ module-level file size set during render, read by observer
+*/
+let fileSize = 0;
+
+/*
+ button state helper
+*/
+function updateButtons() {
+ const buttons = document.querySelectorAll('#btnClear, #btnCreate, #btnSave, #btnUpload, #btnDownload');
+ if (fileSize === 0) {
+ if (buttons[1]) buttons[1].removeAttribute('disabled');
+ if (buttons[2]) buttons[2].removeAttribute('disabled');
+ } else {
+ if (buttons[0]) buttons[0].removeAttribute('disabled');
+ if (buttons[3]) buttons[3].removeAttribute('disabled');
+ if (buttons[4]) buttons[4].removeAttribute('disabled');
+ }
+}
+
/*
observe DOM changes
*/
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');
- }
- });
+ updateButtons();
}
});
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;
+ if (data && Object.keys(data).length > 0) {
+ for (let i = 0; i < Object.keys(data).length; i++) {
+ let feed = Object.keys(data)[i];
+ let descr = data[feed].descr;
+ if (feed && descr) {
+ continue;
}
- } else {
- fs.write('/etc/banip/banip.custom.feeds', null).then(function () {
+ return 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 () {
+ return fs.write('/etc/banip/banip.custom.feeds', null).then(function () {
ui.addNotification(null, E('p', _('Upload of the custom feed file failed.')), 'error');
});
}
}
}
/*
- gather all input data
+ gather all input data and fall through from 'save'
*/
- let sumSubElements = [];
+ const exportObj = {};
const nodeKeys = document.querySelectorAll('[id^="widget.cbid.json"][id$="name"]');
for (const keyNode of nodeKeys) {
const keyValue = keyNode.value?.trim();
sub[key] = value;
}
}
- if (sub.descr) {
- sumSubElements.push(keyValue, sub);
+ /* require at least descr and rule to produce a valid feed entry */
+ if (sub.descr && sub.rule && (sub.url_4 || sub.url_6)) {
+ exportObj[keyValue] = sub;
}
}
- /*
- construct json object
- */
- let exportObj = {};
- for (let i = 0; i < sumSubElements.length; i += 2) {
- const key = sumSubElements[i];
- const value = sumSubElements[i + 1];
- exportObj[key] = value;
- }
- const exportJson = JSON.stringify(exportObj, null, 4);
/*
save to file and reload
*/
+ const exportJson = JSON.stringify(exportObj, null, 4);
return fs.write('/etc/banip/banip.custom.feeds', exportJson)
.then(() => location.reload());
}
return view.extend({
load: function () {
- return L.resolveDefault(fs.stat('/etc/banip/banip.custom.feeds'), "")
+ return L.resolveDefault(fs.stat('/etc/banip/banip.custom.feeds'), null)
.then(function (stat) {
if (!stat) {
- return fs.write('/etc/banip/banip.custom.feeds', "");
+ return fs.write('/etc/banip/banip.custom.feeds', "").then(function () {
+ return { size: 0, data: null };
+ });
}
- return L.resolveDefault(fs.read_direct('/etc/banip/banip.custom.feeds', 'json'), "");
- })
+ return L.resolveDefault(fs.read_direct('/etc/banip/banip.custom.feeds', 'json'), "")
+ .then(function (data) {
+ return { size: stat.size, data: data };
+ });
+ });
},
- render: function (data) {
+ render: function (result) {
let m, s, o, feed, url_4, url_6, rule, chain, descr, flag;
+ const data = result.data;
+ fileSize = result.size;
m = new form.JSONMap(data, null, _('With this editor you can upload your local custom feed file or fill up an initial one (a 1:1 copy of the version shipped with the package). \
The file is located at \'/etc/banip/banip.custom.feeds\'. \
if (!value) {
return true;
}
- if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-\?\&\+_@%=:~#]+$/)) {
+ if (!value.match(/^https?:\/\/[A-Za-z0-9\[\]\/.\-?&+_@%=:~#]+$/)) {
return _('Protocol/URL format not supported');
}
return true;
if (!value) {
return true;
}
- if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-\?\&\+_@%=:~#]+$/)) {
+ if (!value.match(/^https?:\/\/[A-Za-z0-9\[\]\/.\-?&+_@%=:~#]+$/)) {
return _('Protocol/URL format not supported');
}
return true;
handleSaveApply: null,
handleSave: null,
handleReset: null
-});
+});
\ No newline at end of file
return L.view.extend({
load: () => Promise.resolve(),
- render: () => {
- L.Poll.add(() => {
+ render: function () {
+ const pollFn = () => {
return callLogRead(1000, false, true).then(res => {
const logEl = document.getElementById('logfile');
if (!logEl) return;
const filtered = (res?.log ?? [])
- .filter(entry => !logtag || entry.msg.includes(logtag))
- .map(entry => {
- const d = new Date(entry.time);
- const date = d.toLocaleDateString([], {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit'
+ .filter(entry => !logtag || entry.msg.includes(logtag))
+ .map(entry => {
+ const d = new Date(entry.time * 1000);
+ const date = d.toLocaleDateString([], {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit'
+ });
+ const time = d.toLocaleTimeString([], {
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ hour12: false
+ });
+ return `[${date}-${time}] ${entry.msg}`;
});
- const time = d.toLocaleTimeString([], {
- hour: '2-digit',
- minute: '2-digit',
- second: '2-digit',
- hour12: false
- });
- return `[${date}-${time}] ${entry.msg}`;
- });
- if (filtered.length > 0) {
- logEl.value = filtered.join('\n');
- } else {
- logEl.value = _('No %s related logs yet!').format(name);
- }
+
+ logEl.value = filtered.length > 0
+ ? filtered.join('\n')
+ : _('No %s related logs yet!').format(name);
logEl.scrollTop = logEl.scrollHeight;
});
- });
+ };
+
+ this._pollFn = pollFn;
+ L.Poll.add(pollFn);
return E('div', { class: 'cbi-map' }, [
E('div', { class: 'cbi-section' }, [
]);
},
+ unload: function () {
+ if (this._pollFn) {
+ L.Poll.remove(this._pollFn);
+ this._pollFn = null;
+ }
+ },
+
handleSaveApply: null,
handleSave: null,
handleReset: null
});
}
-return L.Class.extend({ Logview });
+return L.Class.extend({ Logview });
\ No newline at end of file
/*
poll runtime information
*/
+ let parseErrCount = 0;
poll.add(function () {
- return L.resolveDefault(fs.read_direct('/var/run/banip_runtime.json'), 'null').then(function (res) {
- const status = document.getElementById('status');
- const buttons = document.querySelectorAll('.cbi-page-actions button');
- try {
- var info = JSON.parse(res);
- } catch (e) {
- status.textContent = '-';
- if (status.classList.contains('spinning')) {
- buttons.forEach(function (btn) {
- btn.disabled = false;
- })
- status.classList.remove('spinning');
- }
- ui.addNotification(null, E('p', _('Unable to parse the runtime information!')), 'error');
+ return L.resolveDefault(fs.stat('/var/run/banip_runtime.json'), null).then(function (stat) {
+ if (!stat) {
return;
}
- if (status && info) {
- status.textContent = `${info.status || '-'} (frontend: ${info.frontend_ver || '-'} / backend: ${info.backend_ver || '-'})`;
- if (info.status === "processing") {
- if (!status.classList.contains("spinning")) {
- status.classList.add("spinning");
- }
- buttons.forEach(function (btn) {
- btn.disabled = true;
- btn.blur();
- })
- } else {
- if (status.classList.contains("spinning")) {
+ return L.resolveDefault(fs.read_direct('/var/run/banip_runtime.json'), 'null').then(function (res) {
+ const status = document.getElementById('status');
+ const buttons = document.querySelectorAll('.cbi-page-actions button');
+ let info = null;
+ try {
+ info = JSON.parse(res);
+ parseErrCount = 0;
+ } catch (e) {
+ info = null;
+ parseErrCount++;
+ if (status) {
+ status.textContent = '-';
buttons.forEach(function (btn) {
btn.disabled = false;
- })
- status.classList.remove("spinning");
+ });
+ status.classList.remove('spinning');
+ if (parseErrCount >= 3) {
+ ui.addNotification(null, E('p', _('Unable to parse the banIP runtime information!')), 'error');
+ poll.stop();
+ }
}
+ return;
}
- }
- if (info) {
- setText('elements', info.element_count);
- setText('feeds', info.active_feeds?.join(', '));
- setText('devices', `wan-dev: ${info.wan_devices?.join(', ') || '-'} /
+ if (status && info) {
+ status.textContent = `${info.status || '-'} (frontend: ${info.frontend_ver || '-'} / backend: ${info.backend_ver || '-'})`;
+ if (info.status === "processing") {
+ buttons.forEach(function (btn) {
+ btn.disabled = true;
+ btn.blur();
+ });
+ if (!status.classList.contains("spinning")) {
+ status.classList.add("spinning");
+ }
+ } else {
+ if (status.classList.contains("spinning")) {
+ status.classList.remove("spinning");
+ buttons.forEach(function (btn) {
+ btn.disabled = false;
+ });
+ }
+ }
+ }
+ if (info) {
+ setText('elements', info.element_count);
+ setText('feeds', info.active_feeds?.join(', ') || '-');
+ setText('devices', `wan-dev: ${info.wan_devices?.join(', ') || '-'} /
wan-if: ${info.wan_interfaces?.join(', ') || '-'} /
vlan-allow: ${info.vlan_allow?.join(', ') || '-'} /
vlan-block: ${info.vlan_block?.join(', ') || '-'}`);
- setText('uplink', info.active_uplink?.join(', ') || '-');
- setText('nft', info.nft_info);
- setText('run', info.run_info);
- setText('flags', info.run_flags);
- setText('last', info.last_run);
- setText('sys', info.system_info);
- }
+ setText('uplink', info.active_uplink?.join(', ') || '-');
+ setText('nft', info.nft_info);
+ setText('run', info.run_info);
+ setText('flags', info.run_flags);
+ setText('last', info.last_run);
+ setText('sys', info.system_info);
+ }
+ });
});
}, 2);
o.optional = true;
o.retain = true;
- o = s.taboption('general', form.Value, 'ban_fetchparm', _('Download Parameters'), _('Override the pre-configured download options for the selected download utility.'))
+ o = s.taboption('general', form.Value, 'ban_fetchparm', _('Download Parameters'), _('Override the pre-configured download options for the selected download utility.'));
o.depends('ban_autodetect', '0');
o.optional = true;
o.retain = true;
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.default = 1;
o.rmempty = false;
/*
o.optional = true;
o.rmempty = true;
- o = s.taboption('adv_set', form.MultiValue, 'ban_feedfreset', _('Feed Flag Reset'), _('Override the default feed configuration and remove existing port/protocol limitations.'));
+ o = s.taboption('adv_set', form.MultiValue, 'ban_feedreset', _('Feed Flag Reset'), _('Override the default feed configuration and remove existing port/protocol limitations.'));
o.value('allowlist', _('local allowlist'));
o.value('blocklist', _('local blocklist'));
feedKeys.forEach(f => o.value(f.trim()));
o.rmempty = true;
o = s.taboption('adv_log', form.Flag, 'ban_remotelog', _('Enable Remote Logging'), _('Enable the cgi interface to receive remote logging events.'));
- o.default = 0
+ o.default = 0;
o.optional = true;
o.rmempty = true;
return _('Invalid characters');
}
return true;
- }
+ };
o.optional = true;
o.rmempty = true;
*/
o = s.taboption('adv_email', form.DummyValue, '_sub');
o.rawhtml = true;
- o.default = '<em style="color:#37c;font-weight:bold;">' + _('To enable email notifications, set up the \'msmtp\' package and specify a vaild E-Mail receiver address.') + '</em>'
+ o.default = '<em style="color:#37c;font-weight:bold;">' + _('To enable email notifications, set up the \'msmtp\' package and specify a valid E-Mail receiver address.') + '</em>'
+ '<hr style="width: 200px; height: 1px;" />';
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('feeds', form.DummyValue, '_feeds');
+ o = s.taboption('feeds', form.DummyValue, '_feeds1');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('Country Selection') + '</em>';
o = s.taboption('feeds', form.Flag, 'ban_countrysplit', _('Split Country Set'), _('The selected Countries are stored in separate Sets.'));
o.rmempty = true;
- o = s.taboption('feeds', form.DummyValue, '_feeds');
+ o = s.taboption('feeds', form.DummyValue, '_feeds2');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('ASN Selection') + '</em>';
o = s.taboption('feeds', form.Flag, 'ban_asnsplit', _('Split ASN Set'), _('The selected ASNs are stored in separate Sets.'));
o.rmempty = true;
- o = s.taboption('feeds', form.DummyValue, '_feeds');
+ o = s.taboption('feeds', form.DummyValue, '_feeds3');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('External Allowlist Feeds') + '</em>';
return _('Invalid URL format');
}
return true;
- }
+ };
}
- o = s.taboption('feeds', form.DummyValue, '_feeds');
+ o = s.taboption('feeds', form.DummyValue, '_feeds4');
o.rawhtml = true;
o.default = '<hr style="width: 200px; height: 1px;" /><em style="color:#37c;font-weight:bold;">' + _('Local Feed Settings') + '</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.default = 1;
o.rmempty = false;
o = s.taboption('feeds', form.ListValue, 'ban_autoallowuplink', _('Auto Allow Uplink'), _('Limit the uplink autoallow function.'));
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.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.default = 0;
o.optional = true;
o.rmempty = true;
if (!value) {
return true;
}
- if (!value.match(/^[1-9][0-9]*(ms|s|m|h|d|w)$/)) {
- return _('Invalid expiry format');
+ if (!value.match(/^([1-9][0-9]*(ms|s|m|h|d|w))+$/)) {
+ return _('Invalid expiry format, e.g. 5m, 2h, 1d or 1h30m');
}
return true;
};
return handleAction('restart');
})
}, [_('Save & Restart')])
- ])
+ ]);
});
return m.render();
},
/*
button handling
*/
+let errMsg = false;
+
function handleAction(report, ev) {
if (ev === 'search') {
ui.showModal(_('IP Search'), [
document.getElementById('search').focus();
}
if (ev === 'content') {
- let content, selectOption, errMsg;
+ let content, selectOption;
if (report[1]) {
try {
}
selectOption = [E('option', { value: '' }, [_('-- Set Selection --')])];
Object.keys(content.nftables)
- .filter(key => content.nftables[key].set?.name && content.nftables[key].set.table === 'banIP')
- .sort((a, b) => content.nftables[a].set.name.localeCompare(content.nftables[b].set.name))
- .forEach(key => {
- selectOption.push(E('option', { 'value': content.nftables[key].set.name }, content.nftables[key].set.name));
- })
+ .filter(key => content.nftables[key].set?.name && content.nftables[key].set.table === 'banIP')
+ .sort((a, b) => content.nftables[a].set.name.localeCompare(content.nftables[b].set.name))
+ .forEach(key => {
+ selectOption.push(E('option', { 'value': content.nftables[key].set.name }, content.nftables[key].set.name));
+ })
ui.showModal(_('Set Content'), [
E('p', _('List the elements of a specific banIP-related Set.')),
E('div', { 'class': 'left', 'style': 'display:flex; flex-direction:column' }, [
'class': 'btn cbi-button-action',
'click': ui.createHandlerFn(this, function (ev) {
const checkbox = document.getElementById('chkFilter');
- const isChecked = checkbox.checked;
+ const isChecked = checkbox.checked ? 'true' : 'false';
let set = document.getElementById('set').value;
if (set) {
document.getElementById('result').textContent = 'Collecting Set content, please wait...';
}
if (ev === 'map') {
const modal = ui.showModal(null, [
- E('div', { id: 'mapModal',
- style: 'position: relative;' }, [
+ E('div', {
+ id: 'mapModal',
+ style: 'position: relative;'
+ }, [
E('iframe', {
id: 'mapFrame',
src: L.resource('view/banip/map.html'),
},
render: function (report) {
- let content=[], rowSets, tblSets, notMsg, errMsg;
+ let content = [], rowSets, tblSets, notMsg;
if (report) {
try {
E('em', content[0].sets[key].inbound + cnt1),
E('em', content[0].sets[key].outbound + cnt2),
E('em', content[0].sets[key].port),
- E('em', content[0].sets[key].set_elements.join(", "))
+ E('em', content[0].sets[key].set_elements.join(", "))
]);
});
rowSets.push([
You can also display the specific content of Sets, search for suspicious IPs and finally, these IPs can also be displayed on a map.')),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;width:230px;font-weight:bold;' }, _('Timestamp')),
- E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-bottom:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.timestamp || '-')
+ E('div', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.timestamp || '-')
]),
E('hr'),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked syn-flood packets')),
- E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_synflood || '-')
+ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_synflood || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked udp-flood packets')),
- E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_udpflood || '-')
+ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_udpflood || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked icmp-flood packets')),
- E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_icmpflood || '-')
+ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_icmpflood || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked invalid ct packets')),
- E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_ctinvalid || '-')
+ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_ctinvalid || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked invalid tcp packets')),
- E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_tcpinvalid || '-')
+ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_tcpinvalid || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('blocked bcp38 packets')),
- E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_bcp38 || '-')
+ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.sum_bcp38 || '-')
]),
E('hr'),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('auto-added IPs to allowlist')),
- E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.autoadd_allow || '-')
+ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.autoadd_allow || '-')
]),
E('div', { 'class': 'cbi-value' }, [
E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;width:230px;font-weight:bold;' }, _('auto-added IPs to blocklist')),
- E('div', { 'class': 'cbi-value-title', 'id': 'start', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.autoadd_block || '-')
+ E('div', { 'class': 'cbi-value-title', 'style': 'margin-top:-5px;color:#37c;font-weight:bold;' }, content?.[0]?.autoadd_block || '-')
])
]),
E('br'),
'id': 'btnMap',
'disabled': 'disabled',
'click': ui.createHandlerFn(this, function () {
- if (content[1] && content[1].length > 1) {
+ if (Array.isArray(content[1]) && content[1].length > 1) {
sessionStorage.setItem('mapData', JSON.stringify(content[1]));
return handleAction(report, 'map');
- }
- else {
+ } else {
if (!notMsg) {
notMsg = true;
return ui.addNotification(null, E('p', _('No GeoIP Map data!')), 'info');
'class': 'btn cbi-button cbi-button-positive important',
'style': 'float:none',
'click': function () {
- document.querySelectorAll('.cbi-page-actions button').forEach(function(btn) {
- btn.disabled = true;
- })
- this.blur();
- this.classList.add('spinning');
+ const btn = this;
+ document.querySelectorAll('.cbi-page-actions button').forEach(function (b) {
+ b.disabled = true;
+ });
+ btn.blur();
+ btn.classList.add('spinning');
L.resolveDefault(fs.exec_direct('/etc/init.d/banip', ['report', 'gen']))
- .then(function () {
- location.reload();
- })
+ .then(function (res) {
+ if (res !== null) {
+ location.reload();
+ } else {
+ btn.classList.remove('spinning');
+ document.querySelectorAll('.cbi-page-actions button').forEach(function (b) {
+ b.disabled = false;
+ });
+ ui.addNotification(null, E('p', _('Failed to generate banIP report!')), 'error');
+ }
+ });
}
}, [_('Refresh')])
])