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 <noreply@anthropic.com>
This commit is contained in:
Jesko Anschütz 2026-03-28 09:18:12 +01:00
parent e884acf41d
commit cc9ca2cd81
3 changed files with 16 additions and 3 deletions

View file

@ -269,7 +269,7 @@ mime_type text null
checksum text null checksum text null
size_bytes bigint null size_bytes bigint null
enabled boolean not null default true 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 created_at timestamptz not null
updated_at timestamptz not null updated_at timestamptz not null
``` ```

View file

@ -869,6 +869,10 @@ func HandleDeleteMediaUI(media *store.MediaStore, screens *store.ScreenStore, up
} }
asset, err := media.Get(r.Context(), mediaID) 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. // K3: Restricted User darf nur eigene Medien löschen.
if u := reqcontext.UserFromContext(r.Context()); u != nil && !canDeleteMedia(u, asset) { 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 return
} }
if err == nil && asset.StoragePath != "" { if asset.StoragePath != "" {
os.Remove(filepath.Join(uploadDir, filepath.Base(asset.StoragePath))) //nolint:errcheck os.Remove(filepath.Join(uploadDir, filepath.Base(asset.StoragePath))) //nolint:errcheck
} }
media.Delete(r.Context(), mediaID) //nolint:errcheck media.Delete(r.Context(), mediaID) //nolint:errcheck

View file

@ -74,7 +74,11 @@ func HandleTenantDashboard(
return 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 { if err != nil {
http.Error(w, "db error", http.StatusInternalServerError) http.Error(w, "db error", http.StatusInternalServerError)
return return
@ -230,6 +234,11 @@ func HandleTenantDeleteMedia(
http.Error(w, "Forbidden", http.StatusForbidden) http.Error(w, "Forbidden", http.StatusForbidden)
return 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 != "" { if asset.StoragePath != "" {
os.Remove(filepath.Join(uploadDir, filepath.Base(asset.StoragePath))) //nolint:errcheck os.Remove(filepath.Join(uploadDir, filepath.Base(asset.StoragePath))) //nolint:errcheck
} }