Go-Backend (chi, pgx, golang-migrate) + React/TS-Frontend als PWA. Enthalten: Auth inkl. OIDC, Dateien mit Versionen und Papierkorb, Freigaben (Links + intern), WebDAV, Gruppenordner, Admin/Theming, Volltextsuche mit OCR, eigener PDF-Betrachter und WOPI-Office (Collabora/OnlyOffice). Nicht im Repo: deploy/.env (Sitzungsschlüssel, DB- und Admin-Passwort) sowie alle Daten- und Build-Verzeichnisse – siehe .gitignore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
64 lines
1.6 KiB
Go
64 lines
1.6 KiB
Go
package middleware
|
||
|
||
import (
|
||
"testing"
|
||
"time"
|
||
)
|
||
|
||
func TestFailureLimiterLocksOutAfterLimit(t *testing.T) {
|
||
l := NewFailureLimiter(3, time.Minute, time.Minute)
|
||
|
||
for i := 0; i < 2; i++ {
|
||
l.Fail("10.0.0.1")
|
||
if allowed, _ := l.Allowed("10.0.0.1"); !allowed {
|
||
t.Fatalf("locked out after %d of 3 failures", i+1)
|
||
}
|
||
}
|
||
|
||
l.Fail("10.0.0.1")
|
||
allowed, retryAfter := l.Allowed("10.0.0.1")
|
||
if allowed {
|
||
t.Fatal("still allowed after reaching the failure limit")
|
||
}
|
||
if retryAfter <= 0 {
|
||
t.Fatalf("retryAfter = %v, want positive so Retry-After is usable", retryAfter)
|
||
}
|
||
}
|
||
|
||
// Ein Sync-Client darf nicht unter fremden Fehlversuchen leiden: Erfolg räumt
|
||
// den Zähler weg.
|
||
func TestFailureLimiterResetOnSuccess(t *testing.T) {
|
||
l := NewFailureLimiter(2, time.Minute, time.Minute)
|
||
|
||
l.Fail("10.0.0.2")
|
||
l.Reset("10.0.0.2")
|
||
l.Fail("10.0.0.2")
|
||
|
||
if allowed, _ := l.Allowed("10.0.0.2"); !allowed {
|
||
t.Fatal("locked out although a success cleared the earlier failure")
|
||
}
|
||
}
|
||
|
||
func TestFailureLimiterIsolatesKeys(t *testing.T) {
|
||
l := NewFailureLimiter(1, time.Minute, time.Minute)
|
||
l.Fail("10.0.0.3")
|
||
|
||
if allowed, _ := l.Allowed("10.0.0.4"); !allowed {
|
||
t.Fatal("a different address was locked out")
|
||
}
|
||
}
|
||
|
||
// Nach Ablauf des Fensters zählt der Versuch nicht mehr mit – sonst summierten
|
||
// sich Vertipper über Wochen zu einer Sperre.
|
||
func TestFailureLimiterWindowExpires(t *testing.T) {
|
||
l := NewFailureLimiter(2, 10*time.Millisecond, time.Minute)
|
||
|
||
l.Fail("10.0.0.5")
|
||
time.Sleep(20 * time.Millisecond)
|
||
l.Fail("10.0.0.5")
|
||
|
||
if allowed, _ := l.Allowed("10.0.0.5"); !allowed {
|
||
t.Fatal("locked out although the first failure was outside the window")
|
||
}
|
||
}
|