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:
HoneyandClaude Opus 5 committed 2026-08-24 09:25:36 +02:00
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")
}
}