package auth import ( "context" "time" "tyto/internal/database" ) // SessionManager handles session lifecycle. type SessionManager struct { db database.Database duration time.Duration } // NewSessionManager creates a new session manager. func NewSessionManager(db database.Database, duration time.Duration) *SessionManager { if duration == 0 { duration = 24 * time.Hour } return &SessionManager{ db: db, duration: duration, } } // Create creates a new session for a user. func (m *SessionManager) Create(ctx context.Context, userID, ipAddress, userAgent string) (*database.Session, error) { now := time.Now().UTC() session := &database.Session{ Token: generateToken(), UserID: userID, CreatedAt: now, ExpiresAt: now.Add(m.duration), IPAddress: ipAddress, UserAgent: userAgent, } if err := m.db.CreateSession(ctx, session); err != nil { return nil, err } return session, nil } // Get retrieves a session by token, returning an error if expired or not found. func (m *SessionManager) Get(ctx context.Context, token string) (*database.Session, error) { session, err := m.db.GetSession(ctx, token) if err != nil { return nil, err } if session == nil { return nil, ErrSessionNotFound } if time.Now().UTC().After(session.ExpiresAt) { // Clean up expired session m.db.DeleteSession(ctx, token) return nil, ErrSessionExpired } return session, nil } // Delete removes a session. func (m *SessionManager) Delete(ctx context.Context, token string) error { return m.db.DeleteSession(ctx, token) } // Extend extends a session's expiration time. func (m *SessionManager) Extend(ctx context.Context, token string) error { session, err := m.Get(ctx, token) if err != nil { return err } // Update expiration session.ExpiresAt = time.Now().UTC().Add(m.duration) // Re-create session with new expiration // (This is simpler than adding an Update method to Database interface) if err := m.db.DeleteSession(ctx, token); err != nil { return err } return m.db.CreateSession(ctx, session) } // Duration returns the session duration. func (m *SessionManager) Duration() time.Duration { return m.duration }