64 lines
1.3 KiB
Go
64 lines
1.3 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/prism/proxy/internal/store"
|
|
)
|
|
|
|
func TestLoginLimiterLockAndClear(t *testing.T) {
|
|
st, err := store.Open(filepath.Join(t.TempDir(), "data"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer st.Close()
|
|
|
|
ctx := context.Background()
|
|
limiter := NewLoginLimiter(st)
|
|
cfg := LoginConfig{MaxAttempts: 3, Window: time.Minute, LockDuration: 2 * time.Minute}
|
|
ip := "203.0.113.1"
|
|
|
|
for i := 0; i < 2; i++ {
|
|
res, err := limiter.RecordFailure(ctx, ip, cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if res.Locked {
|
|
t.Fatalf("unexpected lock at attempt %d", i+1)
|
|
}
|
|
if res.Remaining != cfg.MaxAttempts-i-1 {
|
|
t.Fatalf("remaining=%d want %d", res.Remaining, cfg.MaxAttempts-i-1)
|
|
}
|
|
}
|
|
|
|
res, err := limiter.RecordFailure(ctx, ip, cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !res.Locked || res.RetryAfter <= 0 {
|
|
t.Fatalf("expected lock, got %+v", res)
|
|
}
|
|
|
|
check, err := limiter.Check(ctx, ip, cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if check.Allowed {
|
|
t.Fatal("expected blocked while locked")
|
|
}
|
|
|
|
if err := limiter.RecordSuccess(ctx, ip); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
check, err = limiter.Check(ctx, ip, cfg)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !check.Allowed || check.Remaining != cfg.MaxAttempts {
|
|
t.Fatalf("expected reset, got %+v", check)
|
|
}
|
|
}
|