diff options
Diffstat (limited to 'player-server/internal')
| -rw-r--r-- | player-server/internal/auth/interfaces.go | 4 | ||||
| -rw-r--r-- | player-server/internal/auth/token.go | 9 | ||||
| -rw-r--r-- | player-server/internal/auth/token_test.go | 5 | ||||
| -rw-r--r-- | player-server/internal/service/auth.go | 7 | ||||
| -rw-r--r-- | player-server/internal/service/auth_test.go | 4 |
5 files changed, 21 insertions, 8 deletions
diff --git a/player-server/internal/auth/interfaces.go b/player-server/internal/auth/interfaces.go index 790c534..e167a60 100644 --- a/player-server/internal/auth/interfaces.go +++ b/player-server/internal/auth/interfaces.go @@ -15,7 +15,9 @@ type SessionManager interface { } // TokenManager is the abstraction for API token generation and hashing. +// Generate returns an error when the system random source fails so callers +// can surface the failure (e.g. via HTTP 500) instead of panicking. type TokenManager interface { - Generate() (plaintext, hash string) + Generate() (plaintext, hash string, err error) Hash(plaintext string) string } diff --git a/player-server/internal/auth/token.go b/player-server/internal/auth/token.go index bdb7e6b..bcb696f 100644 --- a/player-server/internal/auth/token.go +++ b/player-server/internal/auth/token.go @@ -20,14 +20,17 @@ func NewTokenManager() TokenManager { } // Generate creates a plaintext API token and its stored hash. -func (m *tokenManager) Generate() (plaintext, hash string) { +// Returns an error if the system random source fails. A crypto/rand.Read +// failure indicates a process-level emergency, so callers should propagate +// the error upward rather than masking it. +func (m *tokenManager) Generate() (plaintext, hash string, err error) { b := make([]byte, tokenByteLength) if _, err := rand.Read(b); err != nil { - panic(fmt.Sprintf("generate token: %v", err)) + return "", "", fmt.Errorf("generate token: %w", err) } plaintext = hex.EncodeToString(b) - return plaintext, m.Hash(plaintext) + return plaintext, m.Hash(plaintext), nil } // Hash returns the SHA-256 hash of a plaintext API token. diff --git a/player-server/internal/auth/token_test.go b/player-server/internal/auth/token_test.go index bf18aa5..a9bddf8 100644 --- a/player-server/internal/auth/token_test.go +++ b/player-server/internal/auth/token_test.go @@ -11,7 +11,10 @@ func TestTokenManager_Generate(t *testing.T) { seen := make(map[string]string) for i := 0; i < 1000; i++ { - plaintext, hash := tm.Generate() + plaintext, hash, err := tm.Generate() + if err != nil { + t.Fatalf("generate token: %v", err) + } if len(plaintext) != tokenByteLength*2 { t.Fatalf("expected plaintext length %d, got %d", tokenByteLength*2, len(plaintext)) } diff --git a/player-server/internal/service/auth.go b/player-server/internal/service/auth.go index 6bd2055..1fe468b 100644 --- a/player-server/internal/service/auth.go +++ b/player-server/internal/service/auth.go @@ -92,8 +92,13 @@ func (s *authService) Login(ctx context.Context, username, password string) (*Au } // CreateAPIToken creates a hashed API token and returns the one-time plaintext value. +// A token generation failure (e.g. crypto/rand.Read returning an error) is +// surfaced to the caller; the HTTP layer translates it into a 500 response. func (s *authService) CreateAPIToken(ctx context.Context, userID int64, name string, expiresAt *time.Time) (*CreateAPITokenResult, error) { - plaintext, hash := s.tm.Generate() + plaintext, hash, err := s.tm.Generate() + if err != nil { + return nil, fmt.Errorf("generate api token: %w", err) + } now := s.clock.Now() token := &model.APIToken{ UserID: userID, diff --git a/player-server/internal/service/auth_test.go b/player-server/internal/service/auth_test.go index 213f6e5..b01a2b3 100644 --- a/player-server/internal/service/auth_test.go +++ b/player-server/internal/service/auth_test.go @@ -16,8 +16,8 @@ type fixedTokenManager struct { hash string } -func (m fixedTokenManager) Generate() (string, string) { - return m.plaintext, m.hash +func (m fixedTokenManager) Generate() (string, string, error) { + return m.plaintext, m.hash, nil } func (m fixedTokenManager) Hash(plaintext string) string { |
