luci-app-banip: release 1.8.1-1

* sync with base package

Signed-off-by: Dirk Brenken <dev@brenken.org>
This commit is contained in:
Dirk Brenken
2026-03-15 18:21:18 +01:00
parent 38600b1af8
commit 86bc7f71eb
8 changed files with 271 additions and 223 deletions

View File

@@ -180,7 +180,7 @@ return view.extend({
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('Last Run')),
E('div', { 'class': 'cbi-value-field', 'id': 'last', 'style': 'margin - bottom:- 5px; color:#37c; ' }, ' - ')
E('div', { 'class': 'cbi-value-field', 'id': 'last', 'style': 'margin-bottom:- 5px; color:#37c; ' }, ' - ')
]),
E('div', { 'class': 'cbi-value' }, [
E('label', { 'class': 'cbi-value-title', 'style': 'margin-bottom:-5px;padding-top:0rem;' }, _('System Info')),

View File

@@ -6,8 +6,8 @@ include $(TOPDIR)/rules.mk
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>

View File

@@ -4,7 +4,8 @@
'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;
@@ -12,19 +13,24 @@ const resetScroll = () => {
return view.extend({
load: function () {
return L.resolveDefault(fs.stat(localFile), "")
return L.resolveDefault(fs.stat(localFile), null)
.then(function (stat) {
if (!stat) {
return fs.write(localFile, "");
}
return Promise.all([
L.resolveDefault(fs.stat(localFile), ""),
L.resolveDefault(fs.read_direct(localFile), "")
]);
});
if (!stat) {
return fs.write(localFile, "").then(() => [{ size: 0 }, ""]);
}
return Promise.all([
Promise.resolve(stat),
L.resolveDefault(fs.read_direct(localFile), "")
]);
});
},
render: function (allowlist) {
if (allowlist[0] && allowlist[0].size >= 100000) {
const size = allowlist[0] ? allowlist[0].size : 0;
const content = allowlist[1] != null ? allowlist[1] : '';
const tooBig = size >= maxSize;
if (tooBig) {
resetScroll();
ui.addNotification(null, E('p', _('The allowlist is too big, unable to save modifications.')), 'error');
}
@@ -35,28 +41,29 @@ return view.extend({
'style': 'width: 100% !important; padding: 5px; font-family: monospace; margin-top: .4em',
'spellcheck': 'false',
'wrap': 'off',
'rows': 25
}, [allowlist[1] != null ? allowlist[1] : ''])
'rows': 25,
'readonly': tooBig ? 'readonly' : null,
'input': function () { notMsg = false; }
}, [content])
]);
},
handleSave: function (ev) {
let value = ((document.querySelector('textarea').value || '').trim().toLowerCase().replace(/\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
});
});

View File

@@ -4,7 +4,8 @@
'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;
@@ -12,19 +13,24 @@ const resetScroll = () => {
return view.extend({
load: function () {
return L.resolveDefault(fs.stat(localFile), "")
return L.resolveDefault(fs.stat(localFile), null)
.then(function (stat) {
if (!stat) {
return fs.write(localFile, "");
}
return Promise.all([
L.resolveDefault(fs.stat(localFile), ""),
L.resolveDefault(fs.read_direct(localFile), "")
]);
});
if (!stat) {
return fs.write(localFile, "").then(() => [{ size: 0 }, ""]);
}
return Promise.all([
Promise.resolve(stat),
L.resolveDefault(fs.read_direct(localFile), "")
]);
});
},
render: function (blocklist) {
if (blocklist[0] && blocklist[0].size >= 100000) {
const size = blocklist[0] ? blocklist[0].size : 0;
const content = blocklist[1] != null ? blocklist[1] : '';
const tooBig = size >= maxSize;
if (tooBig) {
resetScroll();
ui.addNotification(null, E('p', _('The blocklist is too big, unable to save modifications.')), 'error');
}
@@ -35,28 +41,29 @@ return view.extend({
'style': 'width: 100% !important; padding: 5px; font-family: monospace; margin-top: .4em',
'spellcheck': 'false',
'wrap': 'off',
'rows': 25
}, [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
});
});

View File

@@ -13,6 +13,26 @@ document.querySelector('head').appendChild(E('link', {
'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
*/
@@ -29,17 +49,7 @@ const observer = new MutationObserver(function (mutations) {
labels.forEach(function (label) {
label.setAttribute("style", "font-weight: bold !important; color: #595 !important;");
})
L.resolveDefault(fs.stat('/etc/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();
}
});
@@ -59,29 +69,20 @@ 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;
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');
});
}
@@ -120,9 +121,9 @@ function handleEdit(ev) {
}
}
/*
gather all input data
gather all input data and fall through from 'save'
*/
let sumSubElements = [];
const exportObj = {};
const nodeKeys = document.querySelectorAll('[id^="widget.cbid.json"][id$="name"]');
for (const keyNode of nodeKeys) {
const keyValue = keyNode.value?.trim();
@@ -144,40 +145,39 @@ function handleEdit(ev) {
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\'. \
@@ -213,7 +213,7 @@ return view.extend({
if (!value) {
return true;
}
if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-\?\&\+_@%=:~#]+$/)) {
if (!value.match(/^https?:\/\/[A-Za-z0-9\[\]\/.\-?&+_@%=:~#]+$/)) {
return _('Protocol/URL format not supported');
}
return true;
@@ -224,7 +224,7 @@ return view.extend({
if (!value) {
return true;
}
if (!value.match(/^(http:\/\/|https:\/\/)[A-Za-z0-9\/\.\-\?\&\+_@%=:~#]+$/)) {
if (!value.match(/^https?:\/\/[A-Za-z0-9\[\]\/.\-?&+_@%=:~#]+$/)) {
return _('Protocol/URL format not supported');
}
return true;
@@ -320,4 +320,4 @@ return view.extend({
handleSaveApply: null,
handleSave: null,
handleReset: null
});
});

View File

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

View File

@@ -60,56 +60,69 @@ return view.extend({
/*
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 (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(', ') || '-'} /
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);
@@ -232,7 +245,7 @@ return view.extend({
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;
@@ -331,7 +344,7 @@ return view.extend({
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;
/*
@@ -507,7 +520,7 @@ return view.extend({
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()));
@@ -592,7 +605,7 @@ return view.extend({
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;
@@ -607,7 +620,7 @@ return view.extend({
return _('Invalid characters');
}
return true;
}
};
o.optional = true;
o.rmempty = true;
@@ -616,7 +629,7 @@ return view.extend({
*/
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.'));
@@ -661,7 +674,7 @@ return view.extend({
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>';
@@ -703,7 +716,7 @@ return view.extend({
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>';
@@ -715,7 +728,7 @@ return view.extend({
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>';
@@ -743,15 +756,15 @@ return view.extend({
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.'));
@@ -766,11 +779,11 @@ return view.extend({
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;
@@ -791,8 +804,8 @@ return view.extend({
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;
};
@@ -824,7 +837,7 @@ return view.extend({
return handleAction('restart');
})
}, [_('Save & Restart')])
])
]);
});
return m.render();
},

View File

@@ -7,6 +7,8 @@
/*
button handling
*/
let errMsg = false;
function handleAction(report, ev) {
if (ev === 'search') {
ui.showModal(_('IP Search'), [
@@ -60,7 +62,7 @@ function handleAction(report, ev) {
document.getElementById('search').focus();
}
if (ev === 'content') {
let content, selectOption, errMsg;
let content, selectOption;
if (report[1]) {
try {
@@ -77,11 +79,11 @@ function handleAction(report, ev) {
}
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' }, [
@@ -126,7 +128,7 @@ function handleAction(report, ev) {
'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...';
@@ -151,8 +153,10 @@ function handleAction(report, ev) {
}
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'),
@@ -193,7 +197,7 @@ return view.extend({
},
render: function (report) {
let content=[], rowSets, tblSets, notMsg, errMsg;
let content = [], rowSets, tblSets, notMsg;
if (report) {
try {
@@ -228,7 +232,7 @@ return view.extend({
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([
@@ -249,41 +253,41 @@ return view.extend({
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'),
@@ -300,11 +304,10 @@ return view.extend({
'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');
@@ -330,15 +333,24 @@ return view.extend({
'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')])
])