fix(share): add ownership checks to Delete and Update (#5189)

* test(share): add failing tests for Delete ownership checks

* fix(share): add ownership check to Delete

* test(share): add failing tests for Update ownership checks

* fix(share): add ownership check to Update

* refactor(share): extract checkOwnership helper with lightweight query

- Deduplicate ownership check from Delete and Update into a single helper
- Use a minimal single-column SELECT instead of Get (avoids loadMedia overhead)
- Use positive bypass form (IsAdmin || invalidUserId) matching codebase convention

* fix(share): convert model.ErrNotFound to rest.ErrNotFound in checkOwnership

Ensure consistent 404 responses when a nonexistent share ID is passed
to Delete or Update, by handling the conversion in checkOwnership
rather than relying on the subsequent write operation.
This commit is contained in:
Deluan Quintão
2026-03-15 00:12:58 -04:00
committed by GitHub
parent 197d357f02
commit 6b8fcc37c6
2 changed files with 117 additions and 1 deletions
+29 -1
View File
@@ -30,7 +30,33 @@ func NewShareRepository(ctx context.Context, db dbx.Builder) model.ShareReposito
return r
}
// TODO: Ownership checks should be moved to the service layer (core/share.go)
func (r *shareRepository) checkOwnership(id string) error {
usr := loggedUser(r.ctx)
if usr.IsAdmin || usr.ID == invalidUserId {
return nil
}
sel := r.newSelect().Columns("user_id").Where(Eq{"id": id})
var share struct {
UserID string `db:"user_id"`
}
err := r.queryOne(sel, &share)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
return rest.ErrNotFound
}
return err
}
if share.UserID != usr.ID {
return rest.ErrPermissionDenied
}
return nil
}
func (r *shareRepository) Delete(id string) error {
if err := r.checkOwnership(id); err != nil {
return err
}
err := r.delete(Eq{"id": id})
if errors.Is(err, model.ErrNotFound) {
return rest.ErrNotFound
@@ -140,7 +166,9 @@ func sortByIdPosition(mfs model.MediaFiles, ids []string) model.MediaFiles {
func (r *shareRepository) Update(id string, entity any, cols ...string) error {
s := entity.(*model.Share)
// TODO Validate record
if err := r.checkOwnership(id); err != nil {
return err
}
s.ID = id
s.UpdatedAt = time.Now()
cols = append(cols, "updated_at")