654 lines
40 KiB
Markdown
654 lines
40 KiB
Markdown
# 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.9.11] - 2026-06-19
|
||
|
||
### Behoben
|
||
- **„Neuestes Release" zeigt nie mehr eine ältere Version als die installierte.** Direkt nach einem
|
||
Update konnte der 30-Minuten-Cache der Update-Prüfung noch den vorherigen Stand halten, sodass die
|
||
Karte „Installiert" z. B. „Neuestes Release v0.9.9" neben „installiert v0.9.10" zeigte (wirkte
|
||
rückwärts). Ist der gecachte Wert kleiner als die installierte Version, wird er jetzt verworfen
|
||
(Anzeige „—"), bis „Nach Updates suchen" den echten neuesten Tag auflöst.
|
||
|
||
## [0.9.10] - 2026-06-19
|
||
|
||
### Behoben
|
||
- **Build-Commit & Branch werden jetzt auch in Produktion angezeigt** (System → Version & Releases,
|
||
Karte „Installiert"). Sie wurden zur Laufzeit aus `.git` gelesen — das im Docker-Prod-Image
|
||
fehlt — also stand dort „Build —" und als Branch der Kanal. `install.sh` bäckt den deployten
|
||
Commit (`git rev-parse --short HEAD`) und Branch jetzt aus dem `.git` des Hosts in die `.env`
|
||
(`CLUSEV_BUILD_SHA`/`CLUSEV_BUILD_BRANCH`); die Versions-Seite bevorzugt diese und liest im Dev
|
||
weiterhin direkt aus `.git`.
|
||
|
||
## [0.9.9] - 2026-06-19
|
||
|
||
### Hinzugefügt
|
||
- **„Jetzt aktualisieren" im Dashboard (System → Version & Releases).** Ist ein neueres Release im
|
||
Kanal verfügbar, lässt sich das Update jetzt per Knopf auslösen — ganz ohne SSH. Gleiches sichere
|
||
Muster wie der Neustart-Knopf: der Container schreibt nur eine Sentinel-Datei (kein Docker-Socket),
|
||
ein **als root laufender** Host-Watcher (`clusev-update.path`/`.service`) führt `update.sh` aus
|
||
(`git pull` + idempotenter Re-Install) und verbraucht die Sentinel **vor** dem Lauf, damit ein
|
||
dauerhafter Fehler nicht endlos wiederholt. Der Knopf erscheint nur, wenn eine neuere Version
|
||
gefunden wurde, ist per-Nutzer gedrosselt (3/10 Min, auto-ablaufend) und auditiert
|
||
(`deploy.update_request`). Hinweis im UI: das Dashboard ist während des Rebuilds ein bis zwei
|
||
Minuten nicht erreichbar; danach neu laden. `install.sh` installiert die neuen Host-Units mit.
|
||
|
||
## [0.9.8] - 2026-06-19
|
||
|
||
### Hinzugefügt
|
||
- **`update.sh` — Ein-Befehl-Update (`sudo ./update.sh`).** Holt den neuesten Stand
|
||
(`git pull --ff-only`, verwirft nie lokale Änderungen), **aktualisiert sich bei Bedarf selbst**
|
||
(hat sich `update.sh` im Pull geändert, startet es die neue Version neu) und übergibt dann an den
|
||
idempotenten `install.sh` (Build, Neustart, Migration, MOTD). Setzt für root automatisch
|
||
`safe.directory` (das Verzeichnis gehört dem `clusev`-Nutzer, sonst verweigert ein root-`git pull`)
|
||
und ruft `install.sh` **nicht-interaktiv** auf, sodass nichts neu abgefragt wird.
|
||
|
||
### Behoben
|
||
- **Re-Run von `install.sh` bewahrt jetzt Domain & ACME-E-Mail.** Bislang schrieb der Installer
|
||
`APP_DOMAIN`/`ACME_EMAIL` bei jedem Lauf — ein nicht-interaktiver Re-Run (also ein Update) ohne
|
||
gesetzte `CLUSEV_DOMAIN` hätte eine konfigurierte Domain **gelöscht**. Beide defaulten jetzt auf den
|
||
bestehenden `.env`-Wert; Erst-Installation (leer = Bare-IP) unverändert.
|
||
|
||
### Geändert
|
||
- **README-Update-Abschnitt** auf `sudo ./update.sh` umgestellt (der alte Zweischritt
|
||
`git pull && sudo ./install.sh` funktioniert weiterhin); MOTD zeigt den Update-Befehl an.
|
||
|
||
## [0.9.7] - 2026-06-19
|
||
|
||
### Behoben
|
||
- **Update-Prüfung (System → Version & Releases) funktioniert jetzt in Produktion.** Sie las das
|
||
neueste Release aus dem lokalen `.git` — das es im Docker-Prod-Image gar nicht gibt, daher meldete
|
||
„Nach Updates suchen" dort **immer** „Noch kein Release getaggt", selbst wenn längst eine neuere
|
||
Version veröffentlicht war. Der neueste Tag im Kanal wird jetzt über die **öffentliche, lesende
|
||
Tag-API des Git-Hosts** abgefragt (anonym — kein Token verlässt das Panel), mit lokalem `.git` nur
|
||
noch als Dev-Fallback; das Ergebnis ist gecacht, sodass ein Seitenaufruf nie eine Netzwerkanfrage
|
||
auslöst (nur der Knopf selbst). Kanal-Logik: `stable` bietet nur `vX.Y.Z`, `beta` auch Vorab-Tags.
|
||
Schlägt die Abfrage fehl (offline o. Ä.), degradiert sie still statt zu blockieren.
|
||
|
||
## [0.9.6] - 2026-06-19
|
||
|
||
### Geändert
|
||
- **Erst-Admin nutzt jetzt eine feste Standard-E-Mail `admin@clusev.local`** (statt einer aus dem
|
||
Hostnamen abgeleiteten Adresse, die man hätte raten müssen). Zusammen mit dem Standard-Passwort
|
||
`clusev` ist der Erst-Login auf jeder frischen Installation vorhersehbar (`admin@clusev.local` /
|
||
`clusev`, Zwangswechsel beim ersten Login). `--email` / `CLUSEV_ADMIN_EMAIL` überschreiben weiter;
|
||
später unter Einstellungen → Profil änderbar. Installer-Prompt, README und Banner aktualisiert.
|
||
|
||
### Behoben
|
||
- **Command-Palette öffnete sich nach dem ersten Login von selbst und ließ sich nicht schließen**
|
||
(nur im Prod-Build). Ursache: `app.js` baute `window.Echo` auf Top-Level; auf Auth-Seiten fehlt die
|
||
Laufzeit-Reverb-Config (`window.__clusev`) und der Prod-Build bäckt absichtlich keine
|
||
`VITE_REVERB_*`-Fallbacks ein, also warf der Echo-Konstruktor — und brach das Skript **vor** der
|
||
`alpine:init`-Registrierung ab. Dadurch waren `cmdk`/`modalTrigger`/`dualChart` nicht registriert,
|
||
Alpine konnte `x-data="cmdk(…)"` nicht auflösen, entfernte aber `x-cloak`, und das Palette-Overlay
|
||
fiel auf seine sichtbare Default-Darstellung zurück (undismissbar). Echo wird jetzt nur bei
|
||
vorhandener Config konstruiert, in `try/catch` gekapselt (ein Realtime-Fehler legt die UI nie lahm)
|
||
und bei `livewire:navigated` nachgezogen (Realtime auch auf dem per-SPA erreichten Dashboard). Im
|
||
Dev mit Vite trat es nie auf, da Vite die `VITE_REVERB_*` aus der Dev-`.env` einbäckt.
|
||
|
||
## [0.9.5] - 2026-06-17
|
||
|
||
### Geändert
|
||
- **Erst-Admin nutzt jetzt das Standard-Passwort `clusev`** (statt eines Einmal-Zufallspassworts) —
|
||
vorhersehbarer Login. **`must_change_password` erzwingt den Wechsel beim ersten Login**, und
|
||
Banner/MOTD/README weisen ausdrücklich darauf hin, es **sofort** zu ändern (ein bekanntes Default
|
||
ist nur durch den erzwungenen Wechsel vertretbar). Idempotenz unverändert (kein Admin bei Re-Run).
|
||
- **Host-MOTD deutlich aufgewertet.** Statt zwei Zeilen jetzt eine orange CLUSEV-Wortmarke, die
|
||
Version, ein **Live-Stack-Status** („X/Y Dienste aktiv", grün/rot — bei jedem Login frisch aus
|
||
`docker compose ps`), die Dashboard-URL, eine Login-Hinweiszeile (woher die Zugangsdaten kommen —
|
||
ohne Secret) und die Verwaltungs-Befehle. `install.sh` setzt URL, Version und den Compose-Pfad ein;
|
||
fällt bei fehlendem Docker robust auf „Status unbekannt" zurück (bricht nie einen Login ab).
|
||
|
||
### Behoben
|
||
- **README-Voraussetzungen:** `git` ist auf minimalen Debian/Ubuntu-Images nicht vorinstalliert, der
|
||
`git clone`-Schritt scheiterte dort vor dem Installer. Der Install-Block installiert `git` jetzt
|
||
explizit, und „Voraussetzungen" nennt es (ein Full-VM-Installtest hat das aufgedeckt).
|
||
|
||
## [0.9.4] - 2026-06-17
|
||
|
||
### Hinzugefügt
|
||
- **„DNS prüfen & Zertifikat anfordern" im Dashboard (System → Domain & TLS).** Wurde eine Domain
|
||
konfiguriert, deren DNS noch nicht auf den Server zeigte, lässt sich das Let's-Encrypt-Zertifikat
|
||
jetzt per Knopf anstoßen, sobald das DNS stimmt: eine DNS-Vorabprüfung (zeigt die Domain hierher?)
|
||
und — nur ohne klare Fehlanpassung — ein interner Handshake, der Caddys On-Demand-Ausstellung
|
||
auslöst, plus ein persistierter Status (aktiv / DNS zeigt woanders / ausstehend). Sichtbar nur im
|
||
eingebauten-TLS-Modus mit aktiver Domain (im Externer-Proxy-Modus ein Hinweis, bei Bare-IP nichts).
|
||
Per-Nutzer gedrosselt (5/10 Min, auto-ablaufend — sperrt die Control-Plane nie aus) + auditiert; der
|
||
Handshake ist fest auf den `caddy`-Dienst gepinnt (kein SSRF). Hinweis: das automatische On-Demand
|
||
greift weiterhin von selbst beim ersten HTTPS-Aufruf — der Knopf gibt nur explizite Kontrolle +
|
||
Statusrückmeldung.
|
||
|
||
## [0.9.3] - 2026-06-17
|
||
|
||
### Behoben
|
||
- **Modal-Trigger zuverlässig + mit Feedback.** Modale gingen direkt nach einer Navigation teils
|
||
erst beim 2.–3. Klick auf (Konsole: „Could not find Livewire component in DOM tree"), und der
|
||
Button gab kein Signal. Ursache: der globale Modal-Manager wurde bei jedem `wire:navigate` ab-
|
||
und neu aufgebaut, sodass sein `openModal`-Listener kurz fehlte. Er bleibt jetzt über `@persist`
|
||
für die ganze Sitzung bestehen — Modale öffnen beim ersten Klick. Zusätzlich zeigt **jeder**
|
||
Modal-Trigger (in allen Views) ab Klick sofort einen Spinner und blendet einen Fehler-Toast ein,
|
||
falls nach kurzer Zeit nichts aufgeht (neues `<x-modal-trigger>`-Element; der Toaster kennt jetzt
|
||
eine rote Fehler-Variante). So kann ein Klick nie tot wirken und ein echtes Fehlschlagen ist nie
|
||
stumm.
|
||
|
||
### Sicherheit
|
||
- **Passwort-Reset-Timing weiter abgeflacht.** Der Dummy-Verifikationspfad für unbekannte Konten
|
||
spiegelt jetzt exakt die Kosten der echten Recovery-Code-Prüfung (gesperrtes `SELECT` in einer
|
||
Transaktion statt eines schwereren bcrypt-Vergleichs), und Transportfehler beim Reset-Link werden
|
||
geloggt statt stillschweigend verschluckt.
|
||
- **Brute-Force-/Rate-Limiting-Härtung (Audit-Nachgang).** Alle neuen Limits laufen automatisch ab
|
||
und sperren die Control-Plane nie dauerhaft (Bare-IP-Recovery + `clusev:reset-admin` bleiben offen):
|
||
- **Login** zusätzlich pro IP (20/Min) und pro Konto (30/15 Min) begrenzt — ein verteilter
|
||
Mehr-IP-Angriff auf das eine Admin-Konto wird gedeckelt statt linear zu skalieren; und der
|
||
Login-Zweig für unbekannte E-Mails führt jetzt denselben bcrypt aus (Konstantzeit) und schließt
|
||
so das Konten-Enumerations-Timing-Orakel.
|
||
- **TOTP-Replay-Schutz:** jeder 6-stellige Code ist genau einmal gültig (zuletzt akzeptierter
|
||
Zeit-Schritt wird persistiert), ein abgefangener Code lässt sich nicht im 30-Sek-Fenster
|
||
wiederverwenden.
|
||
- **2FA-Challenge & 2FA-Beweis-Reset** zusätzlich pro Konto begrenzt (IP-unabhängiger Backstop),
|
||
sodass die TOTP-/Backup-Code-Brute-Force-Fläche auch verteilt gedeckelt ist.
|
||
- **Globaler `/livewire/update`-Throttle** (180/Min pro Identität) als Flut-Deckel über den
|
||
Per-Aktion-Limitern.
|
||
- **Re-Auth gedrosselt** (Passwortänderung/-Profil, 5/Min pro Nutzer) gegen Passwort-Brute-Force
|
||
über eine gekaperte Session; **SMTP-Testversand** auf 3/10 Min pro Nutzer begrenzt (kein
|
||
Spam-Relay).
|
||
- **DoS-Schutz:** SSH bekommt einen kurzen, separaten Connect-Timeout (~5 s), damit ein toter/
|
||
langsamer Host einen Worker nicht über mehrere sequentielle Reads × 15 s blockiert; die
|
||
Profil-Passwort-Policy auf 12 Zeichen + Groß/Klein + Ziffern angehoben (war 10).
|
||
|
||
## [0.9.2] - 2026-06-15
|
||
|
||
### Hinzugefügt
|
||
- **Ein-Befehl-Installer (`sudo ./install.sh`).** Bootstrappt einen frischen Debian/Ubuntu-Host
|
||
vollständig: installiert Docker aus dem offiziellen apt-Repo, legt einen dedizierten
|
||
`clusev`-Login-Benutzer (Zufallspasswort, `docker`-Gruppe) an, prüft per DNS-Abgleich, ob die
|
||
angegebene Domain auf diesen Host zeigt (sonst Warnung + Wahl „Domain trotzdem nehmen — HTTP bis
|
||
DNS stimmt" oder „auf der IP bleiben"), baut/startet den Stack, migriert und legt den ersten Admin
|
||
an. Das Abschluss-Banner zeigt ausschließlich Dashboard-URL, Admin-Login und — bei Erstanlage — den
|
||
`clusev`-Host-Benutzer; Passwörter erscheinen nur dieses eine Mal. Idempotent (Re-Run baut/migriert
|
||
neu, Secrets bleiben erhalten).
|
||
- **Themed Host-MOTD.** Bei jeder Host-Anmeldung erscheint ein Login-Banner in der
|
||
Produkt-Signalfarbe mit der Dashboard-Adresse.
|
||
|
||
### Geändert
|
||
- **Professionelles README** — Produktbeschreibung, Voraussetzungen, Installation (`git clone` +
|
||
`sudo ./install.sh`), Domain/TLS (inkl. externem Reverse-Proxy), Updates, Konto-Wiederherstellung
|
||
und AGPL-Lizenz; ohne interne Entwicklungs-Hinweise.
|
||
|
||
### Sicherheit
|
||
- **Passwort-Reset in konstanter Zeit.** Unbekannte E-Mail-Adressen durchlaufen jetzt denselben
|
||
Verifikationspfad (Dummy-Hash- bzw. Code-Prüfung) wie existierende Konten — die Antwortzeit verrät
|
||
nicht mehr, ob ein Konto existiert (Account-Enumeration über ein Timing-Orakel ausgeschlossen).
|
||
|
||
## [0.9.1] - 2026-06-15
|
||
|
||
### Geändert
|
||
- **Passwort-vergessen ist jetzt SMTP-bewusst.** Mit konfiguriertem SMTP ist der Standard ein
|
||
**E-Mail-Reset-Link (15 Minuten gültig)**; ein Zweit-Schalter „Kein E-Mail-Zugang? Mit 2FA-Code
|
||
zurücksetzen" blendet den Inline-2FA-Reset ein. Ohne SMTP nur der 2FA-Besitznachweis-Reset. Der
|
||
`clusev:reset-admin`-Hinweis ist von der öffentlichen Seite verschwunden und steht jetzt in
|
||
Einstellungen → Sicherheit (eingeloggt) + README.
|
||
- **System-Seite neu komponiert** statt nur schmaler: 2-Spalten-Layout (links Konfiguration —
|
||
Domain + TLS-Modus, rechts Status & Wiederherstellung), kritische Hinweise (Neustart, Bare-IP) als
|
||
Banner über dem Raster.
|
||
- **Firewall/fail2ban-Bereich:** eine einzeln installierte Box füllt jetzt die volle Breite mit
|
||
interner 2-Spalten-Aufteilung (kein leerer Raum mehr); zwei Boxen weiterhin nebeneinander.
|
||
|
||
### Sicherheit
|
||
- **Backup-Codes nur einmal sichtbar — wasserdicht.** Codes werden ausschließlich direkt nach der
|
||
Erzeugung (erster Faktor oder „Neu erzeugen") angezeigt; „Backup-Codes verwalten" zeigt sie NICHT
|
||
mehr an, sondern bietet nur „Neu erzeugen". Der Reveal läuft über einen transienten Kanal (nicht über
|
||
eine persistierte Livewire-Property), sodass ein abgefangener/replayter Snapshot sie nicht erneut
|
||
rendert; das Reveal-Flag hat eine 10-Minuten-TTL, und der Download-Endpunkt verlangt eine frische,
|
||
einmalige Berechtigung.
|
||
- **Bestätigungs-Dialoge signiert & einmalig.** Destruktive Aktionen (Konto/Session/2FA/Hardening/…)
|
||
laufen über server-ausgestellte, einmal gültige, signierte Tokens statt client-manipulierbarer
|
||
Event-/Audit-Felder — Bestätigungs-Bypass und Audit-Fälschung sind ausgeschlossen; per-Aktion
|
||
server-seitig auf das Ziel beschränkt.
|
||
|
||
### Behoben
|
||
- **fail2ban „Gesperrte IPs"-Modal öffnet sofort** — Skeleton + Lazy-Load statt blockierendem
|
||
SSH-Read beim Öffnen.
|
||
- **Security-Keys-Untertitel** korrigiert: ein Schlüssel kann alleiniger Faktor sein, mit TOTP oder
|
||
beides — nicht mehr „nur als zweiter Faktor".
|
||
- **System-Seite:** TLS-Modus-Schalter bricht nicht mehr um (kürzeres Label, Details in der
|
||
Beschreibung); Domain-Feld zeigt nur noch einen Platzhalter (kein vorausgefüllter Beispielwert).
|
||
- **Einstellungen mobil:** die Tab-Leiste ist breiter als der Schirm geworden — jetzt horizontal
|
||
scrollbar und sauber abgeschnitten (auf Desktop weiterhin vertikal).
|
||
|
||
## [0.9.0] - 2026-06-14
|
||
|
||
### Hinzugefügt
|
||
- **Mehrere Benutzer-Accounts.** Einstellungen → Benutzer: weitere (gleichberechtigte) Admin-Konten
|
||
anlegen, auflisten, entfernen. Neuanlage erzeugt ein Einmal-Passwort (einmalig angezeigt) +
|
||
erzwungenen Passwortwechsel beim ersten Login. Das Audit-Log hält fest, wer was getan hat.
|
||
- **Sitzungsverwaltung.** Einstellungen → Sitzungen: aktive Sitzungen ansehen (Gerät, IP, zuletzt
|
||
aktiv), „andere Geräte abmelden" (eigene) und „alle abmelden (global)"; je Benutzer „überall
|
||
abmelden". Jede Abmeldung rotiert den remember-Token.
|
||
- **Automatischer Neustart.** „Jetzt neu starten" in System schreibt eine Anforderung, die ein
|
||
Host-Watcher (systemd) ausführt — kein Terminal-Befehl, kein Docker-Socket im Container.
|
||
- **SMTP-Konfiguration.** Einstellungen → E-Mail: SMTP-Server hinterlegen (Passwort verschlüsselt),
|
||
Testmail senden. Damit funktionieren Passwort-vergessen-Mails wirklich.
|
||
- **Audit-Log-Aufbewahrung.** Konfigurierbare Aufbewahrungsdauer + täglicher `clusev:prune-audit`.
|
||
- **Datei-Manager zeigt Bilder an.** Öffnet man eine Bilddatei (png/jpg/gif/webp/svg/…), wird sie
|
||
als Vorschau angezeigt statt im Texteditor (SFTP→base64, max. 5 MB, Speichern für Bilder aus).
|
||
- **fail2ban: gesperrte IPs im Modal.** Die lange Jail-/Bann-Liste wandert aus dem Panel in ein
|
||
scrollbares Modal ("Gesperrte IPs ansehen") — mit Entsperren je IP.
|
||
- **Login & Passwortfelder: Anzeigen/Verbergen-Umschalter** (Auge-Icon) in Login, Passwort ändern,
|
||
Reset und Passwort-vergessen.
|
||
|
||
### Geändert
|
||
- **Sitzungen liegen jetzt in der Datenbank** (statt Redis), damit sie auflist- und widerrufbar sind.
|
||
**Einmaliger Effekt:** beim Update werden alle bestehenden Sitzungen ungültig — einmal neu anmelden.
|
||
- **Einstellungen in eigene Tabs** (Profil · Sicherheit · Benutzer · Sitzungen · E-Mail), jeweils als
|
||
eigene Komponente.
|
||
- **System-Seite aufgeräumt:** Inhalt auf eine angenehme Lesebreite begrenzt (nicht mehr
|
||
randlos), echtes Speichern-Icon, „Caddy" in der Oberfläche durch neutrale Begriffe ersetzt,
|
||
plus Hinweis auf die SSH-Notfall-Wiederherstellung (`clusev:reset-admin`).
|
||
- **Eingabefelder:** E-Mail-Felder nutzen jetzt `type="text"` — die Validierung (inkl. Format)
|
||
passiert ausschließlich serverseitig in der Livewire-Klasse (einheitliche, lokalisierte Meldungen).
|
||
- **Backup-Codes-Modal:** Buttons sauber ausgerichtet; der Abschluss-Button heißt jetzt „Schließen"
|
||
(er schließt nur). Alle Modal-Textfelder sind nicht mehr in der Größe ziehbar.
|
||
|
||
## [0.8.0] - 2026-06-14
|
||
|
||
### Hinzugefügt
|
||
- **TLS über externen Reverse-Proxy (z. B. Zoraxy).** Neuer TLS-Modus in System → Domain & TLS:
|
||
„Externer Reverse-Proxy" statt „Caddy (Let's Encrypt)". Im externen Modus holt Caddy **kein**
|
||
Zertifikat mehr (`/_caddy/ask` verweigert) und das Panel erzwingt **keinen** eigenen
|
||
HTTPS-Redirect — ein Proxy davor terminiert TLS und liefert an den HTTP-Port. Die Host-Prüfung
|
||
und der Bare-IP-Recovery-Pfad bleiben in beiden Modi aktiv; die Umstellung gilt nach Stack-Neustart.
|
||
Caddy vertraut dem `X-Forwarded-Proto` des Proxys über `TRUSTED_PROXY_CIDR` (Default `127.0.0.1/32`
|
||
= nichts Externes); Hinweis in der UI, den HTTP-Port per Firewall nur dem Proxy zugänglich zu machen.
|
||
|
||
### Behoben (Sicherheit)
|
||
- **Onboarding-Gate auch auf Livewire-Updates.** `EnsureSecurityOnboarded` ist jetzt persistente
|
||
Livewire-Middleware: das Gate greift auch bei `/livewire/update`-Aufrufen, nicht nur beim
|
||
Seiten-GET — eine während des Onboardings gemountete Komponente kann keine destruktiven Aktionen
|
||
mehr ausführen, nachdem das Konto mitten in der Sitzung auf „Passwort ändern erforderlich"
|
||
zurückgesetzt wurde.
|
||
|
||
## [0.7.0] - 2026-06-14
|
||
|
||
### Hinzugefügt
|
||
- **Optionale, pluggbare 2FA (TOTP und/oder Security-Key — oder aus).** 2FA ist nicht mehr
|
||
erzwungen: Der Betreiber entscheidet selbst, ob er sein Konto absichert, und wählt TOTP, einen
|
||
Security-Key (YubiKey/WebAuthn) oder beides — oder lässt 2FA ganz aus. Empfohlen, nicht Pflicht.
|
||
- **Onboarding erzwingt nur noch die Passwort-Rotation** (kein 2FA-Zwang mehr). Nach dem
|
||
Passwortwechsel landet man direkt im Dashboard; 2FA wird in den Einstellungen angeboten
|
||
(Hinweis „empfohlen").
|
||
- **Ein Security-Key kann der einzige/erste Faktor sein** (vorher war TOTP Voraussetzung).
|
||
TOTP und Keys werden in Einstellungen → Sicherheit unabhängig hinzugefügt/entfernt.
|
||
- **Login-Challenge passt sich dem Faktor an:** TOTP-Nutzer sehen das Code-Feld, reine
|
||
Key-Nutzer führen mit dem Security-Key (Backup-Code als Rückfall) — kein irreführendes
|
||
6-stelliges Feld mehr.
|
||
- **Backup-Codes als Modal** statt eigener Seite: werden beim ersten Faktor erzeugt und einmal
|
||
gezeigt, später jederzeit über „Backup-Codes verwalten" wieder einsehbar / neu erzeugbar /
|
||
herunterladbar. Die alte `/two-factor/recovery-codes`-Seite + Route entfällt (Download bleibt).
|
||
- **Backup-Codes folgen den Faktoren:** beim Entfernen des letzten Faktors werden sie geleert,
|
||
bei verbleibendem Faktor behalten.
|
||
- **Passwort-vergessen ist key-only-sicher:** ein reiner Key-Nutzer setzt per Backup-Code zurück;
|
||
ohne 2FA per E-Mail-Link (falls SMTP) oder `clusev:reset-admin`.
|
||
- **SSH-Key automatisch erstellen & Passwort-Login sicher deaktivieren.** Statt der bisherigen
|
||
Sackgasse („Key zuerst hinterlegen") erzeugt das Panel auf Knopfdruck einen ed25519-Key,
|
||
installiert ihn, **prüft den Key-Login**, stellt die eigene gespeicherte Verbindung darauf um —
|
||
und schaltet Passwort-Login **erst danach** ab. Scheitert die Prüfung, bleibt Passwort-Login aktiv
|
||
(kein Aussperren, auch nicht der Control-Plane). Der Private-Key wird einmalig angezeigt
|
||
(Download) und verschlüsselt im Vault gehalten.
|
||
- **Schnellsuche (Strg/⌘ K) findet Server:** Tippen von Name oder IP springt direkt zur
|
||
Server-Detailseite.
|
||
- **Journal ist live:** `journalctl` wird per Cursor inkrementell nachgeladen (alle 5 s, lückenlos,
|
||
ohne Duplikate) statt eines einmaligen Schnappschusses; Anzeige auf 200 Zeilen begrenzt und
|
||
scrollbar (fixe Höhe), folgt automatisch dem neuesten Eintrag.
|
||
|
||
### Geändert
|
||
- **Metriken-Broadcast-Gate:** `securityOnboarded()` heißt jetzt „Passwort rotiert" (nicht mehr
|
||
„+ 2FA"), da 2FA optional ist — Metriken streamen an eine passwort-rotierte Session.
|
||
|
||
### Behoben
|
||
- **Alleinstehende Firewall-/fail2ban-Box** dehnte sich über die volle Breite; ist jetzt auf eine
|
||
sinnvolle Kartenbreite begrenzt, wenn nur ein Tool installiert ist.
|
||
- **Einstellungen-Tab in der URL** (`?tab=…`): Reload/Deep-Link bleibt auf dem gewählten Tab statt
|
||
auf „Profil" zurückzuspringen.
|
||
|
||
## [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
|
||
HTTP→HTTPS 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 (R1–R14), 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
|