Added new clear function-calls for the recent-stored-events and as well the permanent-block list

This commit is contained in:
2026-02-21 17:23:33 +01:00
parent c85d51edd6
commit 3e06cfc1ab
12 changed files with 138 additions and 11 deletions

View File

@@ -62,6 +62,9 @@
"logs.overview.total_events": "Gespeicherte Ereignisse gesamt",
"logs.overview.per_server": "Ereignisse pro Server",
"logs.overview.recent_events_title": "Letzte gespeicherte Ereignisse",
"logs.overview.clear_events": "Leeren",
"logs.overview.clear_events_confirm": "Damit werden alle gespeicherten Ban-Ereignisse unwiderruflich gelöscht. Statistiken, Insights und der gesamte Ereignisverlauf werden auf Null zurückgesetzt.\n\nDiese Aktion kann nicht rückgängig gemacht werden. Fortfahren?",
"logs.overview.clear_events_success": "Alle gespeicherten Ereignisse gelöscht.",
"logs.overview.recent_empty": "Keine gespeicherten Ereignisse gefunden.",
"logs.overview.empty": "Es wurden noch keine Sperr-Ereignisse protokolliert.",
"logs.overview.open_insights": "Insights öffnen",
@@ -247,6 +250,9 @@
"settings.advanced.opnsense.alias": "Alias-Name",
"settings.advanced.opnsense.skip_tls": "TLS-Validierung überspringen (Self-Signed)",
"settings.advanced.log_title": "Log der permanenten Sperren",
"settings.advanced.clear_log": "Leeren",
"settings.advanced.clear_log_confirm": "Damit wird das gesamte Sperrprotokoll unwiderruflich gelöscht. Fail2ban UI geht danach davon aus, dass keine IPs auf der externen Firewall gesperrt sind.\n\nDiese Aktion kann nicht rückgängig gemacht werden. Fortfahren?",
"settings.advanced.clear_log_success": "Permanentes Sperrprotokoll geleert.",
"settings.advanced.log_empty": "Noch keine permanenten Sperren vorhanden.",
"settings.advanced.log_ip": "IP",
"settings.advanced.log_integration": "Integration",

View File

@@ -51,17 +51,20 @@
"dashboard.manual_block.confirm": "IP {ip} im Jail {jail} sperre?",
"dashboard.manual_block.success": "IP erfolgriich g'sperrt",
"dashboard.manual_block.error": "Fehler bim Sperre vo dr IP",
"dashboard.manual_block.jail_required": "Bitte wähl es Jail us",
"dashboard.manual_block.jail_required": "Bitte wähu es Jail us",
"dashboard.manual_block.ip_required": "Bitte gib e IP-Adrässe ii",
"dashboard.manual_block.invalid_ip": "Bitte gib e gültigi IP-Adrässe ii",
"dashboard.banned.show_more": "Meh azeige",
"dashboard.banned.show_less": "Weniger azeige",
"logs.overview.title": "Generelli Log-Übersicht",
"logs.overview.subtitle": "Vom Fail2ban-UI gspeichereti Ereigniss über alli Connectorä.",
"logs.overview.subtitle": "Vom Fail2ban-UI gspeichereti Ereigniss über aui Connectorä.",
"logs.overview.refresh": "Date aktualisiere",
"logs.overview.total_events": "Total gspeichereti Ereigniss",
"logs.overview.per_server": "Ereigniss pro Server",
"logs.overview.recent_events_title": "Letschti gspeichereti Ereigniss",
"logs.overview.clear_events": "Lääre",
"logs.overview.clear_events_confirm": "Damit wärde aui gspeicherete Ban-Ereigniss unwiderueflich glöscht. Statistike, Insights und de ganz Ereignisverlauf wärded uf Null zrugggsetzt.\n\nDas chan nöd rückgängig gmacht werde. Wiiterfahre?",
"logs.overview.clear_events_success": "Aui gspeicherete Ereigniss glöscht.",
"logs.overview.recent_empty": "No keni gspeichereti Ereigniss gfunde.",
"logs.overview.empty": "No keni Sperr-Ereigniss protokolliert.",
"logs.overview.open_insights": "Insights azeige",
@@ -85,7 +88,7 @@
"logs.search.label": "Ereigniss sueche",
"logs.search.placeholder": "IP, Jail oder Server sueche",
"logs.search.country_label": "Land",
"logs.search.country_all": "Alli Länder",
"logs.search.country_all": "Aui Länder",
"logs.search.country_unknown": "Unbekannt",
"logs.badge.recurring": "Widerkehrend",
"logs.modal.whois_title": "Whois-Informatione",
@@ -170,11 +173,11 @@
"settings.send_test_email": "Test-Email schicke",
"settings.send_test_email_hint": "⚠️ Bitte speichere zersch dini SMTP-Iistellige, bevor du e Test-Email schicksch.",
"settings.fail2ban": "Globale Standard-Fail2Ban-Konfiguratione",
"settings.fail2ban.description": "Die Einstellige werde uf alli aktivierte Fail2Ban-Server aagwändet und i däre jail.local [DEFAULT]-Abschnitt gspeicheret.",
"settings.fail2ban.description": "Die Einstellige werde uf aui aktivierte Fail2Ban-Server aagwändet und i däre jail.local [DEFAULT]-Abschnitt gspeicheret.",
"settings.enable_bantime_increment": "Bantime-Inkrement aktivierä",
"settings.enable_bantime_increment.description": "Wenn uf true gsetzt, wird d Bantime nach dr Formle: bantime = findtime * (Aazahl vo de Fähler / maxretry) * (1 + bantime.rndtime) berechnet.",
"settings.default_jail_enable": "Jails standardmässig aktivieren",
"settings.default_jail_enable.description": "Wenn aktiviert, werde alli Jails standardmässig aktiviert. Wenn deaktiviert, mues jedes Jails explizit aktiviert werde.",
"settings.default_jail_enable.description": "Wenn aktiviert, werde aui Jails standardmässig aktiviert. Wenn deaktiviert, mues jedes Jails explizit aktiviert werde.",
"settings.default_bantime": "Standard-Bantime",
"settings.default_bantime.description": "D Aazahl vo de Sekunde, wo ä Host gsperrt wird. Zytformat: 1m = 1 Minute, 1h = 1 Stund, 1d = 1 Tag, 1w = 1 Woche, 1mo = 1 Monet, 1y = 1 Jahr.",
"settings.default_bantime_placeholder": "z.B. 48h",
@@ -185,7 +188,7 @@
"settings.default_chain.description": "iptables/nftables-Chain für Bans (z.B. INPUT für Host, DOCKER-USER für Docker-Container).",
"settings.chain_help_title": "Standard-Chain",
"settings.chain_docker_user": "DOCKER-USER",
"settings.chain_help_docker_user": "Für Aawändige i Docker. Bans gäute für alli Container uf em Host.",
"settings.chain_help_docker_user": "Für Aawändige i Docker. Bans gäute für aui Container uf em Host.",
"settings.chain_input": "INPUT",
"settings.chain_help_input": "Für Aawändige uf em Host. Bans gäute nur für s Host-Netz, nid für Docker-Netz.",
"settings.chain_forward": "FORWARD",
@@ -193,7 +196,7 @@
"settings.banaction": "Banaction",
"settings.banaction.description": "Standard-Sperraktione (z.B. nftables-multiport, nftables-allports, firewallcmd-rich-rules, etc). Wird brucht, zum action_* Variablen z definiere.",
"settings.banaction_allports": "Banaction Allports",
"settings.banaction_allports.description": "Sperraktione für alli Ports (z.B. nftables-allports, firewallcmd-allports, etc). Wird brucht, wänn ä Jail alli Ports statt spezifischi Ports sperre muess.",
"settings.banaction_allports.description": "Sperraktione für aui Ports (z.B. nftables-allports, firewallcmd-allports, etc). Wird brucht, wänn ä Jail aui Ports statt spezifischi Ports sperre muess.",
"settings.default_findtime": "Standard-Findtime",
"settings.default_findtime.description": "Ä Host wird gsperrt, wenn er i de letschte 'findtime' Sekunde 'maxretry' Fähler generiert het. Zytformat: 1m = 1 Minute, 1h = 1 Stund, 1d = 1 Tag, 1w = 1 Woche, 1mo = 1 Monet, 1y = 1 Jahr.",
"settings.default_findtime_placeholder": "z.B. 30m",
@@ -247,6 +250,9 @@
"settings.advanced.opnsense.alias": "Alias-Name",
"settings.advanced.opnsense.skip_tls": "TLS-Prüfig überspringe (Self-Signed)",
"settings.advanced.log_title": "Permanent gsperrti IPs",
"settings.advanced.clear_log": "Leere",
"settings.advanced.clear_log_confirm": "Damit wird s ganze Sperrprotokoll unwiderueflich glöscht. Fail2ban UI gaht denn dervo uus, dass kei IPs uf de externe Firewall gsperrt sind.\n\nDas chan nöd rückgängig gmacht werde. Wiiterfahre?",
"settings.advanced.clear_log_success": "Permanents Sperrprotokoll gleert.",
"settings.advanced.log_empty": "No ke permanenti Sperrig erfasst.",
"settings.advanced.log_ip": "IP",
"settings.advanced.log_integration": "Integration",
@@ -391,7 +397,7 @@
"lotr.email.title": "E dunkle Diener isch verbannt worde",
"lotr.email.intro": "D Wächter vo Mittelerde hei e Bedrohig erkannt und us dim Riich verbannt.",
"lotr.email.you_shall_not_pass": "DU DARFSCH NID VERBII",
"lotr.email.footer": "Möge d Server gschützt si. E Bann, um si alli z beherrsche.",
"lotr.email.footer": "Möge d Server gschützt si. E Bann, um si aui z beherrsche.",
"lotr.email.details.dark_servant_location": "Dr Ort vom garstige Ork",
"lotr.email.details.realm_protection": "S Riich vom Schutz",
"lotr.email.details.origins": "Herkunft us de",

View File

@@ -62,6 +62,9 @@
"logs.overview.total_events": "Total stored events",
"logs.overview.per_server": "Events per server",
"logs.overview.recent_events_title": "Recent stored events",
"logs.overview.clear_events": "Clear",
"logs.overview.clear_events_confirm": "This will permanently delete all stored ban events. Statistics, insights, and the event history will be reset to zero.\n\nThis action cannot be undone. Continue?",
"logs.overview.clear_events_success": "All stored ban events cleared.",
"logs.overview.recent_empty": "No stored events found.",
"logs.overview.empty": "No ban events recorded yet.",
"logs.overview.open_insights": "Open insights",
@@ -247,6 +250,9 @@
"settings.advanced.opnsense.alias": "Alias Name",
"settings.advanced.opnsense.skip_tls": "Skip TLS verification (self-signed)",
"settings.advanced.log_title": "Permanent Block Log",
"settings.advanced.clear_log": "Clear",
"settings.advanced.clear_log_confirm": "This will permanently delete the entire block log. Fail2ban UI will assume that no IPs are currently blocked on the external firewall.\n\nThis action cannot be undone. Continue?",
"settings.advanced.clear_log_success": "Permanent block log cleared.",
"settings.advanced.log_empty": "No permanent blocks recorded yet.",
"settings.advanced.log_ip": "IP",
"settings.advanced.log_integration": "Integration",

View File

@@ -62,6 +62,9 @@
"logs.overview.total_events": "Eventos almacenados totales",
"logs.overview.per_server": "Eventos por servidor",
"logs.overview.recent_events_title": "Eventos almacenados recientes",
"logs.overview.clear_events": "Vaciar",
"logs.overview.clear_events_confirm": "Esto eliminará permanentemente todos los eventos de baneo almacenados. Las estadísticas, los análisis y el historial de eventos se restablecerán a cero.\n\nEsta acción no se puede deshacer. ¿Continuar?",
"logs.overview.clear_events_success": "Todos los eventos almacenados han sido eliminados.",
"logs.overview.recent_empty": "No se encontraron eventos almacenados.",
"logs.overview.empty": "Aún no se han registrado eventos de bloqueo.",
"logs.overview.open_insights": "Abrir estadísticas",
@@ -247,6 +250,9 @@
"settings.advanced.opnsense.alias": "Nombre del alias",
"settings.advanced.opnsense.skip_tls": "Omitir verificación TLS (autofirmado)",
"settings.advanced.log_title": "Registro de bloqueos permanentes",
"settings.advanced.clear_log": "Vaciar",
"settings.advanced.clear_log_confirm": "Esto eliminará permanentemente todo el registro de bloqueos. Fail2ban UI asumirá que no hay IPs bloqueadas actualmente en el firewall externo.\n\nEsta acción no se puede deshacer. ¿Continuar?",
"settings.advanced.clear_log_success": "Registro de bloqueos permanentes vaciado.",
"settings.advanced.log_empty": "Aún no hay bloqueos permanentes.",
"settings.advanced.log_ip": "IP",
"settings.advanced.log_integration": "Integración",

View File

@@ -62,6 +62,9 @@
"logs.overview.total_events": "Total d'événements enregistrés",
"logs.overview.per_server": "Événements par serveur",
"logs.overview.recent_events_title": "Événements enregistrés récents",
"logs.overview.clear_events": "Vider",
"logs.overview.clear_events_confirm": "Ceci supprimera définitivement tous les événements de bannissement stockés. Les statistiques, les aperçus et l'historique seront remis à zéro.\n\nCette action est irréversible. Continuer ?",
"logs.overview.clear_events_success": "Tous les événements stockés ont été supprimés.",
"logs.overview.recent_empty": "Aucun événement stocké trouvé.",
"logs.overview.empty": "Aucun événement de blocage n'a encore été enregistré.",
"logs.overview.open_insights": "Ouvrir les insights",
@@ -247,6 +250,9 @@
"settings.advanced.opnsense.alias": "Nom d'alias",
"settings.advanced.opnsense.skip_tls": "Ignorer la vérification TLS (auto-signé)",
"settings.advanced.log_title": "Journal des blocages permanents",
"settings.advanced.clear_log": "Vider",
"settings.advanced.clear_log_confirm": "Ceci supprimera définitivement tout le journal de blocage. Fail2ban UI considérera qu'aucune IP n'est actuellement bloquée sur le pare-feu externe.\n\nCette action est irréversible. Continuer ?",
"settings.advanced.clear_log_success": "Journal des blocages permanents vidé.",
"settings.advanced.log_empty": "Aucun blocage permanent pour le moment.",
"settings.advanced.log_ip": "IP",
"settings.advanced.log_integration": "Intégration",

View File

@@ -62,6 +62,9 @@
"logs.overview.total_events": "Eventi memorizzati totali",
"logs.overview.per_server": "Eventi per server",
"logs.overview.recent_events_title": "Eventi memorizzati recenti",
"logs.overview.clear_events": "Svuota",
"logs.overview.clear_events_confirm": "Questo eliminerà definitivamente tutti gli eventi di ban memorizzati. Le statistiche, gli approfondimenti e la cronologia degli eventi verranno azzerati.\n\nQuesta azione non può essere annullata. Continuare?",
"logs.overview.clear_events_success": "Tutti gli eventi memorizzati sono stati eliminati.",
"logs.overview.recent_empty": "Nessun evento memorizzato trovato.",
"logs.overview.empty": "Nessun evento di blocco è stato ancora registrato.",
"logs.overview.open_insights": "Apri insights",
@@ -247,6 +250,9 @@
"settings.advanced.opnsense.alias": "Nome alias",
"settings.advanced.opnsense.skip_tls": "Ignora verifica TLS (auto-firmato)",
"settings.advanced.log_title": "Registro dei blocchi permanenti",
"settings.advanced.clear_log": "Svuota",
"settings.advanced.clear_log_confirm": "Questo eliminerà definitivamente l'intero registro dei blocchi. Fail2ban UI considererà che nessun IP è attualmente bloccato sul firewall esterno.\n\nQuesta azione non può essere annullata. Continuare?",
"settings.advanced.clear_log_success": "Registro dei blocchi permanenti svuotato.",
"settings.advanced.log_empty": "Nessun blocco permanente ancora registrato.",
"settings.advanced.log_ip": "IP",
"settings.advanced.log_integration": "Integrazione",

View File

@@ -878,6 +878,18 @@ WHERE 1=1`
return result, rows.Err()
}
// Deletes all ban event records.
func ClearBanEvents(ctx context.Context) (int64, error) {
if db == nil {
return 0, errors.New("storage not initialised")
}
res, err := db.ExecContext(ctx, `DELETE FROM ban_events`)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
// =========================================================================
// Recurring IP Statistics
// =========================================================================
@@ -1263,3 +1275,15 @@ func IsPermanentBlockActive(ctx context.Context, ip, integration string) (bool,
}
return rec.Status == "blocked", nil
}
// Deletes all permanent block records.
func ClearPermanentBlocks(ctx context.Context) (int64, error) {
if db == nil {
return 0, errors.New("storage not initialised")
}
res, err := db.ExecContext(ctx, `DELETE FROM permanent_blocks`)
if err != nil {
return 0, err
}
return res.RowsAffected()
}

View File

@@ -555,6 +555,16 @@ func BanInsightsHandler(c *gin.Context) {
})
}
// Deletes all stored ban event records.
func ClearBanEventsHandler(c *gin.Context) {
deleted, err := storage.ClearBanEvents(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"deleted": deleted})
}
// =========================================================================
// Fail2ban Servers Management
// =========================================================================
@@ -1631,6 +1641,16 @@ func ListPermanentBlocksHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"blocks": records})
}
// Deletes all permanent block records.
func ClearPermanentBlocksHandler(c *gin.Context) {
deleted, err := storage.ClearPermanentBlocks(c.Request.Context())
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"deleted": deleted})
}
// Allows manual block/unblock against the configured integration.
func AdvancedActionsTestHandler(c *gin.Context) {
var req struct {

View File

@@ -80,6 +80,7 @@ func RegisterRoutes(r *gin.Engine, hub *Hub) {
// Internal API calls for advanced actions
api.GET("/advanced-actions/blocks", ListPermanentBlocksHandler)
api.DELETE("/advanced-actions/blocks", ClearPermanentBlocksHandler)
api.POST("/advanced-actions/test", AdvancedActionsTestHandler)
// Internal API calls for Fail2ban-UI server management
@@ -95,6 +96,7 @@ func RegisterRoutes(r *gin.Engine, hub *Hub) {
// Internal API calls to get the stats of the bans
api.GET("/events/bans", ListBanEventsHandler)
api.DELETE("/events/bans", ClearBanEventsHandler)
api.GET("/events/bans/stats", BanStatisticsHandler)
api.GET("/events/bans/insights", BanInsightsHandler)

View File

@@ -483,7 +483,7 @@ function renderLogOverviewContent() {
var todayCount = totalBansToday();
var weekCount = totalBansWeek();
if (statsKeys.length === 0 && totalStored === 0) {
html += '<p class="text-gray-500" data-i18n="logs.overview.empty">No ban events recorded yet.</p>';
//html += '<p class="text-gray-500" data-i18n="logs.overview.empty">No ban events recorded yet.</p>';
} else {
html += ''
+ '<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">'
@@ -531,7 +531,10 @@ function renderLogOverviewContent() {
}
html += ' </tbody></table></div></div>';
}
html += '<h4 class="text-md font-semibold text-gray-800 mb-3" data-i18n="logs.overview.recent_events_title">Recent stored events</h4>';
html += '<div class="flex items-center justify-between mb-3">'
+ '<h4 class="text-md font-semibold text-gray-800" data-i18n="logs.overview.recent_events_title">Recent stored events</h4>'
+ '<button type="button" class="px-3 py-1.5 text-xs rounded border border-red-300 text-red-600 hover:bg-red-50" onclick="clearStoredBanEvents()" data-i18n="logs.overview.clear_events">Clear</button>'
+ '</div>';
var countries = getBanEventCountries();
var recurringMap = getRecurringIPMap();
var searchQuery = (banEventsFilterText || '').trim();
@@ -649,6 +652,28 @@ function loadMoreBanEvents() {
});
}
function clearStoredBanEvents() {
var msg = t('logs.overview.clear_events_confirm',
'This will permanently delete all stored ban events. Statistics, insights, and the event history will be reset to zero.\n\nThis action cannot be undone. Continue?');
if (!confirm(msg)) return;
fetch('/api/events/bans', { method: 'DELETE', headers: serverHeaders() })
.then(function(res) { return res.json(); })
.then(function(data) {
if (data.error) {
showToast(data.error, 'error');
return;
}
showToast(t('logs.overview.clear_events_success', 'All stored ban events cleared.'), 'success');
latestBanEvents = [];
latestBanStats = {};
latestBanInsights = null;
banEventsTotal = 0;
banEventsHasMore = false;
renderLogOverviewSection();
})
.catch(function(err) { showToast(String(err), 'error'); });
}
// Filtering function for the banned IPs for the dashboard.
function filterIPs() {
const input = document.getElementById("ipSearch");

View File

@@ -479,6 +479,23 @@ function refreshPermanentBlockLog() {
loadPermanentBlockLog();
}
function clearPermanentBlockLog() {
var msg = t('settings.advanced.clear_log_confirm',
'This will permanently delete the entire block log. Fail2ban UI will assume that no IPs are currently blocked on the external firewall.\n\nThis action cannot be undone. Continue?');
if (!confirm(msg)) return;
fetch('/api/advanced-actions/blocks', { method: 'DELETE', headers: serverHeaders() })
.then(function(res) { return res.json(); })
.then(function(data) {
if (data.error) {
showToast(data.error, 'error');
return;
}
showToast(t('settings.advanced.clear_log_success', 'Permanent block log cleared.'), 'success');
loadPermanentBlockLog();
})
.catch(function(err) { showToast(String(err), 'error'); });
}
// =========================================================================
// Advanced Test
// =========================================================================

View File

@@ -454,7 +454,10 @@
</div>
</div>
<div class="mt-6">
<h4 class="text-md font-semibold text-gray-800 mb-2" data-i18n="settings.advanced.log_title">Permanent Block Log</h4>
<div class="flex items-center justify-between mb-2">
<h4 class="text-md font-semibold text-gray-800" data-i18n="settings.advanced.log_title">Permanent Block Log</h4>
<button type="button" class="px-3 py-1.5 text-xs rounded border border-red-300 text-red-600 hover:bg-red-50" onclick="clearPermanentBlockLog()" data-i18n="settings.advanced.clear_log">Clear</button>
</div>
<div id="permanentBlockLog" class="overflow-x-auto border border-gray-200 rounded-md">
<p class="text-sm text-gray-500 p-4" data-i18n="settings.advanced.log_empty">No permanent blocks recorded yet.</p>
</div>