Erste Abarbeitung des Repository-Audits (siehe TODO.md). Sicherheit: - Rate-Limiting für alle vier Auth-Endpunkte. Sie waren unbegrenzt aufrufbar, also beliebig viele Mails über den eigenen SMTP-Zugang und beliebig viele Rateversuche auf Verifizierungscodes. - Passwort-Reset-Token nur noch als SHA-256-Hash in der Datenbank. Bisher Klartext: Lesezugriff auf die DB genuegte zur Kontouebernahme. - Tote Mock-Login-Route entfernt. Sie verglich gegen ein hartcodiertes Fake-Passwort und war ueber die Middleware-Ausnahme fuer /api/auth/* ohne Anmeldung erreichbar. - Passwort-Reset auf bcrypt-Kosten 12, wie beim Signup. Reparaturen: - npm test rief jest auf, obwohl es weder Jest-Config noch Jest-Tests gibt. Zeigt jetzt auf Playwright; jest/ts-jest/@types/jest entfernt. - Falscher sonar.projectKey im Workflow. Verifiziert per tsc gegen die geaenderten Bereiche: keine neuen Typfehler. v1.117.0 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
9.4 KiB
To-do — Repository-Audit vom 2026-09-06
Abarbeitungsliste aus dem Repository-Audit. Reihenfolge ist bewusst gewählt: schnelle Sicherheitsgewinne zuerst, das große Refactoring zuletzt.
Abhaken mit [x]. Die Nummern in Klammern entsprechen den Punkten aus dem Audit.
Block A — Schnell erledigt, sofortiger Gewinn
A1. Tote Mock-Login-Route entfernen (Audit 3)
src/app/api/auth/login/route.tslöschen- Prüfen, dass niemand sie aufruft (
grep -rn "api/auth/login" src/) - Commit + Version bumpen
Warum: Altcode aus der Anfangszeit. Vergleicht gegen ein hartcodiertes Fake-Passwort
($2b$10$examplehashedpassword), erzeugt ein bedeutungsloses mock-jwt-token-… und setzt es
als Cookie. Weil die Middleware /api/auth/* bewusst durchlässt, ist die Route ohne Login
von außen erreichbar und schreibt jede probierte E-Mail per console.log ins Log.
Kein Login-Bypass (der Vergleich schlägt immer fehl), aber unnötige Angriffsfläche.
A2. npm test reparieren (Audit 6)
- Entscheiden: Jest raus oder Jest einrichten
package.json:"test"auf das zeigen lassen, was wirklich existiert (Playwright)"test:e2e"für Playwright ergänzen- Debug-Skripte in
tests/aussortieren (siehe unten)
Warum: "test": "jest" — aber es gibt keine Jest-Config und keinen einzigen Jest-Test.
Die 15 Dateien in tests/ sind Playwright-Specs, und die Namen verraten den Charakter:
login-debug.spec.ts, css-debug-test.spec.ts, login-simple-debug.spec.ts. Wegwerf-Skripte,
keine Regressionstests. npm test läuft ins Leere.
Aufräumen: Die reinen Debug-Skripte löschen, die brauchbaren behalten und benennen.
A3. dev-Branch auflösen (Audit 5)
- Die vier Maßnahmen aus
f6c4a21frisch aufmainanwenden (siehe A1, B1, B2) devaufmainzurücksetzen oder löschenCLAUDE.md: Branch-Strategie an die gelebte Praxis anpassen
Warum: Commit f6c4a21 vom 04.07.2026 behebt bereits Rate-Limiting, Token-Hashing,
die Mock-Route und die Secret-Datei — wurde aber nie gemerged. dev fehlen inzwischen
70 Commits von main, ein Merge würde alte Dateistände zurückholen. Deshalb:
Commit als Vorlage nehmen, Änderungen neu anwenden, dev danach entsorgen.
CLAUDE.md beschreibt einen dev → main-Workflow, der faktisch nicht gelebt wird
(alles läuft direkt auf main). Doku an die Realität anpassen ist ehrlicher.
Block B — Sicherheit
B1. Rate-Limiting auf den Auth-Endpunkten (Audit 4)
- Sliding-Window-Limiter in
src/lib/rate-limit.tsanlegen - Einbinden in
signup - Einbinden in
resend-verification - Einbinden in
reset-password - Einbinden in
verify-email - Limits dokumentieren (Vorschlag: 5 Versuche / 15 Minuten je IP)
Warum: Im gesamten src/ ist kein Limiter vorhanden. Signup, Passwort-Reset und
Verification-Mails sind unbegrenzt aufrufbar — Einladung zum Missbrauch deines SMTP-Zugangs.
B2. Passwort-Reset-Token nur als SHA-256-Hash speichern (Audit 4)
- Beim Erzeugen: Klartext per Mail, Hash in die DB
- Beim Einlösen: eingehenden Token hashen, dann vergleichen
- Migration für bestehende Tokens (einfachster Weg: alle invalidieren)
Warum: src/app/api/auth/reset-password/route.ts:28 legt passwordResetToken im
Klartext ab. Wer Lesezugriff auf die Datenbank hat, kann fremde Konten übernehmen.
Der Token selbst kommt aus crypto.randomUUID() — das ist in Ordnung, nur die Ablage nicht.
B3. Secrets aus dem Git entfernen und rotieren (Audit 2)
.env.production.saveaus dem Arbeitsbaum löschen.gitignoreauf.env*erweitern (mit Ausnahme für.env.example)NEXTAUTH_SECRETneu erzeugenSMTP_PASSWORDneu setzen- Datenbank-Passwort rotieren
- Entscheiden: Historie umschreiben oder belassen
- Nach dem Wechsel: einmal neu einloggen
Warum: .env.production.save ist eingecheckt und enthält echte Werte —
DATABASE_URL (70 Zeichen), NEXTAUTH_SECRET (20 Zeichen), SMTP_PASSWORD (20 Zeichen).
.gitignore listet .env.production, die .save-Endung fällt durchs Raster.
Drin seit Commit da8d019.
Entwarnung: Das GitHub-Repo ist privat — nicht öffentlich abgreifbar. Die Werte stehen aber in der kompletten Historie, in jedem Klon und auf Gitea.
Anleitung siehe docs/secret-rotation.md.
Block C — Build und Typsicherheit
C1. Build darf Fehler nicht mehr verschlucken (Audit 1)
- Schritt 1:
eslint.ignoreDuringBuildsinnext.config.jsauffalse - Gemeldete ESLint-Fehler abarbeiten
- Schritt 2:
npm run type-checklaufen lassen, Fehlerzahl notieren - Fehler abarbeiten — modulweise, nicht auf einmal
- Schritt 3:
typescript.ignoreBuildErrorsauffalse any-Stellen reduzieren (aktuell 452) — fortlaufend, kein Blocker
Warum: next.config.js hat ignoreDuringBuilds: true und ignoreBuildErrors: true.
tsconfig.json sagt zwar strict: true, das ist aber wirkungslos, weil der Build die Fehler
gar nicht meldet. Ein Typfehler fällt nicht beim Bauen auf, sondern erst als kaputte Seite
im Browser. Ein erfolgreicher Build ist derzeit kein Beweis, dass der Code korrekt ist.
Achtung Reihenfolge: Erst ESLint, dann TypeScript. Beides gleichzeitig abzuschalten blockiert jeden Deploy, bis alles behoben ist.
Block D — Struktur
D1. Dateien über 4000 Zeilen aufteilen (Audit 7)
Betroffen sind genau zwei Dateien:
| Datei | Zeilen |
|---|---|
src/components/WeeklyView.tsx |
11.906 |
src/components/SettingsSidebar.tsx |
5.445 |
Voraussetzung: C1 muss laufen — ohne Typecheck ist ein Refactoring dieser Größe Blindflug. Ebenso hilfreich: A2, damit es überhaupt Tests gibt.
WeeklyView.tsx → Zielstruktur
src/components/weekly/anlegen- Reine Helfer nach
src/lib/weekly/(Datum, Slots, Formatierung) - Drag & Drop in einen Hook
useTaskDragDrop.ts - Someday-Listen in
SomedayLists.tsx - All-Day-Leiste in
AllDayBar.tsx - Zeitraster + Tagesspalten in
TimeGrid.tsx/DayColumn.tsx - Einstellungs-Flyouts in
QuickSettingsPanel.tsx - Daten-Laden in
useWeeklyData.ts WeeklyView.tsxbleibt als Orchestrator übrig
SettingsSidebar.tsx → Zielstruktur
src/components/settings/anlegen- Ein Panel pro Themenbereich als eigene Datei
- Gemeinsame Bausteine (Farbwähler, Schalterzeile) in
settings/controls/
Vorgehen: In kleinen Schritten, jeder Schritt ein eigener Commit, nach jedem Schritt Typecheck. Kein "großer Wurf" — die Datei ist zu zentral.
Warum: WeeklyView.tsx ist ein Viertel des gesamten Quellcodes. Der Weekday-Bug von
Anfang September saß genau dort und war nur deshalb schwer zu finden.
Block E — Dauerhafte Absicherung
E1. Regelmäßige automatische Prüfung (Audit 8)
- SonarQube-Analyse gegen https://sq.martin-bierschenk.de einrichten
- Regelmäßigen Lauf aufsetzen — nightly 03:00,
todo-sonar.timer(systemd user unit) npm auditin denselben Lauf aufnehmen (scripts/quality-check.sh)todo-sonar.timeraufscripts/quality-check.shumstellen statt nurtodo-sonar-scan- Playwright-Tests in den nächtlichen Lauf aufnehmen (braucht laufende App — erst nach A2)
- Quality Gate im SonarQube definieren
- Ergebnis irgendwohin melden, wo es auffällt (bisher nur Konsolenausgabe)
- Entscheiden:
.github/workflows/sonarqube.ymllöschen oder behalten
Stand: Die Analyse läuft bereits — nächtlich um 03:00 auf dem Spark, per systemd-Timer,
Ergebnis auf https://sq.martin-bierschenk.de. Was fehlte, war npm audit (Sicherheitslücken
in Abhängigkeiten findet SonarQube nicht) und ein Bündel-Skript. Beides ist jetzt da.
Zur Entscheidung: GitHub Actions wurde am 02.09. bewusst verworfen — das Repo ist privat,
Actions-Minuten kosten, und der SonarQube-Server läuft ohnehin selbst gehostet. Trotzdem liegt
seit dem 03.09. ein Workflow im Repo, der bei jedem Push auf main anspringt. Er ruft
npm run type-check und npm run lint auf — beides schlägt derzeit fehl (siehe C1), der
Workflow wäre also dauerhaft rot. Sein Projekt-Key war zudem falsch und hätte in ein zweites,
leeres SonarQube-Projekt geschrieben; das ist korrigiert. Entweder löschen (passt zur
Entscheidung vom 02.09.) oder bewusst behalten und C1 vorziehen.
Warum: Bisher fallen Regressionen erst in Produktion auf. In Kombination mit C1 (Build meldet Fehler) und A2 (Tests laufen) entsteht daraus ein echtes Netz.
E2. Abhängigkeiten auf Sicherheitslücken prüfen
npm auditauf dem Container ausführen- Kritische Funde beheben
Warum: Konnte im Audit nicht geprüft werden — node_modules ist auf dem
CIFS-Share nicht installierbar (keine Symlinks). Zu bekannten Lücken in den
Abhängigkeiten liegt daher keine Aussage vor. Muss nachgeholt werden.
Kleinkram (ohne Eile)
- 114
console.logaus dem Produktionscode entfernen (die 275console.errorsind in Ordnung) NEXTAUTH_SECRETauf 32 Byte verlängern (erledigt sich mit B3)- API-Routen: JSON-401 statt HTML-Redirect für nicht angemeldete Aufrufe
deploy.shunddocker-compose.ymllöschen oder als veraltet markieren — sie beschreiben ein Portainer-Setup, das nicht mehr verwendet wird- Eigener Auth-Check in
apple/syncundweather/geocode(aktuell nur durch die Middleware geschützt — zusätzliche Absicherung schadet nicht)