fix(backend): enforce file ACL on file-tag and import endpoints

Two broken-access-control holes:

- PUT/DELETE /files/:id/tags(/:tag_id) and GET /files/:id/tags went
  straight to TagService with no ACL check, letting any authenticated
  user read or rewrite tags on anyone's private files. The handlers now
  require view (list) or edit (mutate) on the target file via new
  FileService.AuthorizeView/AuthorizeEdit helpers.

- POST /files/import accepted an arbitrary host path from any user,
  turning it into an arbitrary server-side file read. It is now
  admin-only and the supplied path is confined to IMPORT_PATH.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 13:59:33 +03:00
parent a6680b1c05
commit 945df7ef8a
3 changed files with 87 additions and 5 deletions
+6
View File
@@ -613,6 +613,12 @@ func (h *FileHandler) CommonTags(c *gin.Context) {
// ---------------------------------------------------------------------------
func (h *FileHandler) Import(c *gin.Context) {
// Server-side directory import reads arbitrary paths on the host; restrict
// it to administrators.
if !requireAdmin(c) {
return
}
var body struct {
Path string `json:"path"`
}
+20
View File
@@ -430,6 +430,11 @@ func (h *TagHandler) FileListTags(c *gin.Context) {
return
}
if err := h.fileSvc.AuthorizeView(c.Request.Context(), fileID); err != nil {
respondError(c, err)
return
}
tags, err := h.tagSvc.ListFileTags(c.Request.Context(), fileID)
if err != nil {
respondError(c, err)
@@ -465,6 +470,11 @@ func (h *TagHandler) FileSetTags(c *gin.Context) {
return
}
if err := h.fileSvc.AuthorizeEdit(c.Request.Context(), fileID); err != nil {
respondError(c, err)
return
}
tags, err := h.tagSvc.SetFileTags(c.Request.Context(), fileID, tagIDs)
if err != nil {
respondError(c, err)
@@ -491,6 +501,11 @@ func (h *TagHandler) FileAddTag(c *gin.Context) {
return
}
if err := h.fileSvc.AuthorizeEdit(c.Request.Context(), fileID); err != nil {
respondError(c, err)
return
}
tags, err := h.tagSvc.AddFileTag(c.Request.Context(), fileID, tagID)
if err != nil {
respondError(c, err)
@@ -517,6 +532,11 @@ func (h *TagHandler) FileRemoveTag(c *gin.Context) {
return
}
if err := h.fileSvc.AuthorizeEdit(c.Request.Context(), fileID); err != nil {
respondError(c, err)
return
}
if err := h.tagSvc.RemoveFileTag(c.Request.Context(), fileID, tagID); err != nil {
respondError(c, err)
return