mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-04-11 13:47:05 +02:00
Fix Last seen date/time pharsing of Recurring IPs overview
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -698,14 +699,46 @@ LIMIT ?`
|
|||||||
var results []RecurringIPStat
|
var results []RecurringIPStat
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var stat RecurringIPStat
|
var stat RecurringIPStat
|
||||||
var lastSeen sql.NullString
|
// First, scan as string to see what format SQLite returns
|
||||||
if err := rows.Scan(&stat.IP, &stat.Country, &stat.Count, &lastSeen); err != nil {
|
// Then parse it properly
|
||||||
return nil, err
|
var lastSeenStr sql.NullString
|
||||||
|
if err := rows.Scan(&stat.IP, &stat.Country, &stat.Count, &lastSeenStr); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to scan row: %w", err)
|
||||||
}
|
}
|
||||||
if lastSeen.Valid {
|
|
||||||
if parsed, err := time.Parse(time.RFC3339Nano, lastSeen.String); err == nil {
|
if lastSeenStr.Valid && lastSeenStr.String != "" {
|
||||||
stat.LastSeen = parsed
|
// Try to parse the datetime string
|
||||||
|
// SQLite stores DATETIME as TEXT, format depends on how it was inserted
|
||||||
|
// The modernc.org/sqlite driver returns MAX(occurred_at) in format:
|
||||||
|
// "2006-01-02 15:04:05.999999999 -0700 MST" (e.g., "2025-11-22 12:17:24.697430041 +0000 UTC")
|
||||||
|
formats := []string{
|
||||||
|
"2006-01-02 15:04:05.999999999 -0700 MST", // Format returned by MAX() in SQLite
|
||||||
|
time.RFC3339Nano,
|
||||||
|
time.RFC3339,
|
||||||
|
"2006-01-02 15:04:05.999999999+00:00",
|
||||||
|
"2006-01-02 15:04:05+00:00",
|
||||||
|
"2006-01-02 15:04:05.999999999",
|
||||||
|
"2006-01-02 15:04:05",
|
||||||
|
"2006-01-02T15:04:05.999999999Z",
|
||||||
|
"2006-01-02T15:04:05Z",
|
||||||
|
"2006-01-02T15:04:05.999999999",
|
||||||
|
"2006-01-02T15:04:05",
|
||||||
}
|
}
|
||||||
|
parsed := time.Time{} // zero time
|
||||||
|
for _, format := range formats {
|
||||||
|
if t, parseErr := time.Parse(format, lastSeenStr.String); parseErr == nil {
|
||||||
|
parsed = t.UTC()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If still zero, log the actual string for debugging
|
||||||
|
if parsed.IsZero() {
|
||||||
|
log.Printf("ERROR: Could not parse lastSeen datetime '%s' (length: %d) for IP %s. All format attempts failed.", lastSeenStr.String, len(lastSeenStr.String), stat.IP)
|
||||||
|
}
|
||||||
|
stat.LastSeen = parsed
|
||||||
|
} else {
|
||||||
|
// Log when lastSeen is NULL or empty
|
||||||
|
log.Printf("WARNING: lastSeen is NULL or empty for IP %s", stat.IP)
|
||||||
}
|
}
|
||||||
results = append(results, stat)
|
results = append(results, stat)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -298,13 +298,25 @@ func BanInsightsHandler(c *gin.Context) {
|
|||||||
|
|
||||||
countriesMap, err := storage.CountBanEventsByCountry(ctx, since, serverID)
|
countriesMap, err := storage.CountBanEventsByCountry(ctx, since, serverID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
settings := config.GetSettings()
|
||||||
|
errorMsg := err.Error()
|
||||||
|
if settings.Debug {
|
||||||
|
config.DebugLog("BanInsightsHandler: CountBanEventsByCountry error: %v", err)
|
||||||
|
errorMsg = fmt.Sprintf("CountBanEventsByCountry failed: %v", err)
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": errorMsg})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
recurring, err := storage.ListRecurringIPStats(ctx, since, minCount, limit, serverID)
|
recurring, err := storage.ListRecurringIPStats(ctx, since, minCount, limit, serverID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
settings := config.GetSettings()
|
||||||
|
errorMsg := err.Error()
|
||||||
|
if settings.Debug {
|
||||||
|
config.DebugLog("BanInsightsHandler: ListRecurringIPStats error: %v", err)
|
||||||
|
errorMsg = fmt.Sprintf("ListRecurringIPStats failed: %v", err)
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": errorMsg})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user