From cc9ca2cd81a6baf0986683aca962632d03873258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesko=20Ansch=C3=BCtz?= Date: Sat, 28 Mar 2026 09:18:12 +0100 Subject: [PATCH] fix: nil-pointer in DeleteMediaUI, restricted delete-check in tenant handler, SCHEMA fix - HandleDeleteMediaUI: check err after media.Get before using asset (prevents nil-pointer panic) - HandleTenantDeleteMedia: add restricted-user ownership check (K3) - HandleTenantDashboard: filter media list by ownerUserID for restricted users - SCHEMA.md: correct created_by_user_id to 'text null ... on delete set null' Co-Authored-By: Claude Sonnet 4.6 --- docs/SCHEMA.md | 2 +- server/backend/internal/httpapi/manage/ui.go | 6 +++++- server/backend/internal/httpapi/tenant/tenant.go | 11 ++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/SCHEMA.md b/docs/SCHEMA.md index 62bc516..5ec9562 100644 --- a/docs/SCHEMA.md +++ b/docs/SCHEMA.md @@ -269,7 +269,7 @@ mime_type text null checksum text null size_bytes bigint null enabled boolean not null default true -created_by_user_id uuid not null references users(id) on delete restrict +created_by_user_id text null references users(id) on delete set null created_at timestamptz not null updated_at timestamptz not null ``` diff --git a/server/backend/internal/httpapi/manage/ui.go b/server/backend/internal/httpapi/manage/ui.go index 2ba133d..8d706d7 100644 --- a/server/backend/internal/httpapi/manage/ui.go +++ b/server/backend/internal/httpapi/manage/ui.go @@ -869,6 +869,10 @@ func HandleDeleteMediaUI(media *store.MediaStore, screens *store.ScreenStore, up } asset, err := media.Get(r.Context(), mediaID) + if err != nil { + http.Error(w, "medium nicht gefunden", http.StatusNotFound) + return + } // K3: Restricted User darf nur eigene Medien löschen. if u := reqcontext.UserFromContext(r.Context()); u != nil && !canDeleteMedia(u, asset) { @@ -876,7 +880,7 @@ func HandleDeleteMediaUI(media *store.MediaStore, screens *store.ScreenStore, up return } - if err == nil && asset.StoragePath != "" { + if asset.StoragePath != "" { os.Remove(filepath.Join(uploadDir, filepath.Base(asset.StoragePath))) //nolint:errcheck } media.Delete(r.Context(), mediaID) //nolint:errcheck diff --git a/server/backend/internal/httpapi/tenant/tenant.go b/server/backend/internal/httpapi/tenant/tenant.go index 101febc..c94db6f 100644 --- a/server/backend/internal/httpapi/tenant/tenant.go +++ b/server/backend/internal/httpapi/tenant/tenant.go @@ -74,7 +74,11 @@ func HandleTenantDashboard( return } - assets, err := mediaStore.List(r.Context(), tenant.ID, "") + ownerUserID := "" + if u := reqcontext.UserFromContext(r.Context()); u != nil && u.Role == "restricted" { + ownerUserID = u.ID + } + assets, err := mediaStore.List(r.Context(), tenant.ID, ownerUserID) if err != nil { http.Error(w, "db error", http.StatusInternalServerError) return @@ -230,6 +234,11 @@ func HandleTenantDeleteMedia( http.Error(w, "Forbidden", http.StatusForbidden) return } + // K3: Restricted User darf nur eigene Medien löschen. + if u := reqcontext.UserFromContext(r.Context()); u != nil && u.Role == "restricted" && asset.CreatedByUserID != u.ID { + http.Error(w, "Forbidden", http.StatusForbidden) + return + } if asset.StoragePath != "" { os.Remove(filepath.Join(uploadDir, filepath.Base(asset.StoragePath))) //nolint:errcheck }