discourse/lib/bookmarks_bulk_action.rb
Martin Brennan f1c600a8ab
FIX: BookmarksBulkAction#delete passing integer to guardian instead of Bookmark object (#37871)
## Summary

Broken authorization check in `BookmarksBulkAction#delete` — passes
Integer to Guardian instead of Bookmark object, causing
`guardian.can_delete?` to always return `true` for any authenticated
user regardless of bookmark ownership.

## Source

- Patch Triage: https://patch.discourse.org/patch-triage/233
- Original Commit:
https://github.com/discourse/discourse/blob/main/app/controllers/bookmarks_controller.rb

---

🤖 Generated via [Patch Triage](https://patch.discourse.org/patch-triage)
2026-02-17 15:14:46 +10:00

62 lines
1.3 KiB
Ruby

# frozen_string_literal: true
class BookmarksBulkAction
def initialize(user, bookmark_ids, operation, options = {})
@user = user
@bookmark_ids = bookmark_ids
@operation = operation
@changed_ids = []
@options = options
end
def self.operations
@operations ||= %w[clear_reminder delete]
end
def perform!
if BookmarksBulkAction.operations.exclude?(@operation[:type])
raise Discourse::InvalidParameters.new(:operation)
end
case @operation[:type]
when "clear_reminder"
clear_reminder
when "delete"
delete
end
@changed_ids.sort
end
private
def delete
bookmarks.each do |bookmark|
if guardian.can_delete?(bookmark)
BookmarkManager.new(@user).destroy(bookmark.id)
@changed_ids << bookmark.id
else
raise Discourse::InvalidAccess.new
end
end
end
def clear_reminder
bookmarks.each do |bookmark|
if guardian.can_edit?(bookmark)
bookmark.clear_reminder!(force_clear_reminder_at: true)
@changed_ids << bookmark.id
else
raise Discourse::InvalidAccess.new
end
end
end
def guardian
@guardian ||= Guardian.new(@user)
end
def bookmarks
@bookmarks ||= Bookmark.where(id: @bookmark_ids)
end
end