Add bootstrap tooltips and refactor some code formatings

This commit is contained in:
Michael Reber
2025-01-27 13:21:45 +01:00
parent 65612dad8a
commit 879207a5f4
4 changed files with 36 additions and 56 deletions

View File

@@ -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)
}

View File

@@ -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/<jail>.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
}
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
}

View File

@@ -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]
}
}
}
}

View File

@@ -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 += '<p>No jails found.</p>';
} else {
html += ''
+ '<h2>Overview</h2>'
+ '<h2><span data-bs-toggle="tooltip" data-bs-placement="top" title="The Overview displays the currently enabled jails that you have added to your jail.local configuration.">Overview</span></h2>'
+ '<table class="table table-striped" id="jailsTable">'
+ ' <thead>'
+ ' <tr>'