diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..6a842c5 --- /dev/null +++ b/TODO.md @@ -0,0 +1,217 @@ +# U-Navigator – TODO + +Stand: 2026-07-14 + +Ziel dieser Liste ist eine sichere, testbare und veröffentlichungsfähige Version des Plugins. Schreibzugriff sollte erst empfohlen werden, wenn alle Punkte unter P0 abgeschlossen und auf einer echten Unraid-Installation geprüft sind. + +## P0 – Sicherheitsblocker + +### Geschützte Root-Pfade + +- [ ] Eine zentrale Funktion `unav_assert_mutable_path()` einführen. +- [ ] Löschen eines konfigurierten Root-Pfads verbieten. +- [ ] Verschieben und Umbenennen eines konfigurierten Root-Pfads verbieten. +- [ ] Rekursive Rechte- oder Besitzeränderungen direkt am Root-Pfad verbieten. +- [ ] Quelle und Ziel auch im Worker unmittelbar vor der Operation erneut prüfen. +- [ ] API-Tests für Delete, Move und Permissions auf `/mnt/user` beziehungsweise einem Test-Root ergänzen. + +Abnahmekriterium: Kein mutierender API-Aufruf kann den erlaubten Root selbst verändern oder entfernen. + +### Sichere Symlink-Behandlung + +- [ ] Eingabepfad und kanonischen Sicherheitspfad getrennt speichern. +- [ ] Für Dateioperationen `lstat()` statt ausschließlich `realpath()` verwenden. +- [ ] Beim Löschen eines Symlinks ausschließlich den Link entfernen, niemals dessen Ziel. +- [ ] Copy und Move von Symlinks entweder kontrolliert implementieren oder ausdrücklich ablehnen. +- [ ] Symlinks auf Ziele außerhalb erlaubter Roots für Listing, Vorschau und Download weiterhin blockieren. +- [ ] Rekursive Operationen dürfen Symlinks nicht verfolgen. +- [ ] Tests für interne Symlinks, externe Symlinks, kaputte Symlinks und Symlink-Schleifen ergänzen. + +Abnahmekriterium: Eine Aktion auf einem Symlink wirkt niemals unerwartet auf dessen Ziel. + +### Upload-Pfade härten + +- [ ] Relative Pfade vollständig validieren; `..` nicht still entfernen, sondern als Fehler ablehnen. +- [ ] Absolute Pfade, Nullbytes und leere Pfadsegmente ablehnen. +- [ ] Jeden Parent-Pfad prüfen, bevor ein Verzeichnis angelegt wird. +- [ ] Beim Anlegen von Upload-Ordnern keine vorhandenen Symlinks durchlaufen. +- [ ] Zielpfad unmittelbar vor Schreiben beziehungsweise Rename erneut validieren. +- [ ] Temporäre Upload-Dateien in einem privaten Verzeichnis ablegen und zufällige IDs verwenden. +- [ ] Abgebrochene und veraltete Upload-Fragmente automatisch entfernen. +- [ ] Tests für Symlink-Parents und konkurrierende Pfadänderungen ergänzen. + +Abnahmekriterium: Ein Upload kann außerhalb der erlaubten Roots weder Dateien noch Verzeichnisse erzeugen. + +### CSRF und Request-Schutz + +- [ ] Auf einer aktuellen Unraid-7.x-Installation prüfen, ob die WebGUI-Schicht Plugin-PHP-Endpunkte automatisch gegen CSRF schützt. +- [ ] Direkte POST-Requests ohne, mit falschem und mit gültigem `csrf_token` testen. +- [ ] Falls nötig, CSRF-Prüfung zentral in `common.php` implementieren. +- [ ] Mutierende Endpunkte ausschließlich per POST erlauben. +- [ ] Für nicht erlaubte Methoden `405 Method Not Allowed` und einen `Allow`-Header liefern. +- [ ] Für JSON- und Formular-Requests dieselben Schutzregeln anwenden. +- [ ] Authentifizierungsverhalten bei direktem Aufruf aller API-Endpunkte prüfen und dokumentieren. + +Abnahmekriterium: Kein mutierender Aufruf funktioniert ohne gültige Unraid-Sitzung und gültigen CSRF-Schutz. + +### Ressourcenlimits + +- [ ] Maximale Upload-Dateigröße konfigurierbar machen. +- [ ] Maximale Gesamtgröße und Dateianzahl pro Upload begrenzen. +- [ ] Raw-Uploads streamen, statt den gesamten Request in den PHP-Speicher zu laden. +- [ ] Maximale Dateianzahl und Gesamtgröße für ZIP-Downloads festlegen. +- [ ] Vor ZIP-Erstellung freien temporären Speicher prüfen. +- [ ] ZIP-Erstellung als Hintergrundjob ausführen. +- [ ] Laufzeit- und Rekursionstiefenlimits für Size, Copy, Delete und Permissions einführen. +- [ ] Große Verzeichnisse im Listing paginieren oder begrenzen. + +Abnahmekriterium: Einzelne Requests können weder PHP-Speicher noch temporären Speicher unkontrolliert erschöpfen. + +## P1 – Datenintegrität und Jobs + +### Robuste Copy-/Move-Operationen + +- [ ] Kopien zunächst unter einem temporären Zielnamen erstellen. +- [ ] Ziel erst nach erfolgreicher vollständiger Kopie atomar sichtbar machen. +- [ ] Unvollständige Ziele bei Fehlern zuverlässig entfernen. +- [ ] Quelle bei einem Cross-Filesystem-Move erst nach verifizierter Kopie löschen. +- [ ] Dateigröße und optional Prüfsumme vor dem Löschen der Quelle vergleichen. +- [ ] Rechte, Owner, Gruppe und Zeitstempel erhalten. +- [ ] Verhalten für Sparse Files, Hardlinks und Special Files definieren. +- [ ] Zielkonflikte auch unmittelbar vor dem finalen Rename prüfen. +- [ ] Tests für Fehler mitten in einer Verzeichniskopie ergänzen. + +### Job-System + +- [ ] Job-Verzeichnis mit `0700` statt `0777` erstellen. +- [ ] Jobdateien atomar über temporäre Datei plus Rename schreiben. +- [ ] Beim Lesen passende Locks beziehungsweise atomare Snapshots verwenden. +- [ ] Kryptografisch zufällige Job-IDs verwenden. +- [ ] Prüfen, ob der Worker wirklich gestartet ist; nicht nur den Shell-Exitcode auswerten. +- [ ] Hängende Jobs nach Timeout als fehlgeschlagen markieren. +- [ ] Abbruch-Endpunkt für laufende Jobs implementieren. +- [ ] Abbruchstatus in rekursiven Operationen regelmäßig prüfen. +- [ ] Abbruchschaltfläche im Transfer-Panel ergänzen. +- [ ] Alte abgeschlossene Jobs automatisch löschen. +- [ ] Gleichzeitige, kollidierende Jobs auf denselben Pfaden erkennen und serialisieren oder ablehnen. +- [ ] Jobfehler mit verständlicher Meldung und technischem Logeintrag trennen. + +### Löschschutz + +- [ ] Optionalen Papierkorb pro Root implementieren. +- [ ] Direktes permanentes Löschen als gesonderte Aktion behandeln. +- [ ] Anzahl und geschätzte Größe vor rekursivem Löschen anzeigen. +- [ ] Mehrfachauswahl vor dem Start vollständig validieren. +- [ ] Optional eine zweite Bestätigung für sehr große Löschvorgänge verlangen. + +## P1 – Tests + +### PHP-Backend testen + +- [ ] Eigenständige Tests für die tatsächlich ausgelieferten PHP-Endpunkte aufbauen. +- [ ] Die Tests in einer Unraid-kompatiblen PHP-Version ausführen. +- [ ] Listing innerhalb und außerhalb erlaubter Roots testen. +- [ ] Upload, Download, Preview, Copy, Move, Delete, Size und Permissions testen. +- [ ] Read-only-Modus für jede mutierende Aktion testen. +- [ ] Zielkonflikte und ungültige Request-Methoden testen. +- [ ] Sonderzeichen, Unicode, sehr lange Namen und versteckte Dateien testen. +- [ ] Mehrere konfigurierte Roots testen. +- [ ] Regressionstests für alle P0-Sicherheitsfälle ergänzen. + +### CI und statische Prüfung + +- [ ] `php -l` für alle PHP-Dateien in CI ausführen. +- [ ] JavaScript-Syntaxprüfung ausführen. +- [ ] ShellCheck für `build-plugin.sh` aktivieren. +- [ ] XML beziehungsweise PLG-Manifest validieren. +- [ ] Paket bauen und mit den Quellen vergleichen. +- [ ] Manifest-Prüfsumme automatisch verifizieren. +- [ ] Tests bei jedem Push und Pull Request ausführen. + +### Test auf echter Unraid-Instanz + +- [ ] Installation auf unterstützten Unraid-Versionen testen. +- [ ] Upgrade von einer vorherigen Plugin-Version testen. +- [ ] Deinstallation und Neuinstallation testen. +- [ ] Verhalten bei gestopptem und gestartetem Array prüfen. +- [ ] User Shares, Pools und Disk Shares getrennt prüfen. +- [ ] Große Ordner und große Dateien testen. +- [ ] WebGUI-Neustart und Server-Neustart während laufender Jobs testen. +- [ ] Alle offiziellen Themes und mobile Darstellung prüfen. + +## P2 – Konfiguration und Bedienung + +### Root-Konfiguration + +- [ ] Erlaubte Roots in `settings.json` speichern. +- [ ] Einstellungsoberfläche zum Hinzufügen und Entfernen von Roots bauen. +- [ ] Nur existierende absolute Verzeichnisse akzeptieren. +- [ ] Gefährliche Systempfade wie `/`, `/boot`, `/etc`, `/usr`, `/var` und `/root` standardmäßig verbieten. +- [ ] Pro Root einen Anzeigenamen und Read-only-Status erlauben. +- [ ] Änderungen an Roots erst nach erneuter serverseitiger Validierung übernehmen. +- [ ] Root-Auswahl im Explorer anbieten. + +### Dateimanager-Funktionen + +- [ ] Neuen Ordner anlegen. +- [ ] Leere Datei anlegen. +- [ ] Umbenennen mit serverseitiger Namensvalidierung verbessern. +- [ ] Suche nach Dateiname im aktuellen Ordner implementieren. +- [ ] Optionale rekursive Suche mit Ergebnislimit ergänzen. +- [ ] Sortierung nach Name, Typ, Größe und Änderungsdatum anbieten. +- [ ] Versteckte Dateien ein- und ausblendbar machen. +- [ ] Breadcrumb-Navigation ergänzen. +- [ ] Dateibaum beziehungsweise Share-Navigation ergänzen. +- [ ] Tastaturbedienung für Auswahl, Öffnen, Kopieren, Verschieben und Löschen verbessern. + +### Transfer-Oberfläche + +- [ ] Reale Fortschrittswerte nach Bytes statt nur nach Top-Level-Einträgen berechnen. +- [ ] Quelle, Ziel, Geschwindigkeit und Restzeit anzeigen. +- [ ] Fehlgeschlagene Jobs wiederholbar machen. +- [ ] Abgeschlossene Einträge einzeln oder gesammelt entfernen. +- [ ] Uploads pausieren und abbrechen können. + +### Vorschau und Download + +- [ ] MIME-Typ anhand des Dateiinhalts prüfen, nicht nur anhand der Erweiterung. +- [ ] SVG-Vorschau sicher behandeln oder deaktivieren. +- [ ] Medien- und PDF-Vorschau mit geeigneten Sandbox-Headern testen. +- [ ] HTTP-Range-Requests für große Audio- und Videodateien unterstützen. +- [ ] RFC-konforme UTF-8-Dateinamen im `Content-Disposition`-Header verwenden. +- [ ] Einzeldateien streamen, ohne unnötige Pufferung. + +## P2 – Protokollierung und Betrieb + +- [ ] Audit-Log für Upload, Copy, Move, Delete und Permissions einführen. +- [ ] Zeitpunkt, Aktion, Quelle, Ziel, Ergebnis und Fehler protokollieren. +- [ ] Keine CSRF-Tokens oder sensiblen Inhalte ins Debug-Log schreiben. +- [ ] Logrotation und maximale Loggröße definieren. +- [ ] Diagnoseexport für Supportfälle anbieten. +- [ ] Gesundheitsstatus für Job-Worker und temporären Speicher anzeigen. + +## P3 – Paketierung und Veröffentlichung + +- [ ] Version nur an einer Stelle pflegen und beim Build überall einsetzen. +- [ ] `package.json`-Version mit der Plugin-Version synchronisieren. +- [ ] Reproduzierbare TGZ-Pakete mit stabiler Sortierung und Zeitstempeln erzeugen. +- [ ] Nach Möglichkeit SHA-256 zusätzlich zur MD5-Prüfung veröffentlichen. +- [ ] Minimale und getestete Unraid-Version im Plugin-Manifest angeben. +- [ ] Changelog pro Version vollständig pflegen. +- [ ] Release-Build in einer sauberen Working Copy erzeugen. +- [ ] Community-Applications-Metadaten validieren. +- [ ] Installations-, Update- und Rollback-Anleitung ergänzen. +- [ ] Sicherheitsmodell und bekannte Einschränkungen dokumentieren. +- [ ] Read-only als empfohlenen Standard deutlich in README und Oberfläche anzeigen. + +## Definition of Done für die erste produktive Version + +- [ ] Alle P0-Punkte sind abgeschlossen. +- [ ] PHP-Integrationstests decken alle mutierenden Operationen ab. +- [ ] Keine Root- oder Symlink-Regression ist offen. +- [ ] CSRF und Authentifizierung sind auf echter Unraid-Hardware bestätigt. +- [ ] Große Uploads, Downloads und Verzeichnisse besitzen getestete Limits. +- [ ] Fehlgeschlagene Copy-/Move-Jobs hinterlassen keine unbemerkten Teildaten. +- [ ] Installation, Upgrade, Neustart und Deinstallation wurden getestet. +- [ ] Paketinhalt und Manifest-Prüfsumme stimmen überein. +- [ ] Dokumentation und Changelog entsprechen dem ausgelieferten Funktionsumfang. diff --git a/build-plugin.sh b/build-plugin.sh index f4bfe08..ba7c4d3 100755 --- a/build-plugin.sh +++ b/build-plugin.sh @@ -2,7 +2,7 @@ set -eu PLUGIN="u-navigator" -VERSION="2026.07.04.r007" +VERSION="2026.07.14.r008" PKG_DIR="packages" WORK_DIR=".plugin-build" PKG_NAME="${PLUGIN}-${VERSION}.tgz" diff --git a/packages/u-navigator-2026.07.14.r008.tgz b/packages/u-navigator-2026.07.14.r008.tgz new file mode 100644 index 0000000..4d5e7d8 Binary files /dev/null and b/packages/u-navigator-2026.07.14.r008.tgz differ diff --git a/plugin-root/usr/local/emhttp/plugins/u-navigator/U-Navigator.page b/plugin-root/usr/local/emhttp/plugins/u-navigator/U-Navigator.page index 08ac58d..24f2bba 100644 --- a/plugin-root/usr/local/emhttp/plugins/u-navigator/U-Navigator.page +++ b/plugin-root/usr/local/emhttp/plugins/u-navigator/U-Navigator.page @@ -11,26 +11,7 @@ $plugin = "u-navigator"; $version = "__VERSION__"; ?> -
Initialisiere...
-