Releases: malziland/Seafile-Updraft-Backup-Uploader
Release list
v1.0.11 — Queue-Timeout zählt nur noch aktive Laufzeit (BUG-03)
Behebt einen Produktionsabbruch vom 17.07.: Eine nach stillem Worker-Absturz korrekt wiederaufgenommene Upload-Queue wurde zwei Minuten später vom Queue-Timeout abgebrochen.
Behoben
- Queue-Timeout zählt nur noch aktive Laufzeit (BUG-03). Der Timeout-Check verglich stur
time() - startedmit dem Laufzeit-Budget (Floor 12 h) und zählte damit auch tote Standzeit mit: Starb der Worker still (SIGKILL/OOM) und lag die Queue auf einer Zero-Traffic-Site stundenlang schlafend da, brach der Timeout die vom Admin-Fallback korrekt wiederaufgenommene Queue sofort ab — im Produktionsfall bei 34 OK / 0 Fehler und nur noch ~40 min Restarbeit. Die Crash-Erkennung und der Pause/Weiter-Knopf schreiben Standzeiten jetzt alsidle_creditgut; der neue zentrale Checkqueue_timed_out()zieht die Gutschrift ab. Für echte aktive Laufzeit bleibt das Budget als Sicherheitsnetz gegen Endlosschleifen unverändert bestehen. Gilt für Upload- und Restore-Queues.
Abgesichert durch QueueTimeoutTest (inkl. 1:1-Nachstellung des Produktionslogs) sowie neue Fälle in CrashDetectionGateTest und PauseResumeTest — 150 Tests / 414 Assertions, alle grün.
Vollständige Historie: CHANGELOG.md
v1.0.10 — Reliability: Queue-Lock mit Ownership-Token
Reliability-Release. Behebt das letzte offene Restrisiko aus dem internen Audit. Keine Migration nötig — Plugin-Zip über WordPress-Admin → Plugins → Hochladen ersetzen.
Behoben
- Queue-Lock mit Ownership-Token (OPS-01). Bisher konnte in einem sehr engen Zeitfenster ein abgestürzter Verarbeitungs-Prozess beim Aufräumen versehentlich das Lock eines bereits nachgerückten Prozesses freigeben — mit dem Risiko, dass zwei Prozesse kurzzeitig parallel dieselbe Queue bearbeiten. Ein Prozess gibt jetzt nur noch das Lock frei, das er selbst hält; der bewusste Abbruch einer laufenden Queue durch ein neues Backup nutzt einen separaten Force-Pfad. Abgesichert durch 8 neue Unit-Tests.
140 Tests / 389 Assertions, alle grün.
v1.0.9 — Hotfix: Restore-Korruptionsschutz vollständig
Wichtiger Hotfix zu 1.0.8. Ein Nach-Release-Audit deckte auf, dass der Korruptionsschutz für Wiederherstellungen aus 1.0.8 unvollständig war. Wer 1.0.8 installiert hat, sollte auf 1.0.9 aktualisieren. Keine Migration nötig — Plugin-Zip über WordPress-Admin → Plugins → Hochladen ersetzen.
Behoben
- BUG-01 vollständig abgesichert. Der Restore-Code enthielt zwei identische Stellen zur Auswertung von Teil-Downloads; in 1.0.8 wurde nur die Hauptstelle abgesichert, die zweite (im Sofort-Wiederholungs-Zweig) nicht. Dadurch konnte die in 1.0.8 behobene Beschädigung bei Reverse-Proxys, die Range-Anfragen ignorieren (HTTP 200 statt 206), über den Wiederholungs-Pfad weiterhin auftreten — bei Backups ohne gespeicherte Prüfsumme sogar unbemerkt. Beide Stellen nutzen jetzt dieselbe abgesicherte Auswertung.
Intern
- Drei Kommentar-Präzisierungen aus dem Nach-Audit (IPv6-Maskierung, Nonce-Refresh nach langem Tab-Schlaf, dokumentiertes Lock-Restrisiko). Kein Verhaltenseinfluss. 132 Tests / 374 Assertions, alle grün.
v1.0.8 — Sicherheit, Restore-Integrität, Reliability
Sicherheits- und Stabilitäts-Release. Behebt die sieben Findings des internen Kurzaudits. Empfohlenes Update. Keine Migration nötig — Plugin-Zip herunterladen und über WordPress-Admin → Plugins → Hochladen die aktuelle Version ersetzen.
Sicherheit
- DOM-XSS über Seafile-gelieferte Namen behoben. Bibliotheks-/Ordnernamen und Seafile-Fehlertexte wurden im Admin-Bereich per
innerHTMLeingesetzt — ein bösartiger oder mehrbenutzerfähiger Seafile-Server konnte darüber Schadcode in die WordPress-Adminoberfläche einschleusen. Auswahllisten und Ergebnis-Boxen werden jetzt übertextContentaufgebaut. - Fehlende Nonce-Prüfung am Nonce-Refresh-Endpunkt geschlossen.
Behoben
- Beschädigte Wiederherstellung bei Range-ignorierenden Reverse-Proxys. Antwortete ein Proxy auf einen fortgesetzten Teil-Download mit der ganzen Datei (HTTP 200 statt 206), wurde diese an die bereits geschriebenen Bytes angehängt — eine still beschädigte Wiederherstellung. Solche Antworten werden oberhalb von Offset 0 jetzt verworfen und der Block erneut versucht.
- Verlust von „Pause"/„Abbrechen" bei zeitgleichem Fehler (Worker-Absturz, Auth-Fehler, Queue-Timeout).
- Hängende Upload-Queue nach hartem PHP-Prozess-Tod — der Upload-Pfad hat jetzt ein Sicherheitsnetz, das das Queue-Lock sofort freigibt und die Verarbeitung wieder anstößt.
Datenschutz
- IPv6-Adressen im anonymisierten Protokoll-Export maskiert (bisher nur IPv4), ohne Log-Zeitstempel zu zerstören.
Intern
- Dokumentation auf den tatsächlichen Code-Stand korrigiert, Entwickler-Werkzeuge aktualisiert (keine Auswirkung auf das ausgelieferte Plugin). 132 Tests / 374 Assertions, alle grün.
v1.0.7 — Worker-Crash-Notbremse gegen 17h-Resume-Loops
Fix: Worker-Crash-Notbremse
Verhindert, dass ein einzelner Chunk, der den PHP-Prozess wiederholt killt, die gesamte Upload-Queue stundenlang blockiert.
Konkret beobachtet in Produktion: eine 172 MB große uploads.zip blieb wiederholt bei genau 120 MB stehen (PHP-Prozess wurde vom Hoster mitten im Chunk-PUT abgeschossen), Resume nahm korrekt bei 120 MB wieder auf — und starb dort sofort wieder. 17,8 Stunden verschwendet, bis der Queue-Gesamttimeout griff. Die nachfolgende wpcore.zip wurde nie hochgeladen.
Neue dreistufige Eskalation
- Erster Crash → Retry mit exponentiellem Backoff (bestand schon).
- Zweiter Crash am selben Byte → Chunk-Größe für diese eine Datei wird automatisch halbiert (per-File-Override, Untergrenze 4 MiB). Andere Dateien der Queue bleiben unberührt.
- Chunk schon am Floor und immer noch derselbe Crash, oder >5 Crash-Wiederaufnahmen pro Datei → Datei als Fehler markiert, die Queue läuft mit den nächsten Dateien weiter. Besser eine fehlgeschlagene Datei als ein 17-h-Stillstand der gesamten Backup-Übertragung.
Diagnose im Aktivitätsprotokoll
Zwei neue Log-Einträge machen die Eskalation sichtbar:
WARNUNG: Worker still abgestürzt vor X min an gleicher Stelle — Chunk-Größe auf Y MB reduziert, Wiederaufnahme bei …FEHLER: Datei nach wiederholten Worker-Abstürzen übersprungen: … — Queue läuft mit den nächsten Dateien weiter
Tests
Drei neue Unit-Tests in CrashDetectionGateTest (Retry-Cap-Skip, Same-Offset-Chunk-Halbierung, Floor-erreicht-Skip). 123 Tests / 343 Assertions grün, PHPStan ohne Befund.
Installation
Zip herunterladen und über WP-Admin → Plugins → Neu hinzufügen → Plugin hochladen installieren oder aktualisieren. Keine Migration nötig.
Vollständige Änderungsliste siehe CHANGELOG.md.
v1.0.6 — Einzeldatei-Download entfernen (UI-Aufräumen)
Was sich ändert
Der Einzeldatei-Download-Button im „Dateien anzeigen"-Panel ist weg. Das Panel zeigt jetzt nur noch Dateiname und Größe — eine reine Inhaltsliste ohne Aktionen.
Warum
Der Button hieß „Download", triggerte aber keinen Browser-Download:
- Serverseitige Kopie statt Browser-Download.
SBU_Plugin::ajax_download()lud die Datei von Seafile in den lokalenwp-content/updraft/-Ordner. Der Browser zeigte keinen Download-Balken, weil nichts zum Browser geschickt wurde. - Erfolgsmeldung außerhalb des Sichtfelds. Die Meldung „In UpdraftPlus auf 'Lokalen Ordner neu scannen' klicken" landete im gemeinsam genutzten
#sr-Statusfeld zwei Panels höher — bei gescrollter Seite schlicht nicht sichtbar. Das erzeugte den „nichts passiert"-Eindruck. - Confirm-Dialog ohne Erklärung.
confirm(f)fragte nur den rohen Dateinamen (z. B.backup_2026-04-17-1630_INTERIORISTA_1d2b1dcea52d-db.gz) ab, ohne zu sagen, was OK auslöst.
Warum entfernt statt repariert
- Kein realistischer Use-Case. UpdraftPlus-Chunks (
uploads7.zip,uploads14.zip, …) sind semantisch undurchsichtig — eine einzelne Datei aus dem Set ist ohne Kontext nicht restore-fähig. - „Wiederherstellen" deckt den Restore-Fall ab. Der bestehende Restore-Pfad erkennt „Teilweise lokal"-Sets und zieht genau die fehlenden Dateien nach — gezielter Re-Download ist also schon drin.
- Seafile-Weboberfläche deckt den Inspektions-Fall ab. Wer eine einzelne
.gzaußerhalb von WordPress untersuchen will, lädt sie direkt aus der Seafile-Weboberfläche.
Aufgeräumt (tote Code-Pfade)
SBU_Plugin::ajax_download()— Handler vollständig entfernt.'download'aus der AJAX-Hook-Registrierung —wp_ajax_sbu_downloadist weg.SBU_Seafile_API::download_file()— nur vonajax_download()gerufen, jetzt tot, raus.SBU_Seafile_API::DEFAULT_DOWNLOAD_CHUNK— nur vondownload_file()referenziert, raus.window.sDl+'download-file'-Event-Delegation-Eintrag inadmin.js— raus.<button data-sbu-action=\"download-file\">inSBU_Plugin::ajax_list()— raus.
Der im Restore-Flow aktive Download-Pfad (download_whole_file_stream + download_chunks_parallel) bleibt unverändert.
Migration
Keine. Einstellungen, Queue-State und Protokoll-Einträge bleiben intakt. Upload über Plugins → Hochladen in WP-Admin.
Tests
121 Tests / 333 Assertions — unverändert. PHPCS, PHPStan Level 5 und PHPUnit 11 grün auf PHP 8.2 / 8.3 / 8.4.
v1.0.5 — Breaking: PHP 8.2 + PHPUnit 11 + erweiterte Testsuite
Breaking
- PHP-Mindestanforderung 7.4 → 8.2. Plugin-Header,
composer.jsonundreadme.txtsind jetzt konsistent auf 8.2. WordPress blockiert die Aktivierung auf älteren PHP-Versionen mit eigenem Hinweis. Supporte PHP-Matrix: 8.2 / 8.3 / 8.4 (alle drei in CI getestet). Vor dem Update die PHP-Version des Hosts prüfen.
Geändert
- PHPUnit 9.6 → 11.5. Alle 12 bestehenden Test-Dateien von
@covers-Docblocks auf PHP-8-Attribute (#[CoversClass]/#[CoversMethod]) migriert — null Deprecations mehr. - CI-Matrix auf PHP 8.2 / 8.3 / 8.4 umgestellt.
Hinzugefügt
tests/unit/SeafileApiTest.php— 17 HTTP-gemockte Tests fürSBU_Seafile_API(Token-Cache, Library-Resolve, Upload-/Download-Link, Directory-Ops).tests/unit/LogSanitizerTest.php— 12 Tests für den anonymisierten Log-Export (Host-, UUID-, Ordner-, E-Mail-, IP-, Nonce-Maskierung) plus End-zu-End-Leak-Check.- Neue Screenshots für
readme.txtundREADME.md: Einstellungsseite (Backup-Browser + Aktivitätsprotokoll) und Dashboard-Widget mit Demo-Daten.
Dokumentation
README.md,ARCHITECTURE.md,CONTRIBUTING.mdauf den aktuellen Code-Stand gezogen: Modul-Boundaries-Tabelle, Test-Surface-Tabelle, reproduzierbarer Release-Workflow (rsync + zip), explizite Quality-Gate-Befehle.
Tests
121 Tests / 333 Assertions (vorher 92 / 263). PHPCS (WordPress-Standard, Plugin-Source), PHPStan Level 5 und PHPUnit 11 grün auf PHP 8.2 / 8.3 / 8.4.
Upgrade-Hinweis
Vor dem Update die PHP-Version des Hosts prüfen (mindestens 8.2). Danach keine manuelle Migration nötig — Upload über Plugins → Hochladen in WP-Admin.
v1.0.4 — ARCH-001 abgeschlossen
ARCH-001 ist mit diesem Release komplett durch: die beiden letzten Monolith-Fragmente sind raus aus der God-Class. Reines Refactoring, Verhalten 1:1, 92 PHPUnit-Tests / 263 Assertions grün.
Refaktoriert
- Schritt 4 —
SBU_Admin_Ajaxals Trait — alle 24 Ajax-Handler (Verbindungstest, Upload-/Restore-Queue-Kontrolle, Backup-Liste, Download-Stream, Log-Export, Settings-Autosave, Cron-Endpoints) liegen jetzt inincludes/trait-sbu-admin-ajax.php. Trait-Komposition zur Compile-Zeit hält die Zugriffe auf private Plugin-Helfer (verify_ajax_request,get_picker_credentials,format_progress,sanitize_path_segment…) intakt — keine Visibility-Promotion, keine fragile Plugin-Referenz. - Schritt 5 —
SBU_Upload_Flow+SBU_Restore_Flowals Traits — der komplette Upload-Lebenszyklus (on_backup_complete,create_upload_queue,process_queue_tick,upload_one_chunk,finish_queue,verify_backup,persist_backup_hashes,enforce_retention,cleanup_updraft_history,find_backup_files,extract_backup_nonce) wohnt inincludes/trait-sbu-upload-flow.php. Der Restore-Lebenszyklus (verify_restored_file,process_restore_tick) inincludes/trait-sbu-restore-flow.php. Gemeinsame Helfer (safe_queue_update,detect_worker_crash_and_defer,maybe_notify_stall,get_adaptive_limits,tick_budget_exhausted,is_aborted,log_failed_files,get_updraft_dir,get_memory_limit) bleiben inSBU_Plugin, weil beide Flows sie brauchen. SBU_Pluginjetzt ~1100 Zeilen — von ursprünglich 4201 Zeilen (−74 %). Die Klasse ist wieder als Koordinationslayer lesbar: Settings, Admin-UI, Cron-Auth, Tick-Sizing, Queue-Lifecycle-Helfer, Trait-Komposition.
Geändert
SBU_Queue_Engine::tick_is_gated()als@phpstan-impuremarkiert — die Methode liestSBU_QUEUEbei jedem Aufruf frisch viawp_cache_delete. PHPStan hielt wiederholte Aufrufe nach der Trait-Komposition für redundant (if.alwaysTrueinajax_cron_ping). Der Analyzer kannte die Mutations-Semantik nicht; die Annotation dokumentiert sie.
Tests & Qualität
- 92 PHPUnit-Tests / 263 Assertions — alle grün.
- PHPCS (WordPress-Standard, Plugin-Source) sauber.
- PHPStan Level 5 sauber.
- Keine Test-Anpassungen nötig — Traits komponieren zur Compile-Zeit in
SBU_Plugin, die bestehendenSBU_Plugin::*-Referenzen in den Tests funktionieren unverändert.
Upgrade Notice
Reines Refactoring, keine Migration nötig. Download-Asset: seafile-updraft-backup-uploader-1.0.4.zip.
v1.0.3 — Cron-Key-Header, Brute-Force-Schutz, ARCH-001 Schritte 1-3
Zweiter Audit-Durchgang: UI-Feinschliff, Härtung des internen Cron-Pfads, drei Services aus der God-Class rausgezogen.
Sicherheit
- Cron-Key im Header statt im POST-Body — der interne Loopback-Spawn sendet den Schlüssel jetzt über den
X-SBU-Cron-Key-Header. Er taucht damit nicht mehr in Debug-/Error-Tracker-Dumps auf, die Request-Bodies mitloggen. Rückwärtskompatibel: der Empfänger prüft weiterhin Header, Query-Param und Body in dieser Reihenfolge. - Brute-Force-Signal im Aktivitätsprotokoll — fünf ungültige Versuche innerhalb einer Stunde lösen einmalig eine
WARNUNG-Zeile aus (1-Stunden-Transient als Zähler). Vorher: stumme 403s.
UI
- Status-Pillen zentriert —
Lokal vollständig/Teilweise lokal/Nur remoteund der Verify-Status sitzen jetzt auf einer sauberen Baseline statt treppenartig versetzt. Fix im Flex-Layout:align-items:centerstattbaseline. - 24 weitere Inline-
onclickentfernt — die Buttons in der Backup-Liste nutzen jetzt ebenfallsdata-sbu-action. Kombiniert mit 1.0.2 ist das Plugin damit vollständig inline-JavaScript-frei.
Betrieb
- Zero-Traffic-Backstop für das Log-Pruning — zusätzlich zum täglichen WP-Cron räumt die Retention jetzt auch beim ersten
admin_initpro Admin-Zugriff auf. Idle-Sites bleiben im Retention-Fenster.
Refaktoriert (ARCH-001 Schritte 1–3)
SBU_Activity_Logals eigene Klasse (Log-Schreiben, Retention, Cron, Render). 77 Aufrufstellen umgestellt, Verhalten identisch.SBU_Mail_Notifierals eigene Klasse (Admin-Mails Erfolg/Fehler/Stillstand).SBU_Queue_Engineals eigene Klasse (atomares Lock, Lock-TTL, Gate-Check, Loopback-Spawn, WP-Cron-Scheduling).
Konstruktor-DI via Callables, damit die Services nicht auf SBU_Plugin koppeln.
Schritte 4 + 5 verschoben auf v1.0.4 — die Ajax-Controller-Extraktion (24 Handler) und die Upload-/Restore-Flow-Trennung brauchen einen isolierten Release, damit Regressions-Risiken in produktiven Backup-Pfaden gezielt reviewbar bleiben.
Tests
92 PHPUnit-Tests / 263 Assertions — alle grün. PHPCS (WordPress-Standard) und PHPStan (Level 5) sauber.
Installation: seafile-updraft-backup-uploader-1.0.3.zip herunterladen → WordPress → Plugins → Plugin hochladen.
v1.0.2 — Audit-Umsetzung (Datenschutz, Wartbarkeit, CI)
Audit-Umsetzung: Datenschutz, Wartbarkeit, CI-Schärfe.
Hinzugefügt
- Zeit-basierte Aufbewahrung für das Aktivitätsprotokoll (Default 30 Tage, konfigurierbar 7–365 Tage oder 0 = deaktiviert). Alte Einträge werden einmal täglich per Cron und opportunistisch beim Schreiben gelöscht. Das bisherige Zeilen-Limit (500 Zeilen) bleibt als zusätzliche Obergrenze erhalten.
- Warn-Header im Log-Export (unmaskierte Variante) weist jetzt unübersehbar darauf hin, dass der Export identifizierende Daten (Host, Bibliothek, Pfade, E-Mail) enthält — für Support-Weitergabe wird „Anonymisiert exportieren" empfohlen.
- Neue Einstellung „Aktivitätsprotokoll aufbewahren" auf der Plugin-Seite mit Laien-Erklärung (Standard-Empfehlung 30 Tage, Hinweis auf DSGVO-Datensparsamkeit).
- 5 neue Unit-Tests für die Retention-Logik.
Geändert
- Inline-
onclick-Handler aus dem Admin-Template entfernt — 9 Buttons nutzen jetztdata-sbu-action-Attribute, ein zentraler Event-Delegate inadmin.jsroutet auf die Funktionen. Erleichtert künftige Wartung und strengere Content-Security-Policies. - CI-Pipeline scharf gestellt — PHPCS und PHPStan brechen den Build jetzt bei Fehlern ab (vorher mit
|| truemaskiert). PHPStan läuft mit--memory-limit=2G. - Ein Code-Review-Durchlauf mit echten Bugfixes:
wp_unslash()vorsanitize_path_segment()in Ajax-Download/Delete, gecachtecount()-Aufrufe,translators-Kommentare für komplexe i18n-Strings, Parameter-Rename.
Sicherheit
- Retention-Clamp gegen Panik-Eingaben — Werte zwischen 1 und 6 Tagen werden automatisch auf 7 angehoben, damit ein Fehlklick im Admin das Protokoll nicht in einem Tick vollständig leert. 0 bleibt als explizite Deaktivierung.
- Datenminimierung im Default-Fall — Aktivitätsprotokoll-Einträge älter als 30 Tage werden ohne weitere Konfiguration entfernt. Unterstützt die DSGVO-Forderung nach Datensparsamkeit.
Tests
92 PHPUnit-Tests / 263 Assertions, alle grün. PHPCS (WordPress-Standard) und PHPStan (Level 5) sauber.
Upgrade
Keine Migration nötig. Aktivitätsprotokoll wird automatisch nach 30 Tagen aufgeräumt (konfigurierbar).