This repository has been archived on 2026-03-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
oubliette/internal/storage/store.go
Torjus Håkestad 94f1f1c266 feat: add GeoIP country lookup with embedded DB-IP Lite database (PLAN.md 4.3)
Embeds a DB-IP Lite country MMDB (~5MB) in the binary via go:embed,
keeping the single-binary deployment story clean. Country codes are
stored alongside login attempts and sessions, shown in the dashboard
(Top IPs, Top Countries card, Recent/Active Sessions, session detail).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 15:27:46 +01:00

125 lines
4.1 KiB
Go

package storage
import (
"context"
"time"
)
// LoginAttempt represents a deduplicated login attempt.
type LoginAttempt struct {
ID int64
Username string
Password string
IP string
Country string
Count int
FirstSeen time.Time
LastSeen time.Time
}
// Session represents an authenticated SSH session.
type Session struct {
ID string
IP string
Country string
Username string
ShellName string
ConnectedAt time.Time
DisconnectedAt *time.Time
HumanScore *float64
}
// SessionLog represents a single log entry for a session.
type SessionLog struct {
ID int64
SessionID string
Timestamp time.Time
Input string
Output string
}
// SessionEvent represents a single I/O event recorded during a session.
type SessionEvent struct {
SessionID string
Timestamp time.Time
Direction int // 0=input (client→server), 1=output (server→client)
Data []byte
}
// 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
Country string // populated by GetTopIPs
Count int64
}
// Store is the interface for persistent storage of honeypot data.
type Store interface {
// RecordLoginAttempt upserts a login attempt, incrementing the count
// for existing (username, password, ip) combinations.
RecordLoginAttempt(ctx context.Context, username, password, ip, country string) error
// CreateSession creates a new session record and returns its UUID.
CreateSession(ctx context.Context, ip, username, shellName, country string) (string, error)
// EndSession sets the disconnected_at timestamp for a session.
EndSession(ctx context.Context, sessionID string, disconnectedAt time.Time) error
// UpdateHumanScore sets the human detection score for a session.
UpdateHumanScore(ctx context.Context, sessionID string, score float64) error
// AppendSessionLog adds a log entry to a session.
AppendSessionLog(ctx context.Context, sessionID, input, output string) error
// DeleteRecordsBefore removes all records older than the given cutoff
// 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)
// GetTopCountries returns the top N countries by total attempt count.
GetTopCountries(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)
// GetSession returns a single session by ID.
GetSession(ctx context.Context, sessionID string) (*Session, error)
// GetSessionLogs returns all log entries for a session ordered by timestamp.
GetSessionLogs(ctx context.Context, sessionID string) ([]SessionLog, error)
// AppendSessionEvents batch-inserts session events.
AppendSessionEvents(ctx context.Context, events []SessionEvent) error
// GetSessionEvents returns all events for a session ordered by id.
GetSessionEvents(ctx context.Context, sessionID string) ([]SessionEvent, error)
// CloseActiveSessions sets disconnected_at for all sessions that are
// still marked as active. This should be called at startup to clean up
// sessions left over from a previous unclean shutdown.
CloseActiveSessions(ctx context.Context, disconnectedAt time.Time) (int64, error)
// Close releases any resources held by the store.
Close() error
}