- H4: sliding-window rate limiter (10 attempts / 5min per IP+username) on login and register; successful login resets the counter; pure stdlib, no new dependency - H8: docker-compose.test.yml DB/ADMIN passwords now :?required (align with main); docker-compose.main.yml AUTH_REGISTRATION_ENABLED defaults to false - M8: fix FAV_PUBLISHER_ENABLE -> FAV_PUBLISHER_ENABLED typo so the gate test actually guards the real flag Co-authored-by: Cursor <cursoragent@cursor.com>
47 lines
990 B
Go
47 lines
990 B
Go
package server
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestLoginRateLimiter_BlocksAfterMaxAttempts(t *testing.T) {
|
|
l := newLoginRateLimiter(3, time.Minute)
|
|
key := "1.2.3.4|alice"
|
|
for i := 0; i < 3; i++ {
|
|
if !l.allow(key) {
|
|
t.Fatalf("attempt %d should be allowed", i+1)
|
|
}
|
|
}
|
|
if l.allow(key) {
|
|
t.Fatalf("4th attempt within window should be blocked")
|
|
}
|
|
}
|
|
|
|
func TestLoginRateLimiter_ResetClearsWindow(t *testing.T) {
|
|
l := newLoginRateLimiter(2, time.Minute)
|
|
key := "1.2.3.4|bob"
|
|
l.allow(key)
|
|
l.allow(key)
|
|
if l.allow(key) {
|
|
t.Fatalf("should be blocked before reset")
|
|
}
|
|
l.reset(key)
|
|
if !l.allow(key) {
|
|
t.Fatalf("should be allowed after reset")
|
|
}
|
|
}
|
|
|
|
func TestLoginRateLimiter_WindowExpiry(t *testing.T) {
|
|
l := newLoginRateLimiter(1, 10*time.Millisecond)
|
|
key := "1.2.3.4|carol"
|
|
l.allow(key)
|
|
if l.allow(key) {
|
|
t.Fatalf("should be blocked within window")
|
|
}
|
|
time.Sleep(20 * time.Millisecond)
|
|
if !l.allow(key) {
|
|
t.Fatalf("should be allowed after window expiry")
|
|
}
|
|
}
|