- HandleManageUI übergibt CSRFToken korrekt ans Template (leeres Hidden-Field blockierte JS-Inject-Snippet) - HandleTenantDashboard setzt CSRF-Cookie und befüllt CSRFToken in Template-Daten - tenant/csrf_helpers.go: setCSRFCookie im tenant-Package (Import-Cycle-Isolation) - Logout-Formular in tenantDashTmpl hat jetzt statisches CSRF-Hidden-Field - Doku: POST /logout und POST /login mit CSRF-Anforderungen dokumentiert Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
11 KiB
11 KiB
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 Backendsinternal/app/— App-Initialisierung und Lifecycleinternal/config/— Konfiguration via Umgebungsvariableninternal/db/— PostgreSQL-Anbindung und Migrations-Runnerinternal/store/— Datenbankzugriff (TenantStore, ScreenStore, MediaStore, PlaylistStore, AuthStore)internal/fileutil/— Upload-Hilfsfunktionen (SaveUploadedFile mit Tenant-Isolation)internal/httpapi/— HTTP-Routing, Middleware und Handlerinternal/httpapi/csrf.go— Double-Submit-Cookie CSRF-Schutzinternal/httpapi/ratelimit.go— Rate-Limiting fuer /login (Brute-Force-Schutz)internal/httpapi/uploads.go— Upload-Handler konsolidiertinternal/httpapi/screenshot.go— Handler fuer Player-Screenshot-Upload und Screenshot-Abrufinternal/httpapi/screenshot_store.go— In-Memory-Store fuer Screenshots (ScreenshotStore, thread-safe viasync.RWMutex)internal/httpapi/manage/— Admin-UI und Playlist-Management-UIinternal/httpapi/manage/csrf_helpers.go— CSRF-Token Helpers fuer Templates (manage-Package)internal/httpapi/tenant/— Tenant-Self-Service-Dashboardinternal/httpapi/tenant/csrf_helpers.go— CSRF-Token Helpers fuer Templates (tenant-Package, Import-Cycle-Isolation)internal/mqttnotifier/— MQTT-Notifizierungen (NotifyChanged,RequestScreenshot)internal/reqcontext/— Context-Keys fuer authentifizierten User
Datenbank-Stores
AuthStore (internal/store/auth.go)
Screen-User Management:
CreateScreenUser(ctx, tenantID, username, passwordHash)— neuen Screen-User anlegenListScreenUsers(ctx, tenantID)— alle Screen-User eines Tenants auflistenDeleteUser(ctx, userID)— User und alle zugeordneten Permissions loeschen
Authentifizierung:
GetUserByUsername(ctx, username)— Nutzer per Username ladenCreateSession(ctx, userID, ttl)— neue Session anlegenGetSessionUser(ctx, sessionID)— User zu gueltigem Session-Token ladenDeleteSession(ctx, sessionID)— Session loeschen (Logout)CleanExpiredSessions(ctx)— abgelaufene Sessions bereinigenEnsureAdminUser(ctx, tenantSlug, password)— Admin-User beim Start anlegenVerifyPassword(ctx, userID, password)— Passwort gegen bcrypt-Hash pruefen
ScreenStore (internal/store/screen.go)
Screen-User Zugriffskontrolle:
GetAccessibleScreens(ctx, userID)— alle Screens, auf die der User Zugriff hatHasUserScreenAccess(ctx, userID, screenID)— prueft ob User auf Screen zugreifen darf (boolean)AddUserToScreen(ctx, userID, screenID)— User zu Screen hinzufuegen (Eintrag inuser_screen_permissions)RemoveUserFromScreen(ctx, userID, screenID)— User von Screen entfernenGetScreenUsers(ctx, screenID)— alle User, die auf Screen Zugriff haben
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 |
| POST | /api/v1/player/screenshot |
Screenshot-Upload 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 |
Screen-Uebersicht fuer screen_user |
| 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) |
| GET | /api/v1/screens/{screenId}/screenshot |
Screenshot eines Screens abrufen |
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 |
| POST | /admin/users |
Screen-User anlegen |
| POST | /admin/users/{userID}/delete |
Screen-User loeschen |
| POST | /admin/screens/{screenID}/users |
User zu Screen hinzufuegen |
| POST | /admin/screens/{screenID}/users/{userID}/remove |
User von Screen entfernen |
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 |
MORZ_INFOBOARD_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.
Middleware
RequireScreenAccess
Middleware zur rollenbasierten Zugriffskontrolle auf Screen-Ressourcen.
Verhalten:
- Admins duerfen auf alle Screens zugreifen
- Screen-User duerfen nur auf Screens zugreifen, fuer die sie in
user_screen_permissionseingetragen sind - Tenant-User duerfen auf alle Screens ihres Tenants zugreifen
- Response:
403 Forbiddenwenn keine Berechtigung
Verwendung:
GET /api/v1/screens/{screenId}/playlistPOST /manage/{screenSlug}/...- Alle privaten Screen-Endpunkte
Migrationen
001_core.sql— initiales Schema (Tenants, Screens, Playlists, Media, etc.)002_auth.sql— Auth-Tabellen (users,sessions)003_user_screen_permissions.sql— Screen-User Management (user_screen_permissions)