Skip to content

Releases: malziland/Seafile-Updraft-Backup-Uploader

v1.0.11 — Queue-Timeout zählt nur noch aktive Laufzeit (BUG-03)

Choose a tag to compare

@malziland malziland released this 17 Jul 12:50

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() - started mit 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 als idle_credit gut; der neue zentrale Check queue_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

Choose a tag to compare

@malziland malziland released this 16 Jul 18:14

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

Choose a tag to compare

@malziland malziland released this 16 Jul 17:52

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

Choose a tag to compare

@malziland malziland released this 16 Jul 17:39

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 innerHTML eingesetzt — ein bösartiger oder mehrbenutzerfähiger Seafile-Server konnte darüber Schadcode in die WordPress-Adminoberfläche einschleusen. Auswahllisten und Ergebnis-Boxen werden jetzt über textContent aufgebaut.
  • 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

Choose a tag to compare

@malziland malziland released this 25 May 10:07

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

  1. Erster Crash → Retry mit exponentiellem Backoff (bestand schon).
  2. 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.
  3. 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)

Choose a tag to compare

@malziland malziland released this 19 Apr 12:00

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 lokalen wp-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 .gz auß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_download ist weg.
  • SBU_Seafile_API::download_file() — nur von ajax_download() gerufen, jetzt tot, raus.
  • SBU_Seafile_API::DEFAULT_DOWNLOAD_CHUNK — nur von download_file() referenziert, raus.
  • window.sDl + 'download-file'-Event-Delegation-Eintrag in admin.js — raus.
  • <button data-sbu-action=\"download-file\"> in SBU_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

Choose a tag to compare

@malziland malziland released this 19 Apr 11:49

Breaking

  • PHP-Mindestanforderung 7.4 → 8.2. Plugin-Header, composer.json und readme.txt sind 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ür SBU_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.txt und README.md: Einstellungsseite (Backup-Browser + Aktivitätsprotokoll) und Dashboard-Widget mit Demo-Daten.

Dokumentation

  • README.md, ARCHITECTURE.md, CONTRIBUTING.md auf 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

Choose a tag to compare

@malziland malziland released this 19 Apr 11:12

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_Ajax als Trait — alle 24 Ajax-Handler (Verbindungstest, Upload-/Restore-Queue-Kontrolle, Backup-Liste, Download-Stream, Log-Export, Settings-Autosave, Cron-Endpoints) liegen jetzt in includes/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_Flow als 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 in includes/trait-sbu-upload-flow.php. Der Restore-Lebenszyklus (verify_restored_file, process_restore_tick) in includes/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 in SBU_Plugin, weil beide Flows sie brauchen.
  • SBU_Plugin jetzt ~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-impure markiert — die Methode liest SBU_QUEUE bei jedem Aufruf frisch via wp_cache_delete. PHPStan hielt wiederholte Aufrufe nach der Trait-Komposition für redundant (if.alwaysTrue in ajax_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 bestehenden SBU_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

Choose a tag to compare

@malziland malziland released this 19 Apr 10:39

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 zentriertLokal vollständig / Teilweise lokal / Nur remote und der Verify-Status sitzen jetzt auf einer sauberen Baseline statt treppenartig versetzt. Fix im Flex-Layout: align-items:center statt baseline.
  • 24 weitere Inline-onclick entfernt — die Buttons in der Backup-Liste nutzen jetzt ebenfalls data-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_init pro Admin-Zugriff auf. Idle-Sites bleiben im Retention-Fenster.

Refaktoriert (ARCH-001 Schritte 1–3)

  • SBU_Activity_Log als eigene Klasse (Log-Schreiben, Retention, Cron, Render). 77 Aufrufstellen umgestellt, Verhalten identisch.
  • SBU_Mail_Notifier als eigene Klasse (Admin-Mails Erfolg/Fehler/Stillstand).
  • SBU_Queue_Engine als 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)

Choose a tag to compare

@malziland malziland released this 19 Apr 09:45

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 jetzt data-sbu-action-Attribute, ein zentraler Event-Delegate in admin.js routet 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 || true maskiert). PHPStan läuft mit --memory-limit=2G.
  • Ein Code-Review-Durchlauf mit echten Bugfixes: wp_unslash() vor sanitize_path_segment() in Ajax-Download/Delete, gecachte count()-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).