clusev/CHANGELOG.md

344 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Changelog
Alle nennenswerten Änderungen an Clusev. Format nach
[Keep a Changelog](https://keepachangelog.com), Versionierung nach
[SemVer](https://semver.org).
**Release-Prozess:** Feature-Commits sammeln sich auf dem Branch. Ist ein Stand
reif, wird er nach `main` gemerged, als `vX.Y.Z` getaggt und hier unter einer
eigenen Versionsüberschrift dokumentiert. Nutzer beziehen ausschließlich
getaggte Releases (Kanal `stable`, optional `beta`) — niemals Entwicklungs-Builds.
## [Unreleased]
_Keine offenen Änderungen — der nächste Stand wird hier gesammelt und als `vX.Y.Z` getaggt._
## [0.6.1] - 2026-06-14
### Behoben
- **Sidebar-Server-Switcher driftete von der Detailseite ab.** Es gab zwei „aktueller
Server"-Begriffe: den Switcher (Session) und die `/servers/{uuid}`-Detailseite. Jetzt setzt der
Aufruf einer Detailseite den Server aktiv (Sidebar spiegelt immer die Seite), und ein Wechsel im
Switcher auf einer Detailseite navigiert zum gewählten Server statt die alte Seite neu zu laden.
Geschrieben wird nur bei bewusster Navigation (race-frei). *Bekannte Rest-Kante:* nach
Back/Forward (wire:navigate-Cache, kein erneutes `mount()`) zeigt die gecachte Seite den richtigen
Server, aber die Session kann kurz auf den vorigen zeigen — löst sich bei der nächsten bewussten
Navigation; inhärent am Single-Session-Modell (auch Multi-Tab).
## [0.6.0] - 2026-06-14
### Hinzugefügt
- **WebAuthn / Security-Keys (YubiKey) als optionaler 2. Login-Faktor.** Per
`web-auth/webauthn-lib`. TOTP + Backup-Codes bleiben der erforderliche 2FA und die einzige
Wiederherstellung; ein Security-Key ist eine zusätzliche Login-Option.
- **Gated auf Domain + HTTPS:** Die rpId ist die aktive Domain — auf Bare-IP/HTTP ist die
Funktion ausgeblendet (mit Hinweis), da eine IP keine gültige rpId ist.
- **Einstellungen → Sicherheit:** Security-Keys hinzufügen (benannt), auflisten, entfernen
(mit Bestätigung). Beim Login-2FA-Schritt „Mit Security-Key anmelden" neben TOTP/Backup-Code.
- 2FA deaktivieren (UI **und** `clusev:reset-admin --disable-2fa`) entfernt jetzt auch
Security-Keys + Backup-Codes, damit ein Reset den zweiten Faktor vollständig zurücksetzt.
### Sicherheit
- rpId strikt = aktive Domain (nie eine IP). Challenges serverseitig + einmalig.
- Signatur-Zähler-Prüfung mit Rollback-/Klon-Erkennung; Zähler 0 nur toleriert, wenn der
gespeicherte Zähler ebenfalls 0 ist (Plattform-Authenticator/Passkeys).
- Registrierung erfordert eine aktive 2FA-Anmeldung; Label wird vor der Browser-Ceremony
validiert (keine verwaisten Credentials). Alle Aktionen im Audit-Log.
> Hinweis: Der echte End-to-End-Test (YubiKey registrieren + anmelden) ist nur unter einer Domain
> mit HTTPS möglich; die Ceremony-Logik ist auf Options-/Speicher-/Gating-Ebene getestet.
## [0.5.0] - 2026-06-14
### Hinzugefügt
- **Kontowiederherstellung.**
- **2FA-Backup-Codes:** 8 Einmal-Codes werden bei der 2FA-Einrichtung erzeugt, einmalig
angezeigt und als `.txt` herunterladbar; in den Einstellungen (Sicherheit) neu erzeugbar.
Beim Login-2FA-Schritt als Alternative zum Authenticator-Code verwendbar.
- **„Passwort vergessen":** Reset über einen 2FA-Code oder Backup-Code (ohne E-Mail nötig).
Zusätzlich ein E-Mail-Reset-Link, sobald ein echter Mailer konfiguriert ist
(`mail.default` ≠ `log`/`array`).
- **CLI-Notfall:** `php artisan clusev:reset-admin` setzt das Admin-Passwort (und optional 2FA
+ Backup-Codes) per Server-Shell zurück — der Last-Resort bei kompletter Aussperrung.
### Sicherheit
- Passwort-Resets (Formular, E-Mail-Link, CLI) rotieren das `remember_token` — eine gestohlene
„Angemeldet bleiben"-Cookie überlebt einen Reset nicht.
- Backup-Codes werden atomar (Row-Lock) verbraucht (kein Replay).
- Der Notify-Toaster liegt jetzt auch auf den Auth-Seiten; alle Reset-/Backup-Aktionen werden im
Audit-Log erfasst.
## [0.4.6] - 2026-06-14
### Behoben
- **Validierungsmeldungen waren nur Englisch.** Es gab keine `lang/{de,en}/validation.php`, also
fiel Laravel bei jedem Eingabefeld-Fehler auf seine eingebauten englischen Meldungen zurück —
unabhängig von der gewählten Sprache. Vollständige `validation.php` in Deutsch (Quelle) und
Englisch ergänzt, plus lokalisierte Attribut-Namen (z. B. „SSH-Port", „E-Mail-Adresse"). Leeres
Login-Formular zeigt jetzt z. B. „E-Mail-Adresse muss ausgefüllt werden.".
## [0.4.5] - 2026-06-14
### Hinzugefügt
- **Favicons + PWA-Manifest.** Vollständiger Icon-Satz aus dem App-Brand-Mark (oranges
Server-Glyph auf Dunkel): `favicon.svg` (skalierbar), `favicon.ico` (16/32/48),
`apple-touch-icon.png`, `icon-192/512.png` und `site.webmanifest`. In beiden Layouts via
gemeinsames `partials/head-icons` eingebunden (incl. `theme-color`); nginx liefert das
Manifest als `application/manifest+json`.
- **Eigene Fehlerseiten.** Gebrandete, zweisprachige Seiten für 403/404/419/429/500/503 auf
einem eigenständigen Fehler-Layout (Design-Tokens, Brand-Mark) — ersetzen Laravels
Standard-Fehlerseiten. Es werden nie rohe Status-Texte oder Stacktraces gezeigt; in Prod ist
`APP_DEBUG` fest auf `false` gepinnt.
### Behoben
- **Roher Fehlertext beim Datei-Download.** Der Download-Fehler zeigte die unverpackte
Exception-Meldung; jetzt eine lokalisierte Meldung (`files.download_failed`), konsistent mit
Upload/Löschen.
- **Fehlerseiten-Sprache.** Früh geworfene Fehler (CSRF 419, gematchte Aborts) berücksichtigen
jetzt die Nutzersprache (locale-Auflösung im Exception-Hook, absturzsicher gekapselt).
## [0.4.4] - 2026-06-14
### Behoben
- **Zoom beim Fokus auf Eingabefelder (Handy/Tablet).** iOS Safari zoomt die Seite hinein, wenn
ein fokussiertes Eingabefeld eine Schriftgröße < 16px hat durch das dichte Design (`text-xs`/
`text-sm` auf Inputs) trat das bei jedem Feld auf. Eine zentrale Regel (`@media (pointer:
coarse)`) erzwingt jetzt 16px für `input`/`textarea`/`select` auf Touch-Geräten (Handy + Tablet
jeder Größe, inkl. iPad Pro 1024/1366px), während das Desktop-Layout (Maus) unverändert klein
bleibt. Per Touch-Emulation über alle Eingabefelder verifiziert.
## [0.4.3] - 2026-06-14
### Behoben
- **Mobile Overflow durch lange URLs und IPv6-Bans.** Responsive-Audit (R7) über alle Views bei
375/768px: mit den aktuellen Daten lief nichts über, aber lange Werte konnten Zeilen über den
Viewport schieben. Behoben: die Panel-Domain (`break-all` am Link, `min-w-0` an der
Zugriffsadresse) im System-Bereich und gebannte IPv6-Adressen in der fail2ban-Liste
(`min-w-0 break-all`). Per injizierter 253-Zeichen-Domain und langer IPv6 bei 375px verifiziert.
## [0.4.2] - 2026-06-14
### Hinzugefügt
- **Server-Status Initialisierung".** Neu angelegte Server starten in einem cyanfarbenen
`pending`-Zustand (nicht mehr sofort rot/Offline), bis der erste Kontakt sie auf online/offline
setzt.
- **SSH-Verbindungstest beim Anlegen.** Beim Server-Anlegen wird die SSH-Anmeldung in der
Anlage-Transaktion geprüft (Login + Befehls-Marker beweisen, dass Befehle ausführbar sind);
schlägt sie fehl, wird nichts gespeichert und der SSH-Grund im Formular angezeigt.
- **Hinweis nur per SSH-Key".** Die SSH-Passwort-Login-Zeile der Härtungs-Checkliste weist
darauf hin, dass der Zugang nach dem Deaktivieren nur noch per SSH-Key möglich ist.
### Geändert
- **Einheitliche Buttons.** Alle Buttons haben durchgehend Rahmen + Hintergrund; Löschen-Aktionen
nutzen die neue `danger-soft`-Variante (dezent rot getönt, dauerhaft nicht erst beim Hover).
Die rahmenlosen `ghost`/`ghost-danger`-Varianten sind entfallen.
- **Firewall- und fail2ban-Boxen** erscheinen nur noch, wenn das jeweilige Tool installiert ist
(oder die Statusabfrage fehlschlug), und liegen im responsiven 2-Spalten-Grid (eine Box volle
Breite). Die redundante nicht installiert"-Box entfällt installiert wird über die
Härtungs-Checkliste.
- **Automatische Updates** gelten als Betreiber-Präferenz, nicht als Sicherheitsanforderung: der
Zustand wird neutral als aktiv/inaktiv angezeigt und aus" nie mehr als unsicher (OFFEN) markiert.
### Behoben
- **fail2ban/UFW fälschlich nicht installiert".** Die Härtungs-Checkliste erkennt ein Tool jetzt
auch dann als installiert, wenn nur die Binary auf dem PATH liegt oder der Dienst läuft (vorher
nur `dpkg -l … ^ii`) konsistent mit den Status-Panels. Behebt den Widerspruch Checkliste:
nicht installiert" vs. Panel: aktiv, N gesperrt".
## [0.4.1] - 2026-06-14
### Behoben
- **Verstümmelter Header auf jeder eingeloggten Seite.** Ein Kommentar im `@php`-Block der
topbar enthielt die literalen Tokens `@php`/`@endphp`; Blades Raw-Block-Matcher nahm das
`@endphp` im Kommentar als Block-Ende und gab den Rest (inkl. `$title ??= …`) als Klartext im
`<header>` aus der Seitentitel blieb zudem leer. Kommentar bereinigt; neue Regel **R17**
(keine Direktiv-Tokens in Blade-Kommentaren; gerenderte Ausgabe prüfen, nicht nur HTTP 200).
### Sicherheit
- **Realtime-Kanäle sind jetzt privat.** Der Live-Metrik-Broadcast (`MetricsTicked`) läuft über
einen `PrivateChannel`, autorisiert über `/broadcasting/auth` (im `web`-Group PanelScheme +
Session). Damit kann niemand mehr allein mit dem ffentlich gebündelten) App-Key Infrastruktur-
Metriken abonnieren auch nicht über einen alten Caddy-Host nach einem Domain-Wechsel. Neue
Konvention (CLAUDE.md §3 / `routes/channels.php`): **jeder** Broadcast-Kanal ist privat.
## [0.4.0] - 2026-06-14
Die Panel-Domain ist wieder aus dem Dashboard änderbar diesmal sicher: gespeichert wird in der Datenbank, angewendet beim Neustart, das Zertifikat holt Caddy automatisch.
### Hinzugefügt
- **Domain aus dem Dashboard ändern.** Auf der System-Seite lässt sich die Panel-Domain
eintragen oder leeren. Gespeichert wird als Einstellung (`panel_domain`, übersteuert die
Installations-Domain `APP_DOMAIN`); nach einem Stack-Neustart leiten sich URL, der
WebSocket-Endpunkt (Reverb), das TLS-Zertifikat und die Cookie-Sicherheit automatisch davon
ab. Kein Terminal-Editieren mehr nur speichern und neu starten".
- **Automatisches TLS per On-Demand (Caddy).** Caddy stellt das Zertifikat beim ersten
HTTPS-Zugriff aus und fragt vorher die App (`/_caddy/ask`), ob für genau diese Domain
ausgestellt werden darf so kann keine fremde, auf die IP gezeigte Domain Zertifikate
erzwingen. Voraussetzung bleibt: die Domain zeigt per DNS auf den Server.
### Geändert
- Der Reverb-Client (Browser) bezieht seinen Endpunkt jetzt zur Laufzeit aus der aktuellen
Anfrage und läuft über dieselbe Adresse wie das Panel (Proxy/Reverse-Tunnel `/app/*`,
`/apps/*` Caddy in Produktion, nginx in Dev). So folgt Realtime jeder Domain-Änderung
ohne Neu-Bauen der Assets und ohne separat geöffneten Port.
- Server-seitiges Event-Publishing läuft intern direkt zum `reverb`-Dienst, ist damit
unabhängig von der öffentlichen Domain/dem Zertifikat.
### Sicherheit
- **Kein Aussperren.** Sicherer-Cookie-Schalter und HTTPS-Redirect richten sich nach der
tatsächlichen Anfrage (hinter Caddy via `X-Forwarded-*`, das nur in Produktion vertraut
wird). Der Zugriff per **IP über HTTP bleibt immer als Rückfallweg erreichbar**, falls
eine neue Domain (DNS/Zertifikat) noch nicht bereit ist.
- **Nur die aktive Domain liefert das Panel aus.** Bei gesetzter Domain wird das Panel per
Hostname ausschließlich über genau diese Domain (HTTPS) bedient; eine alte/fremde, auf den
Server gezeigte Domain wird abgewiesen (404) auch wenn Caddy ihr Zertifikat noch hält.
## [0.3.0] - 2026-06-13
Zweisprachige Oberfläche: die gesamte UI gibt es jetzt auf Deutsch und Englisch, frei umschaltbar pro Konto.
### Hinzugefügt
- **Sprache wählbar (Deutsch / Englisch).** Ein DE/EN-Umschalter (oben rechts, sowie auf der
Login-Seite) stellt die Sprache um; die Wahl wird pro Konto gespeichert und gilt sofort für
die gesamte Oberfläche. Ohne Wahl greift die Standardsprache (Deutsch).
- Übersetzungen liegen strukturiert unter `lang/{de,en}/<gruppe>.php` eine Gruppe je Feature
plus geteiltes `common`, Schlüssel in beiden Sprachen identisch.
### Geändert
- **Alle sichtbaren Texte sind lokalisiert.** Views, Komponenten und Backend-Services geben
Text ausschließlich über `__('gruppe.schlüssel')` aus, nie mehr fest verdrahtet neue,
verbindliche Regel **R16**. Native Technik-Begriffe (`nginx.service`, `SSH`, `2FA`, Ports)
bleiben unverändert.
### Entfernt
- Erläuternde Warum …?"-Texte auf der System-Seite die Seite zeigt nur noch Funktion und
Status.
## [0.2.1] - 2026-06-13
Verfeinerungen an 0.2.0: vollautomatisches TLS ohne sichtbare Konfiguration und einheitliche Buttons.
### Geändert
- **TLS ist vollautomatisch.** Caddy stellt das Zertifikat aus, erneuert es und leitet
HTTPHTTPS um ohne manuelle Schritte. Die System-Seite zeigt nur noch den **Status**
(Domain, Zugriffsadresse) statt der erzeugten Caddy-Konfiguration und des
`caddy reload`-Befehls. Die Panel-Domain ist eine **Installations-Entscheidung**
(`APP_DOMAIN`) und bleibt damit konsistent mit URL, WebSocket (wss) und Cookie-Sicherheit;
zum Ändern `install.sh` mit der neuen Domain erneut ausführen.
- Härtungs-Checkliste: alle Aktions-Buttons im selben Stil (einheitlich `secondary`,
mit Rahmen) statt zustandsabhängig mal mit, mal ohne Rahmen.
### Entfernt
- Laufzeit-Override der App-URL aus der Datenbank und das dashboard-seitige Bearbeiten
von Domain/E-Mail (konnte URL/WebSocket/Cookies nicht konsistent zur Laufzeit umstellen).
Eine Migration entfernt die leeren Alt-Einträge; ein real konfigurierter Wert bleibt als
Verlauf erhalten. **Upgrade-Hinweis:** eine zuvor im Dashboard gesetzte Domain bitte einmalig
über `install.sh` setzen.
## [0.2.0] - 2026-06-13
Mehr-Betriebssystem-Verwaltung, echte Firewall- und fail2ban-Steuerung aus dem Dashboard sowie eine Tastatur-/Befehls-Bedienung.
### Hinzugefügt
- **OS-Abstraktion**: Updates, Härtung und Firewall laufen jetzt über **apt, dnf und
zypper** (Debian/Ubuntu, RHEL/Fedora/Rocky/Alma, openSUSE). Das Betriebssystem wird
erkannt und auf der Server-Detailseite angezeigt (Paketverwaltung/Firewall). Arch
und Alpine werden erkannt; nicht unterstützte Funktionen werden mit deutschem
Hinweis sauber deaktiviert statt fehlzuschlagen.
- **Firewall-Regeln (UFW)**: Regeln ansehen, hinzufügen und löschen samt
Standard-Anzeige mit Aussperr-Schutz (SSH-Regeln/-Port, deny ohne Port). firewalld
wird nur angezeigt (Laufzeit aller aktiven Zonen inkl. Rich Rules); Regelverwaltung
bleibt vorerst UFW.
- **fail2ban-Status**: Jails mit Zählern, **gebannte IPs sehen und entsperren**,
IP manuell sperren (R5-Dialog, Aussperr-Schutz für Loopback + eigenen Zugang) und
**Whitelist (ignoreip)** verwalten.
- **Befehls-Palette (Strg/⌘-K)** + Tastenkürzel: Schnell-Navigation (Leader g“),
Seitensuche („/“), Hilfe („?“).
### Geändert
- System-Updates verwenden je Distribution den passenden Paketmanager
(Audit-Aktion `system.package_upgrade`).
- fail2ban-Tuning und -Whitelist liegen in getrennten Drop-ins, damit Änderungen sich
nicht gegenseitig überschreiben; das frühere Einzel-Drop-in wird migriert.
- Server-Detailseite zeigt erkanntes System, Paketverwaltung und Firewall-Werkzeug.
- System-Seite erklärt jetzt, warum TLS über Caddy terminiert wird.
### Sicherheit
- Firewall: race-freies Löschen per Regel-Spezifikation (keine Regelnummern),
Whitelisting gegen Befehls-Injection, firewalld-Lockout-Schutz (Ports vor dem Start
in der permanenten Konfiguration).
- fail2ban: kanonischer (inet_pton) Schutz gegen das Sperren des eigenen Zugangs,
ignoreip wird verbatim erhalten (inkl. Hostnames/Fortsetzungszeilen).
## [0.1.1] - 2026-06-13
Wartungs-Release: vollständige Code-Auditierung, Entfernung von totem Code und ein behobenes Open-Redirect. Keine funktionalen Änderungen für Nutzer.
### Behoben
- Open-Redirect im Server-Switcher: ein manipulierter `Referer` konnte die
Weiterleitung nach dem Server-Wechsel auf eine fremde Adresse lenken. Die
Weiterleitung wird jetzt auf einen **gleich-origin** relativen Pfad reduziert
(fremde Schemata wie `javascript:`/`data:`, andere Hosts/Ports sowie
protokoll-relative Tricks `//host` / `/\host` werden abgewiesen).
- SSH-Zugang: eine Passphrase wurde unabhängig vom Auth-Typ gespeichert; sie wird
jetzt nur noch bei Schlüssel-Authentifizierung hinterlegt.
### Geändert
- Datei-Manager + Editor verwenden ein eigenes `file`-Symbol statt des
Audit-Symbols (semantisch korrekt).
- Code-Hygiene: toten Code entfernt (ungenutzte `FirewallService`-Methoden
`status/allow/deny`, `Server::auditEvents()`, `SshCredential::scopeActive()`,
ungenutztes `bell`-Icon), veraltete Doc-Blöcke/Kommentare korrigiert,
Exceptions sauber importiert, base64-Argument im Sudo-Pfad defensiv gequotet,
Null-sichere Nutzerabfrage in den Einstellungen. Pint + Codex-Review sauber.
## [0.1.0] - 2026-06-13
Erste geschnittene Version die komplette v1-Basis inklusive Server- und Panel-Härtung als ein Release.
### Hinzugefügt
- Dashboard mit Live-Sparklines und poll-getriebenem Dual-Chart (KPIs + Tabelle).
- Server-Index + Detailseite, Dienste (systemd: Start/Stop/Restart + Journal),
Datei-Manager (SFTP: Up-/Download, Editor), Audit-Log.
- SSH-Schicht über phpseclib (exec + SFTP) mit Host-Key-Pinning (TOFU) und
Multi-Server-Switcher samt Fleet-Kontext.
- Echte Metriken (CPU/RAM/Disk/Load) inkl. Absolutwerten über Reverb.
- Authentifizierung + 2FA (TOTP) mit erzwungenem Onboarding.
- R5-Bestätigungsmodals (wire-elements/modal) für destruktive Aktionen.
- System-Seite mit Domain & TLS (Caddy Auto-TLS) und Release-Kanal.
- Echte Versions-Seite, die Version, Build-Hash und dieses Änderungsprotokoll liest.
- Deploy: `install.sh` + Caddy (Auto-TLS) + Produktions-Härtung.
- Selbst-gehostete Fonts (kein CDN), Split-Brand Login/2FA.
### Geändert
- Dienst-Steuerung läuft über das hinterlegte Sudo-Passwort (`sudo -S`) statt nur
passwortlosem sudo Start/Stop/Restart + Journal funktionieren live.
- Lazy-Loading der Seiten (Skeletons), normalisierte Buttons + Spinner,
Detailseiten- und Einstellungs-Redesign, Schlüsselerzeugung.
- Vollständige Regel-Auditierung (R1R14), neue Regel R14 (lokale Fonts).
### Behoben
- Datei-Editor: Klick löste einen Alpine-Fehler aus (`@js()` kompiliert nicht in
Komponenten-Attributen) auf Index-Lookups umgestellt.
- Adversarial Review der SSH-Schicht (Escaping, Parser, Host-Key-Pinning).
- 500 durch `@disabled` auf `<x-btn>`; Modal über dem Backdrop; poll-getriebene
Metriken (Chart + Gauges) statt fiktiver Fleet-Daten; 2FA-Setup-QR als `<img>`.
- fail2ban/apt-Härtung schlug fehl, weil der 12s-SSH-Timeout den Paket-Install
abbrach langer Timeout für apt-Aktionen.
### Sicherheit
- Server-Härtung aus dem Dashboard (Root-/Passwort-Login, fail2ban, UFW,
Auto-Updates) mit Befehls-Vorschau, Bestätigung und Aussperr-Schutz.
- Verwaltung hinterlegter SSH-Zugänge (Name, Sperren, Löschen); der Vault
verweigert gesperrte Zugänge. Dienst-Steuerung über hinterlegtes Sudo-Passwort.
- Panel-Selbst-Härtung: Security-Header + umgebungsbewusste CSP, 2FA-Brute-Force-
Drossel, Session-Cookie-Härtung.
- Release-/Versionierungsmodell: echte semantische Versionen + Git-Tags, Changelog
pro Version, Kanäle `stable`/`beta` (kein nutzer-seitiges `dev`).
[Unreleased]: https://git.bave.dev/boban/clusev/compare/v0.2.1...HEAD
[0.2.1]: https://git.bave.dev/boban/clusev/compare/v0.2.0...v0.2.1
[0.2.0]: https://git.bave.dev/boban/clusev/compare/v0.1.1...v0.2.0
[0.1.1]: https://git.bave.dev/boban/clusev/compare/v0.1.0...v0.1.1
[0.1.0]: https://git.bave.dev/boban/clusev/releases/tag/v0.1.0