diff --git a/cmd/server/main.go b/cmd/server/main.go index a1bce65..7d470e4 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -16,7 +16,7 @@ func main() { // Register our routes (IndexHandler, /api/summary, /api/jails/:jail/unban/:ip) web.RegisterRoutes(r) - log.Println("Starting Fail2ban UI on :8080. Run with 'sudo' if fail2ban-client requires it.") + log.Println("Starting Fail2ban-UI server on :8080.") if err := r.Run(":8080"); err != nil { log.Fatalf("Server crashed: %v", err) } diff --git a/internal/fail2ban/client.go b/internal/fail2ban/client.go index ef6cd18..81fea76 100644 --- a/internal/fail2ban/client.go +++ b/internal/fail2ban/client.go @@ -2,18 +2,18 @@ package fail2ban import ( "fmt" - "io/ioutil" - "os/exec" - "path/filepath" + "os" + "os/exec" + "path/filepath" "strings" "time" ) type JailInfo struct { - JailName string `json:"jailName"` - TotalBanned int `json:"totalBanned"` - NewInLastHour int `json:"newInLastHour"` - BannedIPs []string `json:"bannedIPs"` + JailName string `json:"jailName"` + TotalBanned int `json:"totalBanned"` + NewInLastHour int `json:"newInLastHour"` + BannedIPs []string `json:"bannedIPs"` } // GetJails returns all configured jails using "fail2ban-client status". @@ -128,29 +128,29 @@ func BuildJailInfos(logPath string) ([]JailInfo, error) { // Example: we assume each jail config is at /etc/fail2ban/filter.d/.conf // Adapt this to your environment. func GetJailConfig(jail string) (string, error) { - configPath := filepath.Join("/etc/fail2ban/filter.d", jail+".conf") - content, err := ioutil.ReadFile(configPath) - if err != nil { - return "", fmt.Errorf("failed to read config for jail %s: %v", jail, err) - } - return string(content), nil + configPath := filepath.Join("/etc/fail2ban/filter.d", jail+".conf") + content, err := os.ReadFile(configPath) + if err != nil { + return "", fmt.Errorf("failed to read config for jail %s: %v", jail, err) + } + return string(content), nil } // SetJailConfig overwrites the config file for a given jail with new content. func SetJailConfig(jail, newContent string) error { - configPath := filepath.Join("/etc/fail2ban/filter.d", jail+".conf") - if err := ioutil.WriteFile(configPath, []byte(newContent), 0644); err != nil { - return fmt.Errorf("failed to write config for jail %s: %v", jail, err) - } - return nil + configPath := filepath.Join("/etc/fail2ban/filter.d", jail+".conf") + if err := os.WriteFile(configPath, []byte(newContent), 0644); err != nil { + return fmt.Errorf("failed to write config for jail %s: %v", jail, err) + } + return nil } // ReloadFail2ban runs "fail2ban-client reload" func ReloadFail2ban() error { - cmd := exec.Command("fail2ban-client", "reload") - out, err := cmd.CombinedOutput() - if err != nil { - return fmt.Errorf("fail2ban reload error: %v\nOutput: %s", err, out) - } - return nil -} \ No newline at end of file + cmd := exec.Command("fail2ban-client", "reload") + out, err := cmd.CombinedOutput() + if err != nil { + return fmt.Errorf("fail2ban reload error: %v\nOutput: %s", err, out) + } + return nil +} diff --git a/internal/fail2ban/logparse.go b/internal/fail2ban/logparse.go index caeed1d..66bc211 100644 --- a/internal/fail2ban/logparse.go +++ b/internal/fail2ban/logparse.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "regexp" - //"strings" "time" ) @@ -69,31 +68,3 @@ func ParseBanLog(logPath string) (map[string][]BanEvent, error) { } return eventsByJail, nil } - -// GetLastFiveBans crawls the parse results to find the last 5 ban events overall. -func GetLastFiveBans(eventsByJail map[string][]BanEvent) []BanEvent { - var allEvents []BanEvent - for _, events := range eventsByJail { - allEvents = append(allEvents, events...) - } - - // Sort by time descending - // (We want the latest 5 ban events) - sortByTimeDesc(allEvents) - - if len(allEvents) > 5 { - return allEvents[:5] - } - return allEvents -} - -// A simple in-file sorting utility -func sortByTimeDesc(events []BanEvent) { - for i := 0; i < len(events); i++ { - for j := i + 1; j < len(events); j++ { - if events[j].Time.After(events[i].Time) { - events[i], events[j] = events[j], events[i] - } - } - } -} diff --git a/pkg/web/templates/index.html b/pkg/web/templates/index.html index 3753765..08df4e5 100644 --- a/pkg/web/templates/index.html +++ b/pkg/web/templates/index.html @@ -256,9 +256,18 @@ window.addEventListener('DOMContentLoaded', function() { checkReloadNeeded(); fetchSummary().then(function() { showLoading(false); + initializeTooltips(); // Initialize tooltips after fetching and rendering }); }); +// Function to initialize Bootstrap tooltips +function initializeTooltips() { + const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); + tooltipTriggerList.forEach(function (tooltipTriggerEl) { + new bootstrap.Tooltip(tooltipTriggerEl); + }); +} + // Toggle the loading overlay (with !important) function showLoading(show) { var overlay = document.getElementById('loading-overlay'); @@ -342,7 +351,7 @@ function renderDashboard(data) { html += '

No jails found.

'; } else { html += '' - + '

Overview

' + + '

Overview

' + '' + ' ' + ' '