Files
gochat/backend/internal/auth/security_hardening_test.go
Rogeeandrogee f719529d66 fix(security): harden auth and secret handling (HH-444) (#101)
* fix(security): harden auth and credential handling (HH-444)

* fix(security): address HH-444 review blockers

* fix(security): close remaining HH-444 review blockers

---------

Co-authored-by: Rogee <rogee@ipao.vip>
2026-08-22 15:45:06 +08:00

60 lines
1.9 KiB
Go

package auth
import (
"context"
"errors"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/redis/go-redis/v9"
"github.com/stretchr/testify/require"
"github.com/gochat/gochat/internal/config"
"github.com/gochat/gochat/internal/model"
)
func TestJWTAccessTokenUsesConfiguredMinuteExpiry(t *testing.T) {
cfg := &config.JWTConfig{Secret: "test-secret", AccessExpiryMinutes: 15, RefreshExpiryHours: 168}
service := NewJWTService(cfg)
pair, err := service.GenerateTokenPair(&model.User{Base: model.Base{ID: 7}, Provider: "email"}, 3, "agent")
require.NoError(t, err)
require.WithinDuration(t, time.Now().Add(15*time.Minute), pair.ExpiresAt, 2*time.Second)
}
func TestRefreshRotationRejectsReusedToken(t *testing.T) {
cfg := &config.JWTConfig{Secret: "test-secret", AccessExpiryMinutes: 15, RefreshExpiryHours: 168}
store := NewRefreshTokenStore(nil, cfg)
ctx := context.Background()
require.NoError(t, store.StoreForClient(ctx, 7, "browser", "old-token"))
require.NoError(t, store.RotateForClient(ctx, 7, "browser", "new-token"))
valid, err := store.ValidateForClient(ctx, 7, "browser", "old-token")
require.NoError(t, err)
require.False(t, valid)
}
func TestWSTicketIsOneTimeAndExpires(t *testing.T) {
mr := miniredis.RunT(t)
rdb := redis.NewClient(&redis.Options{Addr: mr.Addr()})
t.Cleanup(func() { _ = rdb.Close() })
store := NewWSTicketStore(rdb, 5*time.Second)
ctx := context.Background()
want := WSTicketClaims{UserID: 7, AccountID: 3, Role: "agent", Provider: "email"}
ticket, err := store.Issue(ctx, want)
require.NoError(t, err)
got, err := store.Consume(ctx, ticket)
require.NoError(t, err)
require.Equal(t, want, *got)
_, err = store.Consume(ctx, ticket)
require.ErrorIs(t, err, ErrInvalidWSTicket)
expiring, err := store.Issue(ctx, want)
require.NoError(t, err)
mr.FastForward(6 * time.Second)
_, err = store.Consume(ctx, expiring)
require.True(t, errors.Is(err, ErrInvalidWSTicket))
}