mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-04-17 05:53:15 +02:00
Optimize error-reporting of failure when reloading fail2ban
This commit is contained in:
@@ -351,6 +351,8 @@
|
|||||||
"servers.form.no_keys": "Keine SSH-Schlüssel gefunden; Pfad manuell eingeben",
|
"servers.form.no_keys": "Keine SSH-Schlüssel gefunden; Pfad manuell eingeben",
|
||||||
"filter_debug.not_available": "Filter-Debug ist nur verfügbar, wenn mindestens ein registrierter Fail2ban-Server aktiviert ist.",
|
"filter_debug.not_available": "Filter-Debug ist nur verfügbar, wenn mindestens ein registrierter Fail2ban-Server aktiviert ist.",
|
||||||
"filter_debug.local_missing": "Das lokale Fail2ban-Filterverzeichnis wurde auf diesem Host nicht gefunden.",
|
"filter_debug.local_missing": "Das lokale Fail2ban-Filterverzeichnis wurde auf diesem Host nicht gefunden.",
|
||||||
|
"filter_debug.save_success": "Filter- und Jail-Konfiguration gespeichert und Fail2ban neu geladen",
|
||||||
|
"filter_debug.save_reload_warning": "Konfiguration gespeichert, aber Fail2ban-Reload fehlgeschlagen",
|
||||||
"email.ban.title": "Achtung: Fail2Ban hat eine neue IP-Adresse blockiert",
|
"email.ban.title": "Achtung: Fail2Ban hat eine neue IP-Adresse blockiert",
|
||||||
"email.ban.intro": "Fail2Ban-UI hat eine fehlerhafte Anfrage oder wiederholte Authentifizierungsfehler erkannt und die Quell-IP automatisch blockiert. Überprüfen Sie die Metadaten und Log-Auszüge unten.",
|
"email.ban.intro": "Fail2Ban-UI hat eine fehlerhafte Anfrage oder wiederholte Authentifizierungsfehler erkannt und die Quell-IP automatisch blockiert. Überprüfen Sie die Metadaten und Log-Auszüge unten.",
|
||||||
"email.ban.subject.banned": "Gesperrt",
|
"email.ban.subject.banned": "Gesperrt",
|
||||||
|
|||||||
@@ -351,6 +351,8 @@
|
|||||||
"servers.form.no_keys": "Kei SSH-Schlüssel gfunde; Pfad selber igäh",
|
"servers.form.no_keys": "Kei SSH-Schlüssel gfunde; Pfad selber igäh",
|
||||||
"filter_debug.not_available": "Filter-Debug funktioniert nur, we mindestens ei registrierte Fail2ban-Server aktiviert isch.",
|
"filter_debug.not_available": "Filter-Debug funktioniert nur, we mindestens ei registrierte Fail2ban-Server aktiviert isch.",
|
||||||
"filter_debug.local_missing": "S lokale Fail2ban-Filterverzeichnis isch uf däm Host nid gfunde worde.",
|
"filter_debug.local_missing": "S lokale Fail2ban-Filterverzeichnis isch uf däm Host nid gfunde worde.",
|
||||||
|
"filter_debug.save_success": "Filter- und Jail-Konfiguration gspicheret und Fail2ban neu glade",
|
||||||
|
"filter_debug.save_reload_warning": "Konfiguration gspicheret, aber z'Reload isch fähugschlage",
|
||||||
"email.ban.title": "Achtung: Fail2Ban het e nöi IP-Adrässe blockiert",
|
"email.ban.title": "Achtung: Fail2Ban het e nöi IP-Adrässe blockiert",
|
||||||
"email.ban.intro": "Fail2Ban-UI het e fehlerhafti Aafrag oder widerholti Authentifizierigsfähler erkennt und d Quell-IP automatisch blockiert. Überprüef d Metadate und Log-Uuszüg unge.",
|
"email.ban.intro": "Fail2Ban-UI het e fehlerhafti Aafrag oder widerholti Authentifizierigsfähler erkennt und d Quell-IP automatisch blockiert. Überprüef d Metadate und Log-Uuszüg unge.",
|
||||||
"email.ban.subject.banned": "G'sperrt",
|
"email.ban.subject.banned": "G'sperrt",
|
||||||
|
|||||||
@@ -351,6 +351,8 @@
|
|||||||
"servers.form.no_keys": "No SSH keys found; enter path manually",
|
"servers.form.no_keys": "No SSH keys found; enter path manually",
|
||||||
"filter_debug.not_available": "Filter debug is only available when at least one registered Fail2ban server is enabled.",
|
"filter_debug.not_available": "Filter debug is only available when at least one registered Fail2ban server is enabled.",
|
||||||
"filter_debug.local_missing": "The local Fail2ban filter directory was not found on this host.",
|
"filter_debug.local_missing": "The local Fail2ban filter directory was not found on this host.",
|
||||||
|
"filter_debug.save_success": "Filter and jail config saved and reloaded",
|
||||||
|
"filter_debug.save_reload_warning": "Config saved, but fail2ban reload failed",
|
||||||
"email.ban.title": "Security alert: Fail2Ban blocked a new IP-address",
|
"email.ban.title": "Security alert: Fail2Ban blocked a new IP-address",
|
||||||
"email.ban.intro": "Fail2Ban-UI detected a bad request or repeated authentication failures and automatically blocked the source-IP. Review the metadata and log excerpts below.",
|
"email.ban.intro": "Fail2Ban-UI detected a bad request or repeated authentication failures and automatically blocked the source-IP. Review the metadata and log excerpts below.",
|
||||||
"email.ban.subject.banned": "Banned",
|
"email.ban.subject.banned": "Banned",
|
||||||
|
|||||||
@@ -351,6 +351,8 @@
|
|||||||
"servers.form.no_keys": "No se encontraron claves SSH; introduzca la ruta manualmente",
|
"servers.form.no_keys": "No se encontraron claves SSH; introduzca la ruta manualmente",
|
||||||
"filter_debug.not_available": "La depuración de filtros solo está disponible cuando al menos un servidor Fail2ban registrado está activado.",
|
"filter_debug.not_available": "La depuración de filtros solo está disponible cuando al menos un servidor Fail2ban registrado está activado.",
|
||||||
"filter_debug.local_missing": "No se encontró el directorio de filtros local de Fail2ban en este host.",
|
"filter_debug.local_missing": "No se encontró el directorio de filtros local de Fail2ban en este host.",
|
||||||
|
"filter_debug.save_success": "Configuración de filtro y jail guardada y Fail2ban recargado",
|
||||||
|
"filter_debug.save_reload_warning": "Configuración guardada, pero la recarga de Fail2ban falló",
|
||||||
"email.ban.title": "Alerta de seguridad: Fail2Ban bloqueó una nueva dirección IP",
|
"email.ban.title": "Alerta de seguridad: Fail2Ban bloqueó una nueva dirección IP",
|
||||||
"email.ban.intro": "Fail2Ban-UI detectó una solicitud incorrecta o fallos de autenticación repetidos y bloqueó automáticamente la IP de origen. Revise los metadatos y extractos de registro a continuación.",
|
"email.ban.intro": "Fail2Ban-UI detectó una solicitud incorrecta o fallos de autenticación repetidos y bloqueó automáticamente la IP de origen. Revise los metadatos y extractos de registro a continuación.",
|
||||||
"email.ban.subject.banned": "Bloqueado",
|
"email.ban.subject.banned": "Bloqueado",
|
||||||
|
|||||||
@@ -351,6 +351,8 @@
|
|||||||
"servers.form.no_keys": "Aucune clé SSH trouvée ; saisissez le chemin manuellement",
|
"servers.form.no_keys": "Aucune clé SSH trouvée ; saisissez le chemin manuellement",
|
||||||
"filter_debug.not_available": "Le débogage des filtres n'est disponible que lorsqu'au moins un serveur Fail2ban enregistré est activé.",
|
"filter_debug.not_available": "Le débogage des filtres n'est disponible que lorsqu'au moins un serveur Fail2ban enregistré est activé.",
|
||||||
"filter_debug.local_missing": "Le répertoire de filtres Fail2ban local est introuvable sur cet hôte.",
|
"filter_debug.local_missing": "Le répertoire de filtres Fail2ban local est introuvable sur cet hôte.",
|
||||||
|
"filter_debug.save_success": "Configuration de filtre et jail enregistrée et Fail2ban rechargé",
|
||||||
|
"filter_debug.save_reload_warning": "Configuration enregistrée, mais le rechargement de Fail2ban a échoué",
|
||||||
"email.ban.title": "Alerte de sécurité : Fail2Ban a bloqué une nouvelle adresse IP",
|
"email.ban.title": "Alerte de sécurité : Fail2Ban a bloqué une nouvelle adresse IP",
|
||||||
"email.ban.intro": "Fail2Ban-UI a détecté une requête suspecte ou des échecs d'authentification répétés et a automatiquement bloqué l'IP source. Consultez les métadonnées et extraits de journaux ci-dessous.",
|
"email.ban.intro": "Fail2Ban-UI a détecté une requête suspecte ou des échecs d'authentification répétés et a automatiquement bloqué l'IP source. Consultez les métadonnées et extraits de journaux ci-dessous.",
|
||||||
"email.ban.subject.banned": "Bloqué",
|
"email.ban.subject.banned": "Bloqué",
|
||||||
|
|||||||
@@ -351,6 +351,8 @@
|
|||||||
"servers.form.no_keys": "Nessuna chiave SSH trovata; inserire il percorso manualmente",
|
"servers.form.no_keys": "Nessuna chiave SSH trovata; inserire il percorso manualmente",
|
||||||
"filter_debug.not_available": "Il debug dei filtri è disponibile solo quando almeno un server Fail2ban registrato è attivato.",
|
"filter_debug.not_available": "Il debug dei filtri è disponibile solo quando almeno un server Fail2ban registrato è attivato.",
|
||||||
"filter_debug.local_missing": "La directory dei filtri Fail2ban locale non è stata trovata su questo host.",
|
"filter_debug.local_missing": "La directory dei filtri Fail2ban locale non è stata trovata su questo host.",
|
||||||
|
"filter_debug.save_success": "Configurazione di filtro e jail salvata e Fail2ban ricaricato",
|
||||||
|
"filter_debug.save_reload_warning": "Configurazione salvata, ma il ricaricamento di Fail2ban non è riuscito",
|
||||||
"email.ban.title": "Allerta di sicurezza: Fail2Ban ha bloccato un nuovo indirizzo IP",
|
"email.ban.title": "Allerta di sicurezza: Fail2Ban ha bloccato un nuovo indirizzo IP",
|
||||||
"email.ban.intro": "Fail2Ban-UI ha rilevato una richiesta sospetta o ripetuti fallimenti di autenticazione e ha automaticamente bloccato l'IP sorgente. Rivedere i metadati e gli estratti di log di seguito.",
|
"email.ban.intro": "Fail2Ban-UI ha rilevato una richiesta sospetta o ripetuti fallimenti di autenticazione e ha automaticamente bloccato l'IP sorgente. Rivedere i metadati e gli estratti di log di seguito.",
|
||||||
"email.ban.subject.banned": "Bloccato",
|
"email.ban.subject.banned": "Bloccato",
|
||||||
|
|||||||
@@ -1458,12 +1458,10 @@ func SetJailFilterConfigHandler(c *gin.Context) {
|
|||||||
// Reload fail2ban
|
// Reload fail2ban
|
||||||
config.DebugLog("Reloading fail2ban")
|
config.DebugLog("Reloading fail2ban")
|
||||||
if err := conn.Reload(c.Request.Context()); err != nil {
|
if err := conn.Reload(c.Request.Context()); err != nil {
|
||||||
config.DebugLog("Failed to reload fail2ban: %v", err)
|
log.Printf("⚠️ Config saved but fail2ban reload failed: %v", err)
|
||||||
// Still return success but warn about reload failure
|
|
||||||
// The config was saved successfully, user can manually reload
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"message": "Config saved successfully, but fail2ban reload failed",
|
"message": "Config saved successfully, but fail2ban reload failed",
|
||||||
"warning": "Please check the fail2ban configuration and reload manually: " + err.Error(),
|
"warning": err.Error(),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1908,13 +1906,9 @@ func UpdateJailManagementHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update errMsg with detailed error output when debug mode is enabled
|
if detailedErrorOutput != "" {
|
||||||
settings := config.GetSettings()
|
// We use only the extracted error output
|
||||||
if settings.Debug && detailedErrorOutput != "" {
|
errMsg = strings.TrimSpace(detailedErrorOutput)
|
||||||
errMsg = fmt.Sprintf("%s\n\nDetailed error output:\n%s", errMsg, detailedErrorOutput)
|
|
||||||
} else if detailedErrorOutput != "" {
|
|
||||||
// Even without debug mode, include basic error info
|
|
||||||
errMsg = fmt.Sprintf("%s (check debug mode for details)", errMsg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If any jails were enabled in this request and reload failed, disable them all
|
// If any jails were enabled in this request and reload failed, disable them all
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ mark {
|
|||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
pointer-events: auto;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@@ -28,12 +28,37 @@ function showToast(message, type, duration) {
|
|||||||
var toast = document.createElement('div');
|
var toast = document.createElement('div');
|
||||||
var variant = type || 'info';
|
var variant = type || 'info';
|
||||||
toast.className = 'toast toast-' + variant;
|
toast.className = 'toast toast-' + variant;
|
||||||
toast.textContent = message;
|
|
||||||
|
// Build inner layout with close button
|
||||||
|
var wrapper = document.createElement('div');
|
||||||
|
wrapper.className = 'flex items-start';
|
||||||
|
|
||||||
|
var textSpan = document.createElement('span');
|
||||||
|
textSpan.className = 'flex-1';
|
||||||
|
textSpan.textContent = message;
|
||||||
|
|
||||||
|
var closeBtn = document.createElement('button');
|
||||||
|
closeBtn.className = 'flex-shrink-0 ml-2 mt-0.5 opacity-60 hover:opacity-100 focus:outline-none';
|
||||||
|
closeBtn.setAttribute('aria-label', 'Close');
|
||||||
|
closeBtn.innerHTML = '<i class="fas fa-times text-sm"></i>';
|
||||||
|
|
||||||
|
wrapper.appendChild(textSpan);
|
||||||
|
wrapper.appendChild(closeBtn);
|
||||||
|
toast.appendChild(wrapper);
|
||||||
|
|
||||||
|
// Close button handler
|
||||||
|
closeBtn.addEventListener('click', function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
clearTimeout(autoRemoveTimer);
|
||||||
|
toast.classList.remove('show');
|
||||||
|
setTimeout(function() { toast.remove(); }, 300);
|
||||||
|
});
|
||||||
|
|
||||||
container.appendChild(toast);
|
container.appendChild(toast);
|
||||||
requestAnimationFrame(function() {
|
requestAnimationFrame(function() {
|
||||||
toast.classList.add('show');
|
toast.classList.add('show');
|
||||||
});
|
});
|
||||||
setTimeout(function() {
|
var autoRemoveTimer = setTimeout(function() {
|
||||||
toast.classList.remove('show');
|
toast.classList.remove('show');
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
toast.remove();
|
toast.remove();
|
||||||
|
|||||||
@@ -155,7 +155,11 @@ function saveJailConfig() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
closeModal('jailConfigModal');
|
closeModal('jailConfigModal');
|
||||||
showToast(t('filter_debug.save_success', 'Filter and jail config saved and reloaded'), 'success');
|
if (data.warning) {
|
||||||
|
showToast(t('filter_debug.save_reload_warning', 'Config saved, but fail2ban reload failed') + ': ' + data.warning, 'warning', 12000);
|
||||||
|
} else {
|
||||||
|
showToast(t('filter_debug.save_success', 'Filter and jail config saved and reloaded'), 'success');
|
||||||
|
}
|
||||||
return refreshData({ silent: true });
|
return refreshData({ silent: true });
|
||||||
})
|
})
|
||||||
.catch(function(err) {
|
.catch(function(err) {
|
||||||
@@ -468,17 +472,17 @@ function saveManageJailsSingle(checkbox) {
|
|||||||
console.error('Could not find jail name span');
|
console.error('Could not find jail name span');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const jailName = nameSpan.textContent.trim();
|
const jailName = nameSpan.textContent.trim();
|
||||||
if (!jailName) {
|
if (!jailName) {
|
||||||
console.error('Jail name is empty');
|
console.error('Jail name is empty');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isEnabled = checkbox.checked;
|
const isEnabled = checkbox.checked;
|
||||||
const updatedJails = {};
|
const updatedJails = {};
|
||||||
updatedJails[jailName] = isEnabled;
|
updatedJails[jailName] = isEnabled;
|
||||||
|
|
||||||
console.log('Saving jail state:', jailName, 'enabled:', isEnabled, 'payload:', updatedJails);
|
console.log('Saving jail state:', jailName, 'enabled:', isEnabled, 'payload:', updatedJails);
|
||||||
|
|
||||||
// Send updated state to the API endpoint /api/jails/manage.
|
// Send updated state to the API endpoint /api/jails/manage.
|
||||||
@@ -500,22 +504,20 @@ function saveManageJailsSingle(checkbox) {
|
|||||||
if (data.error) {
|
if (data.error) {
|
||||||
var errorMsg = data.error;
|
var errorMsg = data.error;
|
||||||
var toastType = 'error';
|
var toastType = 'error';
|
||||||
|
|
||||||
// If jails were auto-disabled, check if this jail was one of them
|
// If jails were auto-disabled, check if this jail was one of them
|
||||||
var wasAutoDisabled = data.autoDisabled && data.enabledJails && Array.isArray(data.enabledJails) && data.enabledJails.indexOf(jailName) !== -1;
|
var wasAutoDisabled = data.autoDisabled && data.enabledJails && Array.isArray(data.enabledJails) && data.enabledJails.indexOf(jailName) !== -1;
|
||||||
|
|
||||||
if (wasAutoDisabled) {
|
if (wasAutoDisabled) {
|
||||||
checkbox.checked = false;
|
checkbox.checked = false;
|
||||||
toastType = 'warning';
|
toastType = 'warning';
|
||||||
// Use the message if available, otherwise use the error
|
|
||||||
errorMsg = data.message || errorMsg;
|
|
||||||
} else {
|
} else {
|
||||||
// Revert checkbox state on error
|
// Revert checkbox state on error
|
||||||
checkbox.checked = !isEnabled;
|
checkbox.checked = !isEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
showToast(errorMsg, toastType);
|
showToast(errorMsg, toastType, wasAutoDisabled ? 15000 : undefined);
|
||||||
|
|
||||||
// Still reload the jail list to reflect the actual state
|
// Still reload the jail list to reflect the actual state
|
||||||
return fetch(withServerParam('/api/jails/manage'), {
|
return fetch(withServerParam('/api/jails/manage'), {
|
||||||
headers: serverHeaders()
|
headers: serverHeaders()
|
||||||
|
|||||||
Reference in New Issue
Block a user