fix(backend): require owner/admin to read or modify object ACLs

GET/PUT /acl/:object_type/:object_id performed no authorization check, so
any authenticated user could read the permission list of, or grant
themselves view/edit on, any file/tag/category/pool. ACLService now
resolves the object's owner and rejects callers who are neither the owner
nor an admin. SetPermissions also wraps its delete+insert replace in a
single transaction so a partial failure can no longer wipe permissions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 13:59:10 +03:00
parent eb2eb00d96
commit a6680b1c05
4 changed files with 109 additions and 12 deletions
+5 -3
View File
@@ -80,7 +80,8 @@ func (h *ACLHandler) GetPermissions(c *gin.Context) {
return
}
perms, err := h.aclSvc.GetPermissions(c.Request.Context(), objectTypeID, objectID)
userID, isAdmin, _ := domain.UserFromContext(c.Request.Context())
perms, err := h.aclSvc.GetPermissions(c.Request.Context(), userID, isAdmin, objectTypeID, objectID)
if err != nil {
respondError(c, err)
return
@@ -124,13 +125,14 @@ func (h *ACLHandler) SetPermissions(c *gin.Context) {
}
}
if err := h.aclSvc.SetPermissions(c.Request.Context(), objectTypeID, objectID, perms); err != nil {
userID, isAdmin, _ := domain.UserFromContext(c.Request.Context())
if err := h.aclSvc.SetPermissions(c.Request.Context(), userID, isAdmin, objectTypeID, objectID, perms); err != nil {
respondError(c, err)
return
}
// Re-read to return the stored permissions (with UserName denormalized).
stored, err := h.aclSvc.GetPermissions(c.Request.Context(), objectTypeID, objectID)
stored, err := h.aclSvc.GetPermissions(c.Request.Context(), userID, isAdmin, objectTypeID, objectID)
if err != nil {
respondError(c, err)
return