diff --git a/internal/locales/de.json b/internal/locales/de.json index 3889827..7493fa5 100644 --- a/internal/locales/de.json +++ b/internal/locales/de.json @@ -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", diff --git a/internal/locales/de_ch.json b/internal/locales/de_ch.json index eacaeea..9fe6daf 100644 --- a/internal/locales/de_ch.json +++ b/internal/locales/de_ch.json @@ -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", diff --git a/internal/locales/en.json b/internal/locales/en.json index 1fb2474..8cf2806 100644 --- a/internal/locales/en.json +++ b/internal/locales/en.json @@ -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", diff --git a/internal/locales/es.json b/internal/locales/es.json index 334e12f..3738390 100644 --- a/internal/locales/es.json +++ b/internal/locales/es.json @@ -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", diff --git a/internal/locales/fr.json b/internal/locales/fr.json index 55b9663..af139e8 100644 --- a/internal/locales/fr.json +++ b/internal/locales/fr.json @@ -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", diff --git a/internal/locales/it.json b/internal/locales/it.json index 03d9f4b..dce92a4 100644 --- a/internal/locales/it.json +++ b/internal/locales/it.json @@ -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", diff --git a/internal/storage/storage.go b/internal/storage/storage.go index 2259031..a9fc932 100644 --- a/internal/storage/storage.go +++ b/internal/storage/storage.go @@ -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() +} diff --git a/pkg/web/handlers.go b/pkg/web/handlers.go index 133c0d7..737bb2e 100644 --- a/pkg/web/handlers.go +++ b/pkg/web/handlers.go @@ -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 { diff --git a/pkg/web/routes.go b/pkg/web/routes.go index 0f4792a..a44d2ca 100644 --- a/pkg/web/routes.go +++ b/pkg/web/routes.go @@ -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) diff --git a/pkg/web/static/js/dashboard.js b/pkg/web/static/js/dashboard.js index 892cb7d..6f5096f 100644 --- a/pkg/web/static/js/dashboard.js +++ b/pkg/web/static/js/dashboard.js @@ -483,7 +483,7 @@ function renderLogOverviewContent() { var todayCount = totalBansToday(); var weekCount = totalBansWeek(); if (statsKeys.length === 0 && totalStored === 0) { - html += '
No ban events recorded yet.
'; + //html += 'No ban events recorded yet.
'; } else { html += '' + 'No permanent blocks recorded yet.