mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-04-11 13:47:05 +02:00
UpdateDefaultSettings now checks CheckJailLocalIntegrity as first and returns error if not managed by Fail2ban-UI
This commit is contained in:
@@ -410,6 +410,21 @@ func (ac *AgentConnector) TestLogpathWithResolution(ctx context.Context, logpath
|
||||
|
||||
// UpdateDefaultSettings implements Connector.
|
||||
func (ac *AgentConnector) UpdateDefaultSettings(ctx context.Context, settings config.AppSettings) error {
|
||||
// Check jail.local integrity first
|
||||
exists, hasUI, chkErr := ac.CheckJailLocalIntegrity(ctx)
|
||||
if chkErr != nil {
|
||||
config.DebugLog("Warning: could not check jail.local integrity on agent %s: %v", ac.server.Name, chkErr)
|
||||
}
|
||||
if exists && !hasUI {
|
||||
return fmt.Errorf("jail.local on agent server %s is not managed by Fail2ban-UI - skipping settings update (please migrate your jail.local manually)", ac.server.Name)
|
||||
}
|
||||
if !exists {
|
||||
config.DebugLog("jail.local does not exist on agent server %s - initializing fresh managed file", ac.server.Name)
|
||||
if err := ac.EnsureJailLocalStructure(ctx); err != nil {
|
||||
return fmt.Errorf("failed to initialize jail.local on agent server %s: %w", ac.server.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert IgnoreIPs array to space-separated string
|
||||
ignoreIPStr := strings.Join(settings.IgnoreIPs, " ")
|
||||
if ignoreIPStr == "" {
|
||||
|
||||
@@ -1555,10 +1555,28 @@ PYEOF
|
||||
func (sc *SSHConnector) UpdateDefaultSettings(ctx context.Context, settings config.AppSettings) error {
|
||||
jailLocalPath := "/etc/fail2ban/jail.local"
|
||||
|
||||
// Read existing file if it exists
|
||||
// Check jail.local integrity first
|
||||
exists, hasUI, chkErr := sc.CheckJailLocalIntegrity(ctx)
|
||||
if chkErr != nil {
|
||||
config.DebugLog("Warning: could not check jail.local integrity on %s: %v", sc.server.Name, chkErr)
|
||||
}
|
||||
|
||||
if exists && !hasUI {
|
||||
// File belongs to the user – never overwrite
|
||||
return fmt.Errorf("jail.local on server %s is not managed by Fail2ban-UI - skipping settings update (please migrate your jail.local manually)", sc.server.Name)
|
||||
}
|
||||
|
||||
if !exists {
|
||||
// File was deleted (e.g. user finished migration) – create a fresh managed file
|
||||
config.DebugLog("jail.local does not exist on server %s - initializing fresh managed file", sc.server.Name)
|
||||
if err := sc.EnsureJailLocalStructure(ctx); err != nil {
|
||||
return fmt.Errorf("failed to initialize jail.local on server %s: %w", sc.server.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Read existing file
|
||||
existingContent, err := sc.runRemoteCommand(ctx, []string{"cat", jailLocalPath})
|
||||
if err != nil {
|
||||
// File doesn't exist, create new one
|
||||
existingContent = ""
|
||||
}
|
||||
|
||||
|
||||
@@ -1071,14 +1071,35 @@ func UpdateDefaultSettingsLocal(settings config.AppSettings) error {
|
||||
config.DebugLog("UpdateDefaultSettingsLocal called")
|
||||
localPath := "/etc/fail2ban/jail.local"
|
||||
|
||||
// Read existing file if it exists
|
||||
// Check jail.local integrity first
|
||||
var existingContent string
|
||||
fileExists := false
|
||||
if content, err := os.ReadFile(localPath); err == nil {
|
||||
existingContent = string(content)
|
||||
fileExists = len(strings.TrimSpace(existingContent)) > 0
|
||||
} else if !os.IsNotExist(err) {
|
||||
return fmt.Errorf("failed to read jail.local: %w", err)
|
||||
}
|
||||
|
||||
hasUIAction := strings.Contains(existingContent, "ui-custom-action")
|
||||
|
||||
if fileExists && !hasUIAction {
|
||||
// File belongs to the user – never overwrite
|
||||
return fmt.Errorf("jail.local is not managed by Fail2ban-UI - skipping settings update (please migrate your jail.local manually)")
|
||||
}
|
||||
|
||||
if !fileExists {
|
||||
// File was deleted (e.g. user finished migration); create a fresh managed file
|
||||
config.DebugLog("jail.local does not exist - initializing fresh managed file")
|
||||
if err := config.EnsureJailLocalStructure(); err != nil {
|
||||
return fmt.Errorf("failed to initialize jail.local: %w", err)
|
||||
}
|
||||
// Re-read the freshly created file
|
||||
if content, err := os.ReadFile(localPath); err == nil {
|
||||
existingContent = string(content)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove commented lines (lines starting with #) but preserve:
|
||||
// - Banner lines (containing "Fail2Ban-UI" or "fail2ban-ui")
|
||||
// - action_mwlg and action override lines
|
||||
|
||||
@@ -154,8 +154,17 @@ func SummaryHandler(c *gin.Context) {
|
||||
|
||||
// Check jail.local integrity on every summary request so the dashboard
|
||||
// can display a persistent warning banner when the file is not managed by us.
|
||||
if exists, hasUI, chkErr := conn.CheckJailLocalIntegrity(c.Request.Context()); chkErr == nil && exists && !hasUI {
|
||||
resp.JailLocalWarning = true
|
||||
if exists, hasUI, chkErr := conn.CheckJailLocalIntegrity(c.Request.Context()); chkErr == nil {
|
||||
if exists && !hasUI {
|
||||
resp.JailLocalWarning = true
|
||||
} else if !exists {
|
||||
// File was removed (user finished migration) – initialize a fresh managed file
|
||||
if err := conn.EnsureJailLocalStructure(c.Request.Context()); err != nil {
|
||||
config.DebugLog("Warning: failed to initialize jail.local on summary request: %v", err)
|
||||
} else {
|
||||
config.DebugLog("Initialized fresh jail.local for server %s (file was missing)", conn.Server().Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, resp)
|
||||
@@ -780,11 +789,18 @@ func TestServerHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check jail.local integrity: if it exists but is not managed by fail2ban-ui, warn the user
|
||||
// Check jail.local integrity: if it exists but is not managed by fail2ban-ui, warn the user.
|
||||
// If the file was removed (user finished migration), initialize a fresh managed file.
|
||||
resp := gin.H{"messageKey": "servers.actions.test_success"}
|
||||
if exists, hasUI, err := conn.CheckJailLocalIntegrity(ctx); err == nil {
|
||||
if exists && !hasUI {
|
||||
resp["jailLocalWarning"] = true
|
||||
} else if !exists {
|
||||
if err := conn.EnsureJailLocalStructure(ctx); err != nil {
|
||||
config.DebugLog("Warning: failed to initialize jail.local on test request: %v", err)
|
||||
} else {
|
||||
config.DebugLog("Initialized fresh jail.local for server %s (file was missing)", conn.Server().Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, resp)
|
||||
@@ -2172,7 +2188,7 @@ func UpdateSettingsHandler(c *gin.Context) {
|
||||
config.DebugLog("Updating DEFAULT settings on server: %s (type: %s)", server.Name, server.Type)
|
||||
if err := conn.UpdateDefaultSettings(c.Request.Context(), newSettings); err != nil {
|
||||
errorMsg := fmt.Sprintf("Failed to update DEFAULT settings on %s: %v", server.Name, err)
|
||||
config.DebugLog("Error: %s", errorMsg)
|
||||
log.Printf("⚠️ %s", errorMsg)
|
||||
errors = append(errors, errorMsg)
|
||||
} else {
|
||||
config.DebugLog("Successfully updated DEFAULT settings on %s", server.Name)
|
||||
|
||||
Reference in New Issue
Block a user