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 }