From ad55164b75e2997cf9464c722df4ee63f89e55c4 Mon Sep 17 00:00:00 2001 From: tavo Date: Wed, 2 Jul 2025 18:56:04 -0600 Subject: [PATCH] delegate rotation --- sessions/sessions.go | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/sessions/sessions.go b/sessions/sessions.go index 0debfab..caa7e9b 100644 --- a/sessions/sessions.go +++ b/sessions/sessions.go @@ -86,7 +86,7 @@ func (s *SessionStore[T]) New(sessionMaxAge time.Duration, data T) (string, stri return st, ct, nil } -// Validates the session and CSRF tokens, and returns new rotated tokens and session data. +// Validates the session and CSRF tokens, then rotates the tokens if valid. func (s *SessionStore[T]) Validate(st, ct string) (string, string, T, error) { var zero T @@ -111,11 +111,35 @@ func (s *SessionStore[T]) Validate(st, ct string) (string, string, T, error) { return "", "", zero, fmt.Errorf("invalid CSRF token") } - // Rotate session tokens + return s.RotateTokens(st) +} + +// RotateTokens rotates the session and CSRF tokens for a given session token. +func (s *SessionStore[T]) RotateTokens(st string) (string, string, T, error) { + var zero T + + hst := hash(st) + + s.mu.RLock() + sess, ok := s.sessions[hst] + s.mu.RUnlock() + + if !ok { + return "", "", zero, fmt.Errorf("invalid session token") + } + + if time.Now().After(sess.expires) { + s.mu.Lock() + delete(s.sessions, hst) + s.mu.Unlock() + return "", "", zero, fmt.Errorf("session expired") + } + newSt, err := generateToken(s.tokenLength) if err != nil { return "", "", zero, fmt.Errorf("error generating new session token: %w", err) } + newCt, err := generateToken(s.tokenLength) if err != nil { return "", "", zero, fmt.Errorf("error generating new CSRF token: %w", err)