57 lines
1.4 KiB
Go
57 lines
1.4 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
var ErrNoSession = errors.New("auth: no such session")
|
|
|
|
type SessionStore interface {
|
|
CreateSession(ctx context.Context, userID uuid.UUID, tokenHash string, expiresAt time.Time) error
|
|
GetSessionUser(ctx context.Context, tokenHash string) (uuid.UUID, error)
|
|
DeleteSession(ctx context.Context, tokenHash string) error
|
|
}
|
|
|
|
type Sessions struct {
|
|
store SessionStore
|
|
ttl time.Duration
|
|
}
|
|
|
|
func NewSessions(store SessionStore, ttl time.Duration) *Sessions {
|
|
return &Sessions{store: store, ttl: ttl}
|
|
}
|
|
|
|
func TokenHash(token string) string {
|
|
sum := sha256.Sum256([]byte(token))
|
|
return hex.EncodeToString(sum[:])
|
|
}
|
|
|
|
func (s *Sessions) Create(ctx context.Context, userID uuid.UUID) (string, time.Time, error) {
|
|
raw := make([]byte, 32)
|
|
if _, err := rand.Read(raw); err != nil {
|
|
return "", time.Time{}, err
|
|
}
|
|
token := base64.RawURLEncoding.EncodeToString(raw)
|
|
exp := time.Now().Add(s.ttl)
|
|
if err := s.store.CreateSession(ctx, userID, TokenHash(token), exp); err != nil {
|
|
return "", time.Time{}, err
|
|
}
|
|
return token, exp, nil
|
|
}
|
|
|
|
func (s *Sessions) Validate(ctx context.Context, token string) (uuid.UUID, error) {
|
|
return s.store.GetSessionUser(ctx, TokenHash(token))
|
|
}
|
|
|
|
func (s *Sessions) Destroy(ctx context.Context, token string) error {
|
|
return s.store.DeleteSession(ctx, TokenHash(token))
|
|
}
|