fix(backend): enforce private-by-default visibility and pool-op ACL

Listings returned every row regardless of ownership: GET /files, /tags,
/pools and /categories exposed other users' private items (while the
single-item GET correctly returned 403), and the pool file operations
(GET /pools/:id, /pools/:id/files, add/remove/reorder) skipped ACL
entirely, so any authenticated user could read and rewrite anyone's
private pool.

- List queries now filter to rows the caller may see (public, owned, or
  granted can_view) via a shared SQL condition; admins bypass. The viewer
  identity is taken from the request context by the service and passed to
  the repository in the list params.
- Tag/Category/Pool single-item Get now enforce CanView (File already did).
- Pool Get/ListFiles require pool view; AddFiles/RemoveFiles/Reorder
  require pool edit.

Adds regression tests for private-by-default listing (hidden / public /
granted / admin) and for pool operations rejecting a non-owner.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 15:07:17 +03:00
parent 2af3c481bb
commit 89ba6bae82
12 changed files with 288 additions and 15 deletions
+6
View File
@@ -49,6 +49,12 @@ type FileListParams struct {
Filter string // filter DSL expression
Search string // substring match on original_name
Trash bool // if true, return only soft-deleted files
// Visibility — populated by the service from the request context. When
// ViewerIsAdmin is false the repository restricts results to files the
// viewer may see (public, owned, or explicitly granted).
ViewerID int16
ViewerIsAdmin bool
}
// FilePage is the result of a cursor-based file listing.