feat(aether): initial commit – self-hosted Cloud, Phasen 1–7
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>
This commit is contained in:
commit
31a027c93a
225 files changed
+38042
No files matched your search
@@ -0,0 +1,63 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user