feat: add minimal web dashboard with stats, top credentials, and sessions
Implements Phase 1.5 — an embedded web UI using Go templates, Pico CSS (dark theme), and htmx for auto-refreshing stats and active sessions. Adds read query methods to the Store interface (GetDashboardStats, GetTopUsernames, GetTopPasswords, GetTopIPs, GetRecentSessions) with implementations for both SQLite and MemoryStore. Introduces the internal/web package with server, handlers, templates, and tests. Web server is opt-in via [web] config section and runs alongside SSH with graceful shutdown. Bumps version to 0.2.0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,20 @@ type SessionLog struct {
|
||||
Output string
|
||||
}
|
||||
|
||||
// DashboardStats holds aggregate counts for the web dashboard.
|
||||
type DashboardStats struct {
|
||||
TotalAttempts int64
|
||||
UniqueIPs int64
|
||||
TotalSessions int64
|
||||
ActiveSessions int64
|
||||
}
|
||||
|
||||
// TopEntry represents a value and its count for top-N queries.
|
||||
type TopEntry struct {
|
||||
Value string
|
||||
Count int64
|
||||
}
|
||||
|
||||
// Store is the interface for persistent storage of honeypot data.
|
||||
type Store interface {
|
||||
// RecordLoginAttempt upserts a login attempt, incrementing the count
|
||||
@@ -58,6 +72,22 @@ type Store interface {
|
||||
// and returns the total number of deleted rows.
|
||||
DeleteRecordsBefore(ctx context.Context, cutoff time.Time) (int64, error)
|
||||
|
||||
// GetDashboardStats returns aggregate counts for the dashboard.
|
||||
GetDashboardStats(ctx context.Context) (*DashboardStats, error)
|
||||
|
||||
// GetTopUsernames returns the top N usernames by total attempt count.
|
||||
GetTopUsernames(ctx context.Context, limit int) ([]TopEntry, error)
|
||||
|
||||
// GetTopPasswords returns the top N passwords by total attempt count.
|
||||
GetTopPasswords(ctx context.Context, limit int) ([]TopEntry, error)
|
||||
|
||||
// GetTopIPs returns the top N IPs by total attempt count.
|
||||
GetTopIPs(ctx context.Context, limit int) ([]TopEntry, error)
|
||||
|
||||
// GetRecentSessions returns the most recent sessions ordered by connected_at DESC.
|
||||
// If activeOnly is true, only sessions with no disconnected_at are returned.
|
||||
GetRecentSessions(ctx context.Context, limit int, activeOnly bool) ([]Session, error)
|
||||
|
||||
// Close releases any resources held by the store.
|
||||
Close() error
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user