Go to file
Stefan Hacker 182ef04cc5 Harden security, polish admin UI and document Windows WebDAV
- helmet, express-rate-limit (login/setup/customer-auth/me-password)
- Constant-time login (bcrypt always runs against a dummy hash on miss)
- Cookie secure flag follows req.protocol; trust proxy is env-gated to
  prevent X-Forwarded-For spoofing on direct exposure
- Drop SVG from accepted logo types (same-origin XSS) and resolve the
  served logo path against LOGO_DIR as defense in depth
- Self-service /me/password endpoint plus header button; bumps minimum
  password length to 8 across backend, prompts and edit modal
- Multer 1.x → 2.x for current security backports
- Customer edit modal replaces stacked prompts; user role is now an
  inline dropdown with a confirm-and-revert flow
- Windows .reg helper plus README section for Basic-Auth-over-HTTP and
  the http:// vs \\HOST@PORT\DavWWWRoot\ mapping syntax

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 12:53:13 +02:00
public Harden security, polish admin UI and document Windows WebDAV 2026-04-16 12:53:13 +02:00
src Harden security, polish admin UI and document Windows WebDAV 2026-04-16 12:53:13 +02:00
webdav Add file upload portal with per-customer links and WebDAV admin access 2026-04-16 11:00:51 +02:00
windows Harden security, polish admin UI and document Windows WebDAV 2026-04-16 12:53:13 +02:00
.dockerignore first commit 2026-04-16 10:52:20 +02:00
.env.example Harden security, polish admin UI and document Windows WebDAV 2026-04-16 12:53:13 +02:00
.gitignore first commit 2026-04-16 10:52:20 +02:00
Dockerfile Redesign UI and add configurable branding logo 2026-04-16 11:24:45 +02:00
README.md Harden security, polish admin UI and document Windows WebDAV 2026-04-16 12:53:13 +02:00
docker-compose.yml Redesign UI and add configurable branding logo 2026-04-16 11:24:45 +02:00
package.json Harden security, polish admin UI and document Windows WebDAV 2026-04-16 12:53:13 +02:00

README.md

Simple File Upload

Kunden laden Dateien/Ordner über einen individuellen Link hoch (ohne Login). Admin + Sachbearbeiter verwalten Kunden im Adminportal und greifen per WebDAV zu.

Start

cp .env.example .env     # optional: Ports anpassen
docker compose up -d --build
  • Adminportal: http://localhost:3500/
  • WebDAV: webdav://HOST:1900/ (Basic Auth, dieselben Benutzer wie im Adminportal)

Beim ersten Start öffnet sich ein Setup-Wizard — dort legst du den ersten Admin an.

Rollen

  • Admin: legt Kunden + weitere Benutzer (Admins / Sachbearbeiter) an, verwaltet Upload-Links und pro-Kunde-Zugriffe. Hat WebDAV-Vollzugriff auf alles.
  • Sachbearbeiter (Staff): sieht im Adminportal nur die Kunden, auf die ihm der Admin Zugriff erteilt hat. Per WebDAV greift er auf die zugeteilten Kundenordner zu (read oder write).
  • Kunde: kein Login; Upload via individuellem Token-Link (optional mit Passwort + Ablaufdatum). Sieht keine Dateiliste.

Konfiguration

.env (Ports)

Variable Default Zweck
APP_PORT 3500 Host-Port für Adminportal + Upload
WEBDAV_PORT 1900 Host-Port für WebDAV

Admin-GUI → Einstellungen

  • Öffentliche Basis-URL: wird in generierten Upload-Links verwendet. Leer = aus Request ableiten.
  • Cron-Intervall (Minuten): periodischer DB/FS-Abgleich (entfernt verwaiste DB-Einträge von via WebDAV gelöschten Dateien und erfasst direkt per WebDAV hochgeladene Dateien).

Volumes

  • ./data/db/ → SQLite-Datei neben der docker-compose.yml
  • ./data/uploads/ → ein Unterordner pro Kunde (Slug)
  • Named Volume webdav-config → dynamisch generierte Apache-Config

Beide Container laufen als UID 1000:1000. Falls vorhandene Daten root gehören:

sudo chown -R 1000:1000 data/

Wie die WebDAV-ACLs funktionieren

Der App-Container erzeugt bei jeder Benutzer-/Kundenänderung:

  • /webdav-config/htpasswd — alle Benutzer (bcrypt-Hashes direkt aus DB)
  • /webdav-config/access.conf — pro Kundenordner ein <Location>-Block:
    • gleiche Read- und Write-User → ein Require user …
    • unterschiedliche → <Limit GET PROPFIND OPTIONS HEAD> + <LimitExcept …> für saubere Trennung

Der WebDAV-Container (Debian Apache) beobachtet das Verzeichnis via inotifywait und ruft apachectl graceful auf → Änderungen sind in ~2 Sek. wirksam.

Kunden-Upload

  • Datei-Button, Ordner-Button oder Drag & Drop (Dateien und Ordner — Struktur bleibt erhalten).
  • Optional Passwortabfrage, optional Ablaufdatum.
  • Kunde sieht keine Dateiliste, nur eigenes Upload-Feedback.

WebDAV-Zugriff

  • macOS Finder: Gehe zu → Mit Server verbinden → http://HOST:1900/
  • Linux / KDE Dolphin: webdav://<user>@HOST:1900/
  • Windows: siehe Abschnitt unten (einmalige Einrichtung nötig)

Write-Rechte umfassen: PUT, DELETE, MKCOL, MOVE, COPY, PROPPATCH, LOCK, UNLOCK. In Dolphin löscht Shift+Entf direkt (umgeht den nicht existierenden WebDAV-Papierkorb).

Windows als Netzlaufwerk verbinden

Windows verweigert standardmäßig WebDAV via Basic Auth über HTTP und limitiert Dateien auf 50 MB. Beides per Registry erlauben:

  1. windows/enable-webdav-basicauth.reg per Rechtsklick → Zusammenführen (als Administrator) ausführen.

  2. WebClient-Dienst (neu) starten:

    sc config WebClient start=auto
    net stop WebClient
    net start WebClient
    
  3. Verbinden — HTTP-URL ist die saubere Variante (eindeutig WebDAV, keine SMB-Verwechslung). Beispiel mit karlheinz-Credentials, gemountet als Z::

    net use Z: http://HOST:1900/frank-meier /user:karlheinz DEINPW /persistent:yes
    

    Im Explorer „Netzlaufwerk verbinden" → Adresse: http://HOST:1900/ bzw. http://HOST:1900/frank-meier/.

    Alternativ mit UNC-Syntax (intern dasselbe, etwas hakeliger): \\HOST@1900\DavWWWRoot\frank-meier\@1900 und \DavWWWRoot\ sind dabei Pflicht, sonst landest du bei SMB Port 445.

Wenn weiterhin „Ordner nicht gefunden" → meist ist der WebClient-Dienst nicht gestartet oder das Registry-Merge wurde nicht als Administrator ausgeführt.