Commit Graph

227 Commits (v1.1.347)

Author SHA1 Message Date
boban de314adebe Fix: Backup läuft als root via sudo – keine Permission-Fehler mehr
mailwolt-backup Script liest /etc/dovecot/private, /etc/letsencrypt/live
etc. als root. ensure_system() installiert es nach sbin + sudoers.
BackupRun.php ruft es via sudo -n auf.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:37:27 +02:00
boban 7e7d5c1069 Fix: CheckUpdates nutzt exec() statt shell_exec() für --check-only
shell_exec kann auf PHP-FPM Servern deaktiviert sein, wodurch
version_remote nie aktualisiert wurde und kein Update angezeigt wurde.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:36:08 +02:00
boban aaccb4bb32 Fix: optionale Dienste (ClamAV) immer live prüfen statt Monit-Cache
Monit-Cache wurde jede Minute neu befüllt mit altem Status.
Optionale Dienste werden jetzt direkt via systemctl geprüft.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:33:11 +02:00
boban 7ccc7921c1 Fix: health:services Cache nach ClamAV enable/disable leeren
Dashboard zeigte ClamAV bis zu 5 Min. falsch als online/offline weil
der Monit-Cache veraltet war. Cache wird jetzt sofort invalidiert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:29:33 +02:00
boban ce66a84c8d Fix: ClamAV wird beim Update automatisch installiert, UI nur Ein/Aus
ensure_system() installiert clamav-daemon falls nicht vorhanden,
deaktiviert aber den Dienst. User sieht nur noch Ein/Ausschalten.
Install-Button, $installed-Property und install()-Methode entfernt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:19:26 +02:00
boban fa65bc1c2e Fix: ClamAV isInstalled() via file_exists statt Hardcode true
Prüft /usr/sbin/clamd und systemd unit-Dateien ohne exec().
Zeigt Install-Button wenn ClamAV nicht installiert ist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:17:24 +02:00
boban 5f627dcb0e Fix: ClamAV enable mit --no-block + kein Queue-Job nötig
systemctl start --no-block kehrt sofort zurück, systemd startet ClamAV
im Hintergrund. runCmd('enable') direkt aufrufen statt Queue-Job.
wire:poll.keep-alive verhindert payload-Fehler in der Browser-Console.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:15:18 +02:00
boban 3f6f787fd3 Fix: ClamAV starting-State überlebt Reload + kein false-dirty bei untracked
Flag-Datei /tmp/mw-clamav-starting speichert Startzeitpunkt sodass
Spinner + Timer auch nach Seitenreload korrekt weiterläuft.
git_dirty_check filtert jetzt untracked Dateien (??) heraus damit
mailwolt-installer/ und ähnliche nicht fälschlich als dirty gelten.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:11:55 +02:00
boban 2331ef74f6 Feat: ClamAV Aktivieren mit Spinner + Sekundentimer bis ClamAV läuft
wire:poll.3s prüft serviceActive() nach Klick. Zeigt laufenden Spinner
mit Sekundenanzeige (0s, 3s, 6s…) bis ClamAV aktiv ist, dann Erfolgsmeldung.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:08:46 +02:00
boban 029d959d51 Fix: ClamAV enable via Queue Job statt shell_exec im Web-Request
nohup/shell_exec wird von PHP-FPM-Prozessgroup nach Request-Ende gekillt.
ClamavEnable Job läuft im Queue-Worker und blockiert nicht den Web-Request.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 21:00:33 +02:00
boban 68e7635f6d Fix: ClamAV enable() blockiert nicht mehr – shell_exec + nohup + </dev/null
exec() wartet auch mit & auf Prozessende. shell_exec mit nohup und
stdin-Redirect auf /dev/null stellt echtes Hintergrund-Detaching sicher.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 20:54:42 +02:00
boban 673e9ec1df Fix: ClamAV enable() – kein Spinner mehr, einfache Textmeldung
$starting-Property, pollStatus() und wire:poll entfernt.
enable() startet ClamAV im Hintergrund und zeigt nur eine
Info-Meldung an – kein dauerhafter Spinner.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 20:53:35 +02:00
boban 79b1eeb93c Fix: ClamAV enable non-blocking – Hintergrund-Start + Poll alle 3s
- enable() startet Dienst via nohup im Hintergrund (kein Request-Timeout)
- $starting=true → wire:poll.3s ruft pollStatus() auf
- Overlay zeigt "ClamAV wird gestartet… lädt Viren-DB / bis 60s"
- pollStatus() erkennt wenn Dienst läuft → Overlay weg, Erfolg-Banner

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 20:44:56 +02:00
boban dc5d8582e1 Fix: ClamAV Feedback – Loading-Overlay + Erfolg/Fehler-Banner inline
- Loading-Overlay über Status-Karte beim Aktivieren/Deaktivieren/Installieren
- $lastSuccess Property für grünen Erfolg-Banner (kein Toast nötig)
- runCmd() helper mit Log für Debugging
- Fehler-Text white-space:pre-wrap für mehrzeilige Ausgaben

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 20:42:45 +02:00
boban a9ad26757b Fix: installed immer true – Enable/Disable immer sichtbar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 20:37:10 +02:00
boban 1bcd93908e Fix: isInstalled via systemctl list-unit-files statt Dateipfad-Check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 20:35:34 +02:00
boban 7d738392b2 Fix: isInstalled() prüft systemd-Unit statt Binary-Pfade
Zuverlässiger auf Servern wo PHP-FPM keinen Zugriff auf /usr/bin hat.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 20:33:37 +02:00
boban 6fa77f9f9b Feature: ClamAV Installation direkt aus der UI + install-Befehl im Wrapper
- mailwolt-clamav: install) apt-get install clamav clamav-daemon clamav-freshclam
- ClamavManager: install() Methode + $installing State
- Blade: Installieren-Button wenn nicht installiert (statt nur Text-Hinweis)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 20:32:30 +02:00
boban b107e9a580 Feature: ClamAV-Verwaltung in Sicherheit-Sidebar
- Neue Seite /security/clamav: Status, Aktivieren/Deaktivieren,
  Signatur-Update, RAM-Hinweis, Info-Box
- Optionale Dienste (ClamAV) im Dashboard nur sichtbar wenn aktiv
- mailwolt-clamav sbin-Wrapper + sudoers-Regel in ensure_system

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 19:21:37 +02:00
boban 3e12d7fd70 Fix: Dashboard zeigt nur die 8 Kern-Dienste (woltguard.dashboard-Liste)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 19:11:44 +02:00
boban 3c6325db32 Fix: Dashboard zeigt Dienste auch ohne Monit (Fallback auf systemd/tcp-Probes)
- loadServices() liest Monit-Cache, fällt zurück auf woltguard.php Karten
  mit direkten systemd/tcp-Probes wenn Cache leer ist
- Monit als Dienst in woltguard.php ergänzt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 19:02:51 +02:00
boban 2369a29161 Fix: migrate-env-reverb prüft auch REVERB_PORT beim Skip-Check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 18:15:56 +02:00
boban 26eb3abdcd Fix: Scheme-Erkennung via APP_URL + nginx-Config statt letsencrypt-Pfad
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 18:13:26 +02:00
boban 4fc31726be Fix: Cert-Prüfung via renewal/-Verzeichnis (www-data-lesbar) statt live/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 18:10:32 +02:00
boban 8fa28a4d84 Fix: migrate-env-reverb liest Domain aus DB-Setting ui_domain als Fallback
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 18:04:52 +02:00
boban 60ebd0ed16 Fix: mailwolt:migrate-env-reverb Command + Update führt Migration immer aus
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 11:01:57 +02:00
boban 29ef2b6a2c Fix: CheckUpdates liest Version-Datei vor git-describe (APP_ENV=local Bug)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 10:30:07 +02:00
boban 996c9c19fe Fix: Laravel Scheduler cron + sudoers für --check-only + CheckUpdates Fallback
- ensure_system() installiert /etc/cron.d/mailwolt für schedule:run
- sudoers: www-data darf mailwolt-update --check-only aufrufen
- CheckUpdates: if/elseif → echter Fallback auf mailwolt-fetch-tags

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 10:13:05 +02:00
boban 7f56926b70 Refactor: SSL-Verwaltung nach Security/SSL verschoben
- Zertifikate einrichten/erneuern nur noch unter Sicherheit → SSL/TLS
- SSL-Seite: Provisioning mit Fortschritt, Ablaufdatum + Tage in Tabelle
- Einstellungen: nur noch read-only Status + Link zu SSL-Seite

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 10:01:58 +02:00
boban 904d60ed2b Fix: 503 fetch-Interceptor + Auto-Update-Polling + SSL-Banner prüft echte Certs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 09:26:20 +02:00
boban d60d228012 Fix: mx-Domain bekommt LE-Zertifikat + Postfix/Dovecot werden konfiguriert
- mailwolt-apply-domains: MAIL_HOST wird in ACME-Challenge-Block aufgenommen,
  certbot wird auch für die Mail-Domain ausgeführt, Postfix + Dovecot erhalten
  danach automatisch das neue Zertifikat
- SslCertificatesTable: certbot-Ausgabe korrekt geparst (Einrückung mit Leerzeichen)
- settings-form: "kein Zertifikat nötig" entfernt (Mail-Domain braucht Zertifikat)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 09:04:02 +02:00
boban 240c672198 Fix: Update-UI zeigt alte Version / schließt sofort ab (Race Condition)
Problem: state-Datei vom letzten Update zeigte noch 'done'. pollUpdate()
las das direkt nach runUpdate() als "Update fertig" — bevor der neue
Prozess überhaupt startete. displayCurrent war dann noch die alte Version.

Fix:
- runUpdate() setzt state='starting' und löscht rc VOR dem Shell-Aufruf
- runUpdate() setzt rc=null, lowState='starting', postActionsDone=false zurück
- refreshLowLevelState(): Kommentar klärt dass 'starting' als running gilt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:50:44 +02:00
boban bd7bb50a52 Fix: SSL-Cert-Status robuster + Provisioning-State nach Reload erhalten
- loadSslStatus(): clearstatcache() + renewal-Conf als primärer Existenzcheck
  (renewal/ ist immer 755, zuverlässiger als is_dir auf live/ das 750 sein kann)
  + /usr/bin/openssl (voller Pfad für sudoers-Matching)
- restoreSslProvisioningState(): stellt letzten Provisioning-Zustand aus
  State-Dateien wieder her, so dass Status nach Page-Reload sichtbar bleibt
- Button zeigt nach Abschluss "Erneut einrichten" statt disabled zu bleiben

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:44:08 +02:00
boban 096e983313 Fix: SSL-Cert-Status zeigt 'Fehlt' obwohl Cert vorhanden
Problem: /etc/letsencrypt/archive/ ist chmod 700 (root only).
file_exists() auf Symlinks in live/ schlägt fehl weil Symlink-Ziel
in archive/ nicht lesbar ist. is_dir() auf live/domain/ funktioniert
da das Verzeichnis selbst 755 ist.

- SettingsForm: file_exists() → is_dir() für Existenzcheck
- SettingsForm: openssl-Aufruf via sudo -n (archive/ ist root-only)
- installer.sh + update.sh: sudoers-Regel für openssl auf LE-Cert-Pfade
  (www-data darf nur exakt diesen openssl-Aufruf, keine anderen Pfade)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:27:49 +02:00
boban ae3b1e6b14 Fix: Update-Check Bootstrap — --check-only Flag in mailwolt-update
Problem: Henne-Ei-Situation — alte Server haben alte CheckUpdates.php die
  git fetch als www-data aufruft (schlägt wegen fehlender Credentials fehl).
  Neue mailwolt-fetch-tags Helper sind noch nicht deployed.

Lösung:
- scripts/update.sh: --check-only Flag — ruft nur git ls-remote als App-User
  auf, schreibt version_remote, beendet sich sofort (kein Update)
- update.sh: schreibt version_remote auch nach normalem Tag-Fetch (damit es
  nach manuellen Updates aktuell bleibt)
- CheckUpdates.php: sichere Fallback-Kette:
  1. mailwolt-update --check-only (nur wenn Skript das Flag kennt — kein
     versehentliches Triggern auf alten Servern)
  2. mailwolt-fetch-tags (ab v1.1.268)
  3. lokale git tags (letzter Fallback)
  + version_remote wird nur verwendet wenn < 2h alt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:13:32 +02:00
boban f740ffc753 Feature: Dedizierter SSL-Abschnitt in Einstellungen mit Echtzeit-Fortschritt
- Neuer Abschnitt "SSL-Zertifikate" in den Einstellungen:
  · Zeigt pro Domain (UI, Webmail, Mailserver) ob LE-Cert vorhanden ist,
    Ablaufdatum und Status (OK / fehlt / läuft ab / abgelaufen)
  · Button "Let's Encrypt Zertifikate einrichten" startet Provisioning
    im Hintergrund (nohup, non-blocking)
  · Live-Fortschrittsanzeige per wire:poll.2s mit Status-Icons pro Domain
    (pending → running → done/error/skip)
- saveDomains() ruft apply-domains jetzt ohne certbot auf (--ssl-auto 0) —
  Domains speichern und SSL einrichten sind damit getrennte Aktionen
- loadSslStatus() liest Certbot-Zertifikat-Info direkt aus openssl
- spin-Keyframe für Spinner-Animation in app.css

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 08:04:58 +02:00
boban c4a2f33293 Fix: Update-Check via mailwolt-fetch-tags + Fehlerdetails in Settings-Toast
- Neu: scripts/mailwolt-fetch-tags ruft git ls-remote als App-User auf (hat Credentials),
  schreibt neuesten Tag nach /var/lib/mailwolt/version_remote
- CheckUpdates.php nutzt jetzt sudo mailwolt-fetch-tags statt direktem git fetch als www-data
  (www-data hat keine Git-Credentials für private Repos)
- SettingsForm.php zeigt tatsächliche Fehlerzeilen ([!], error, failed) im Toast statt
  generischer "fehlgeschlagen"-Meldung
- installer.sh + update.sh installieren mailwolt-fetch-tags nach /usr/local/sbin/
- update.sh trägt mailwolt-fetch-tags automatisch in sudoers nach (Upgrade-Pfad)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 07:46:18 +02:00
boban 8a654bef89 Fix: Wizard Step 5 — korrekte Fehlermeldungen bei SSL-Fehler
installer.sh / mailwolt-apply-domains:
- State-Dateien jetzt korrekt pro Domain: "done" nur wenn LE-Cert existiert,
  sonst "error" — verhindert grüne Checkmarks bei fehlgeschlagenem certbot
- mail-Domain: "skip" statt fälschlich "done" (certbot läuft nicht für MX im Wizard)
- sleep 6 nur wenn Cert ausgestellt wurde (nginx-HTTPS-Switch nötig)

WizardDomains.php:
- Bei frühem DNS-Abbruch: verbleibende "running"-Domains auf "error" setzen
  statt ewig als "Wird registriert…" hängen zu bleiben

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 18:04:30 +02:00
boban 8ff1aeac2a Fix: Wizard Step 5 — per-Domain-Fortschritt, Cert-Fallback, ssl_configured
- mailwolt-apply-domains schreibt jetzt pro Domain running/done/error/nodns
  in die State-Dateien während certbot läuft (statt alles auf einmal am Ende)
- get_cert_dir() erstellt fullchain.pem/privkey.pem Symlinks auf cert.pem/key.pem
  wenn kein LE-Zertifikat vorhanden — verhindert nginx-t-Fehler und kaputten Redirect
- WizardDomains.php: ssl_configured wird jetzt anhand /etc/letsencrypt/live/ geprüft
  statt per Shell-Output (der wegen exec>>LOG immer leer war)
- Shell-Script schreibt done-Datei selbst; PHP nur noch als Absturz-Fallback

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 12:54:11 +02:00
boban 894f753b81 Fix: Wizard SSL-Flow end-to-end sauber gelöst
- pollSetup() macht keinen auto-redirect mehr (port 443 wäre noch nicht offen)
- "Zum Login" ist jetzt ein plain <a href="/login"> ohne Livewire-POST
  → nginx leitet /login nach SSL-Switch automatisch auf HTTPS weiter
- mailwolt-apply-domains schreibt done=1/0 (je nach Cert-Status) VOR nginx-Switch
  + sleep 6s damit Polling noch 3x done lesen kann bevor port 443 öffnet
- done=1 nur wenn mindestens ein LE-Cert erfolgreich ausgestellt wurde

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:11:50 +02:00
boban 9d3cbd88b6 Fix: Race Condition SSL-Wizard + fastcgi_param HTTPS on
- mailwolt-apply-domains schreibt State-Dateien (done=1) BEVOR nginx auf HTTPS
  switcht, dann sleep 6s → Browser kann noch über HTTP redirecten
- WizardDomains.php überschreibt done nicht wenn Shell-Script es bereits gesetzt hat
- fastcgi_param HTTPS on in HTTPS-Blocks ergänzt (ohne dies liefert Laravel 404
  weil Request-Schema falsch erkannt wird)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 16:06:25 +02:00
boban 1547302297 Fix: Wizard leitet nach SSL-Setup automatisch auf HTTPS weiter
- SESSION_SECURE_COOKIE wird nicht mehr automatisch gesetzt (verursachte 419 während HTTP-Poll)
- pollSetup() leitet Browser sofort auf https://domain/setup weiter sobald SSL fertig
- verhindert dass Livewire-Polling über HTTP läuft während nginx schon auf HTTPS umgestellt hat

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 15:54:08 +02:00
boban 73bda08244 Fix: Livewire NoModificationAllowedError im Setup-Wizard Step 5
wire:poll Div war bedingt gerendert – beim Entfernen aus dem DOM
versuchte Livewire noch es zu patchen → outerHTML Fehler.
Div bleibt jetzt immer im DOM, pollSetup() kehrt früh zurück wenn fertig.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 14:55:18 +02:00
boban 32f43020d3 Fix: HTTPS-Redirect im Wizard entfernt + nginx HTTP-Block korrigiert
HTTPS→HTTP Redirect war ein Workaround für SESSION_SECURE_COOKIE,
der jetzt durch den Installer-Fix (false initial) nicht mehr nötig ist.
fastcgi_param HTTPS on gehört nur in den 443-Block, nicht in den 80-Block.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 14:43:26 +02:00
boban 4fd37985b3 Fix: Passwort-Mindestlänge im Wizard auf 6 Zeichen gesenkt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 14:30:32 +02:00
boban 7d30faa7d7 Fix: SESSION_SECURE_COOKIE verhindert HTTP-Setup (419-Fehler)
Installer setzt SESSION_SECURE_COOKIE=false initial – damit Setup-Wizard
über http://ip erreichbar ist. WizardDomains setzt es auf true nach
erfolgreichem SSL. mount()-Redirect ohne exit (sauberer Return).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 14:29:13 +02:00
boban 3869f6e67f Fix: Login-Redirect nur bei erfolgreichem SSL auf Domain umleiten
ssl_configured=1 → https://{ui_domain}/login
ssl_configured=0 → /login (bleibt auf aktueller IP/Host)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 14:08:01 +02:00
boban a322aa17ac Fix: goToLogin leitet auf konfigurierte UI-Domain weiter
route('login') nutzt die gecachte Config (alte IP/URL). Stattdessen
direkt auf https://{ui_domain}/login umleiten, da APP_URL erst nach
dem Prozess-Neustart greift.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 14:06:54 +02:00
boban 0b415c6862 Fix: Setup-Wizard bei HTTPS auf HTTP umleiten
Vor SSL-Zertifikaten schlägt Livewires AJAX über HTTPS fehl.
mount() leitet automatisch auf http:// um damit der Wizard funktioniert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 14:04:50 +02:00
boban 31f486c753 Fix: SSL-Erstellung nicht von APP_ENV abhängig machen
isProduction()-Check entfernt — SSL wird jetzt allein durch skipSsl gesteuert,
da APP_ENV=local sonst SSL-Zertifikate komplett verhindert.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 14:03:24 +02:00