morz-infoboard/server/backend
Jesko Anschütz dd3ec070f7 Security-Review + Phase 6: CSRF, Rate-Limiting, Tenant-Isolation, Screenshot, Ansible
### Security-Fixes (K1–K6, W1–W4, W7, N1, N5–N6, V1, V5–V7)
- K1: CSRF-Schutz via Double-Submit-Cookie (httpapi/csrf.go + csrf_helpers.go)
- K2: requireScreenAccess() in allen manage-Handlern (Tenant-Isolation)
- K3: Tenant-Check bei DELETE /api/v1/media/{id}
- K4: requirePlaylistAccess() + GetByItemID() für JSON-API Playlist-Routen
- K5: Admin-Passwort nur noch als [gesetzt] geloggt
- K6: POST /api/v1/screens/register mit Pre-Shared-Secret (MORZ_INFOBOARD_REGISTER_SECRET)
- W1: Race Condition bei order_index behoben (atomare Subquery in AddItem)
- W2: Graceful Shutdown mit 15s Timeout auf SIGTERM/SIGINT
- W3: http.MaxBytesReader (512 MB) in allen Upload-Handlern
- W4: err.Error() nicht mehr an den Client
- W7: Template-Execution via bytes.Buffer (kein partial write bei Fehler)
- N1: Rate-Limiting auf /login (5 Versuche/Minute pro IP, httpapi/ratelimit.go)
- N5: Directory-Listing auf /uploads/ deaktiviert (neuteredFileSystem)
- N6: Uploads nach Tenant getrennt (uploads/{tenantSlug}/)
- V1: Upload-Logik konsolidiert in internal/fileutil/fileutil.go
- V5: Cookie-Name als Konstante reqcontext.SessionCookieName
- V6: Strukturiertes Logging mit log/slog + JSON-Handler
- V7: DB-Pool wird im Graceful-Shutdown geschlossen

### Phase 6: Screenshot-Erzeugung
- player/agent/internal/screenshot/screenshot.go erstellt
- Integration in app.go mit MORZ_INFOBOARD_SCREENSHOT_EVERY Config

### UX: PDF.js Integration
- pdf.min.js + pdf.worker.min.js als lokale Assets eingebettet
- Automatisches Seitendurchblättern im Player

### Ansible: Neue Rollen
- signage_base, signage_server, signage_provision erstellt
- inventory.yml und site.yml erweitert

### Konzept-Docs
- GRUPPEN-KONZEPT.md, KAMPAGNEN-AKTIVIERUNG.md, MONITORING-KONZEPT.md
- PROVISION-KONZEPT.md, TEMPLATE-EDITOR.md, WATCHDOG-KONZEPT.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-23 21:06:35 +01:00
..
cmd/api Security-Review + Phase 6: CSRF, Rate-Limiting, Tenant-Isolation, Screenshot, Ansible 2026-03-23 21:06:35 +01:00
internal Security-Review + Phase 6: CSRF, Rate-Limiting, Tenant-Isolation, Screenshot, Ansible 2026-03-23 21:06:35 +01:00
Dockerfile Bugfixes: JSON-Tags, Tenant-Lookup, Dockerfile Go-Version 2026-03-22 23:26:56 +01:00
go.mod Tenant-Feature Phase 1+2: Auth-Fundament + Login-Flow + UX-Textverbesserung 2026-03-23 15:46:14 +01:00
go.sum Tenant-Feature Phase 1+2: Auth-Fundament + Login-Flow + UX-Textverbesserung 2026-03-23 15:46:14 +01:00
README.md Dokumentation: Security-Features und Upload-Konsolidierung (Phase 6) 2026-03-23 21:01:47 +01:00

Backend

Dieses Verzeichnis enthaelt das zentrale Go-Backend fuer das Info-Board-System.

Aufgaben

  • HTTP-API und serverseitige HTML-UI (Bulma)
  • PostgreSQL-Anbindung mit automatischen Migrationen
  • Session-basierte Authentifizierung und rollenbasierte Zugriffskontrolle
  • Medienverwaltung und Playlist-Management
  • Player-Status-Ingest und Diagnose
  • MQTT-Notifizierungen bei Playlist-Aenderungen

Unterstruktur

  • cmd/api/ — Startpunkt des Backends
  • internal/app/ — App-Initialisierung und Lifecycle
  • internal/config/ — Konfiguration via Umgebungsvariablen
  • internal/db/ — PostgreSQL-Anbindung und Migrations-Runner
  • internal/store/ — Datenbankzugriff (TenantStore, ScreenStore, MediaStore, PlaylistStore, AuthStore)
  • internal/fileutil/ — Upload-Hilfsfunktionen (SaveUploadedFile mit Tenant-Isolation)
  • internal/httpapi/ — HTTP-Routing, Middleware und Handler
  • internal/httpapi/csrf.go — Double-Submit-Cookie CSRF-Schutz
  • internal/httpapi/ratelimit.go — Rate-Limiting fuer /login (Brute-Force-Schutz)
  • internal/httpapi/uploads.go — Upload-Handler konsolidiert
  • internal/httpapi/manage/ — Admin-UI und Playlist-Management-UI
  • internal/httpapi/manage/csrf_helpers.go — CSRF-Token Helpers fuer Templates
  • internal/httpapi/tenant/ — Tenant-Self-Service-Dashboard
  • internal/mqttnotifier/ — MQTT-Notifizierungen
  • internal/reqcontext/ — Context-Keys fuer authentifizierten User

Aktuelle Endpunkte

Oeffentlich (keine Auth)

Methode Pfad Beschreibung
GET /healthz Health-Check
GET /api/v1 API-Entrypoint
GET /api/v1/meta Metainformationen
POST /api/v1/player/status Status-Ingest vom Player-Agent
GET /api/v1/screens/status Uebersicht aller Screen-Status
GET /api/v1/screens/{screenId}/status Einzelner Screen-Status
DELETE /api/v1/screens/{screenId}/status Screen-Status loeschen
GET /api/v1/screens/{screenId}/playlist Playlist fuer Player (kein Auth)
POST /api/v1/screens/register Agent-Selbstregistrierung
POST /api/v1/tools/message-wall/resolve Message-Wall-Aufloesungsendpunkt
GET /status HTML-Diagnoseseite
GET /status/{screenId} HTML-Detailseite Einzelscreen
GET /uploads/{filename} Hochgeladene Dateien abrufen
GET /static/bulma.min.css Statisches CSS
GET /static/Sortable.min.js Statisches JS
GET /login Login-Formular
POST /login Login verarbeiten
POST /logout Session beenden

Nur eingeloggte Benutzer (RequireAuth)

Methode Pfad Beschreibung
GET /manage/{screenSlug} Playlist-Management-UI
POST /manage/{screenSlug}/upload Medium fuer Screen hochladen
POST /manage/{screenSlug}/items Item zur Playlist hinzufuegen
POST /manage/{screenSlug}/items/{itemId} Item aktualisieren
POST /manage/{screenSlug}/items/{itemId}/delete Item loeschen
POST /manage/{screenSlug}/reorder Items reordnen
POST /manage/{screenSlug}/media/{mediaId}/delete Medium loeschen
GET /api/v1/playlists/{screenId} Playlist mit Metadaten abrufen
POST /api/v1/playlists/{playlistId}/items Item zur Playlist hinzufuegen (API)
PATCH /api/v1/items/{itemId} Item aktualisieren (API)
DELETE /api/v1/items/{itemId} Item loeschen (API)
PUT /api/v1/playlists/{playlistId}/order Items reordnen (API)
PATCH /api/v1/playlists/{playlistId}/duration Standard-Dauer setzen (API)
DELETE /api/v1/media/{id} Medium loeschen (API)

Nur Admins (RequireAuth + RequireAdmin)

Methode Pfad Beschreibung
GET /admin Admin-Uebersicht
POST /admin/screens/provision Provisionierungs-Job starten
POST /admin/screens Neuen Screen anlegen
POST /admin/screens/{screenId}/delete Screen loeschen

Tenant-scoped (RequireAuth + RequireTenantAccess)

Methode Pfad Beschreibung
GET /tenant/{tenantSlug}/dashboard Tenant-Self-Service-Dashboard
POST /tenant/{tenantSlug}/upload Medium hochladen
POST /tenant/{tenantSlug}/media/{mediaId}/delete Medium loeschen
GET /api/v1/tenants/{tenantSlug}/screens Screens eines Tenants auflisten
POST /api/v1/tenants/{tenantSlug}/screens Screen anlegen
GET /api/v1/tenants/{tenantSlug}/media Medien eines Tenants auflisten
POST /api/v1/tenants/{tenantSlug}/media Medium hochladen (API)

Konfiguration

Alle Werte per Umgebungsvariable:

Variable Bedeutung Standard
MORZ_INFOBOARD_HTTP_ADDR HTTP-Listen-Adresse :8080
DATABASE_URL PostgreSQL-Connection-String
MORZ_INFOBOARD_UPLOAD_DIR Verzeichnis fuer hochgeladene Medien /tmp/morz-uploads
MORZ_INFOBOARD_STATUS_STORE_PATH Pfad zur JSON-Persistenz-Datei fuer Status-Store leer (in-memory)
MORZ_INFOBOARD_ADMIN_PASSWORD Passwort des initialen Admin-Users (leer = kein Anlegen) leer
MORZ_INFOBOARD_DEFAULT_TENANT Slug des Tenants, dem der Admin zugeordnet wird morz
MORZ_INFOBOARD_DEV_MODE true = Session-Cookie ohne Secure-Flag (nur lokal) false
MORZ_INFOBOARD_REGISTER_SECRET Pre-Shared-Secret fuer POST /api/v1/screens/register leer
MORZ_INFOBOARD_MQTT_BROKER MQTT-Broker-URL (leer = kein MQTT) leer
MORZ_INFOBOARD_MQTT_USERNAME MQTT-Benutzername leer
MORZ_INFOBOARD_MQTT_PASSWORD MQTT-Passwort leer

Detailliertere Beschreibung und lokale Startbeispiele: DEVELOPMENT.md.