CVE-2023-45816: Exposure of Sensitive Information to an Unauthorized Actor (CWE-200)
value: Discourse is an open source platform for community discussion. Prior to version 3.1.3 of the `stable` branch and version 3.2.0.beta3 of the `beta` and `tests-passed` branches, there is an edge case where a bookmark reminder is sent and an unread notification is generated, but the underlying bookmarkable (e.g. post, topic, chat message) security has changed, making it so the user can no longer access the underlying resource. As of version 3.1.3 of the `stable` branch and version 3.2.0.beta3 of the `beta` and `tests-passed` branches, bookmark reminders are now no longer sent if the user does not have access to the underlying bookmarkable, and also the unread bookmark notifications are always filtered by access. There are no known workarounds.
CWE description: The product exposes sensitive information to an actor that is not explicitly authorized to have access to that information.
CVSS v3 base score: 3.3
Published: 2023-11-10T15:15Z
Repository: https://github.com/discourse/discourse
Language: Ruby
Files changed: app/controllers/notifications_controller.rb, app/controllers/users_controller.rb, app/models/notification.rb, app/services/post_bookmarkable.rb, app/services/topic_bookmarkable.rb, lib/bookmark_query.rb, plugins/chat/lib/chat/message_bookmarkable.rb, plugins/chat/spec/lib/chat/message_bookmarkable_spec.rb, plugins/chat/spec/requests/core_ext/users_controller_spec.rb, spec/lib/bookmark_query_spec.rb, spec/requests/users_controller_spec.rb, spec/services/post_bookmarkable_spec.rb, spec/services/topic_bookmarkable_spec.rb
Commit date: 2023-11-09 13:39:16 +1100
Commit message: SECURITY: Filter unread bookmark reminders the user cannot see

There is an edge case where the following occurs:

1. The user sets a bookmark reminder on a post/topic
2. The post/topic is changed to a PM before or after the reminder
   fires, and the notification remains unread by the user
3. The user opens their bookmark reminder notification list
   and they can still see the notification even though they cannot
   access the topic anymore

There is a very low chance for information leaking here, since
the only thing that could be exposed is the topic title if it
changes to something sensitive.

This commit filters the bookmark unread notifications by using
the bookmarkable can_see? methods and also prevents sending
reminder notifications for bookmarks the user can no longer see.

Diff: diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb
index 75cd9c60b797..ecf965cf256d 100644
--- a/app/controllers/notifications_controller.rb
+++ b/app/controllers/notifications_controller.rb
@@ -53,11 +53,12 @@ class NotificationsController < ApplicationController
           # block is executed
           User.find_by(id: current_user_id)&.bump_last_seen_reviewable!
         end
       end
 
-      notifications = filter_inaccessible_notifications(notifications)
+      notifications =
+        Notification.filter_inaccessible_topic_notifications(current_user.guardian, notifications)
 
       json = {
         notifications: serialize_data(notifications, NotificationSerializer),
         seen_notification_id: current_user.seen_notification_id,
       }
@@ -80,11 +81,12 @@ class NotificationsController < ApplicationController
 
       notifications = notifications.where(read: false) if params[:filter] == "unread"
 
       total_rows = notifications.dup.count
       notifications = notifications.offset(offset).limit(60)
-      notifications = filter_inaccessible_notifications(notifications)
+      notifications =
+        Notification.filter_inaccessible_topic_notifications(current_user.guardian, notifications)
       render_json_dump(
         notifications: serialize_data(notifications, NotificationSerializer),
         total_rows_notifications: total_rows,
         seen_notification_id: user.seen_notification_id,
         load_more_notifications:
@@ -153,12 +155,6 @@ class NotificationsController < ApplicationController
   end
 
   def render_notification
     render_json_dump(NotificationSerializer.new(@notification, scope: guardian, root: false))
   end
-
-  def filter_inaccessible_notifications(notifications)
-    topic_ids = notifications.map { |n| n.topic_id }.compact.uniq
-    accessible_topic_ids = guardian.can_see_topic_ids(topic_ids: topic_ids)
-    notifications.select { |n| n.topic_id.blank? || accessible_topic_ids.include?(n.topic_id) }
-  end
 end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 968911f2a019..238ec7d9639e 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -1876,15 +1876,11 @@ class UsersController < ApplicationController
     if !current_user.username_equals_to?(params[:username])
       raise Discourse::InvalidAccess.new("username doesn't match current_user's username")
     end
 
     reminder_notifications =
-      Notification
-        .for_user_menu(current_user.id, limit: USER_MENU_LIST_LIMIT)
-        .unread
-        .where(notification_type: Notification.types[:bookmark_reminder])
-
+      BookmarkQuery.new(user: current_user).unread_notifications(limit: USER_MENU_LIST_LIMIT)
     if reminder_notifications.size < USER_MENU_LIST_LIMIT
       exclude_bookmark_ids =
         reminder_notifications.filter_map { |notification| notification.data_hash[:bookmark_id] }
 
       bookmark_list =
diff --git a/app/models/notification.rb b/app/models/notification.rb
index 3673a3798f88..91c506a28dd0 100644
--- a/app/models/notification.rb
+++ b/app/models/notification.rb
@@ -225,10 +225,16 @@ class Notification < ActiveRecord::Base
   # public then turns private.
   def self.remove_for(user_id, topic_id)
     Notification.where(user_id: user_id, topic_id: topic_id).delete_all
   end
 
+  def self.filter_inaccessible_topic_notifications(guardian, notifications)
+    topic_ids = notifications.map { |n| n.topic_id }.compact.uniq
+    accessible_topic_ids = guardian.can_see_topic_ids(topic_ids: topic_ids)
+    notifications.select { |n| n.topic_id.blank? || accessible_topic_ids.include?(n.topic_id) }
+  end
+
   # Be wary of calling this frequently. O(n) JSON parsing can suck.
   def data_hash
     @data_hash ||=
       begin
         return {} if data.blank?
diff --git a/app/services/post_bookmarkable.rb b/app/services/post_bookmarkable.rb
index 97086d9ba409..4769b4224f25 100644
--- a/app/services/post_bookmarkable.rb
+++ b/app/services/post_bookmarkable.rb
@@ -10,11 +10,11 @@ class PostBookmarkable < BaseBookmarkable
   def self.serializer
     UserPostBookmarkSerializer
   end
 
   def self.preload_associations
-    [{ topic: [:tags] }, :user]
+    [{ topic: %i[tags category] }, :user]
   end
 
   def self.list_query(user, guardian)
     topics = Topic.listable_topics.secured(guardian)
     pms = Topic.private_messages_for_user(user)
@@ -52,11 +52,12 @@ class PostBookmarkable < BaseBookmarkable
       },
     )
   end
 
   def self.reminder_conditions(bookmark)
-    bookmark.bookmarkable.present? && bookmark.bookmarkable.topic.present?
+    bookmark.bookmarkable.present? && bookmark.bookmarkable.topic.present? &&
+      self.can_see?(bookmark.user.guardian, bookmark)
   end
 
   def self.can_see?(guardian, bookmark)
     guardian.can_see_post?(bookmark.bookmarkable)
   end
diff --git a/app/services/topic_bookmarkable.rb b/app/services/topic_bookmarkable.rb
index f79af4c07c4f..02e092584a97 100644
--- a/app/services/topic_bookmarkable.rb
+++ b/app/services/topic_bookmarkable.rb
@@ -10,11 +10,11 @@ class TopicBookmarkable < BaseBookmarkable
   def self.serializer
     UserTopicBookmarkSerializer
   end
 
   def self.preload_associations
-    [:tags, { first_post: :user }]
+    [:category, :tags, { first_post: :user }]
   end
 
   def self.perform_custom_preload!(topic_bookmarks, guardian)
     topics = topic_bookmarks.map(&:bookmarkable)
     topic_user_lookup = TopicUser.lookup_for(guardian.user, topics)
@@ -56,11 +56,11 @@ class TopicBookmarkable < BaseBookmarkable
       },
     )
   end
 
   def self.reminder_conditions(bookmark)
-    bookmark.bookmarkable.present?
+    bookmark.bookmarkable.present? && self.can_see?(bookmark.user.guardian, bookmark)
   end
 
   def self.can_see?(guardian, bookmark)
     guardian.can_see_topic?(bookmark.bookmarkable)
   end
diff --git a/lib/bookmark_query.rb b/lib/bookmark_query.rb
index 7624f0113691..dd066f6bd2ab 100644
--- a/lib/bookmark_query.rb
+++ b/lib/bookmark_query.rb
@@ -86,6 +86,30 @@ class BookmarkQuery
     results = results.limit(@per_page).to_a
 
     BookmarkQuery.preload(results, self)
     results
   end
+
+  def unread_notifications(limit: 20)
+    reminder_notifications =
+      Notification
+        .for_user_menu(@user.id, limit: [limit, 100].min)
+        .unread
+        .where(notification_type: Notification.types[:bookmark_reminder])
+
+    # We preload associations like we do above for the list to avoid
+    # N1s in the can_see? guardian calls for each bookmark.
+    bookmarks =
+      Bookmark.where(
+        id: reminder_notifications.map { |n| n.data_hash[:bookmark_id] }.compact,
+        user: @user,
+      )
+    BookmarkQuery.preload(bookmarks, self)
+
+    reminder_notifications.select do |n|
+      bookmark = bookmarks.find { |bm| bm.id == n.data_hash[:bookmark_id] }
+      next if bookmark.blank?
+      bookmarkable = Bookmark.registered_bookmarkable_from_type(bookmark.bookmarkable_type)
+      bookmarkable.can_see?(@guardian, bookmark)
+    end
+  end
 end
diff --git a/plugins/chat/lib/chat/message_bookmarkable.rb b/plugins/chat/lib/chat/message_bookmarkable.rb
index a759aef1209e..4a9b20256797 100644
--- a/plugins/chat/lib/chat/message_bookmarkable.rb
+++ b/plugins/chat/lib/chat/message_bookmarkable.rb
@@ -9,11 +9,11 @@ module Chat
     def self.serializer
       Chat::UserMessageBookmarkSerializer
     end
 
     def self.preload_associations
-      [:chat_channel]
+      [{ chat_channel: :chatable }]
     end
 
     def self.list_query(user, guardian)
       accessible_channel_ids = Chat::ChannelFetcher.all_secured_channel_ids(guardian)
       return if accessible_channel_ids.empty?
@@ -56,11 +56,12 @@ module Chat
         },
       )
     end
 
     def self.reminder_conditions(bookmark)
-      bookmark.bookmarkable.present? && bookmark.bookmarkable.chat_channel.present?
+      bookmark.bookmarkable.present? && bookmark.bookmarkable.chat_channel.present? &&
+        self.can_see?(bookmark.user.guardian, bookmark)
     end
 
     def self.can_see?(guardian, bookmark)
       guardian.can_join_chat_channel?(bookmark.bookmarkable.chat_channel)
     end
diff --git a/plugins/chat/spec/lib/chat/message_bookmarkable_spec.rb b/plugins/chat/spec/lib/chat/message_bookmarkable_spec.rb
index f5d050dcf77d..d2030004322d 100644
--- a/plugins/chat/spec/lib/chat/message_bookmarkable_spec.rb
+++ b/plugins/chat/spec/lib/chat/message_bookmarkable_spec.rb
@@ -117,10 +117,17 @@ describe Chat::MessageBookmarkable do
       bookmark1.reload
       bookmark1.bookmarkable.chat_channel.trash!
       bookmark1.reload
       expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(false)
     end
+
+    it "cannot send reminder if the user cannot access the channel" do
+      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(true)
+      bookmark1.bookmarkable.update!(chat_channel: Fabricate(:private_category_channel))
+      bookmark1.reload
+      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(false)
+    end
   end
 
   describe "#reminder_handler" do
     it "creates a notification for the user with the correct details" do
       expect { registered_bookmarkable.send_reminder_notification(bookmark1) }.to change {
diff --git a/plugins/chat/spec/requests/core_ext/users_controller_spec.rb b/plugins/chat/spec/requests/core_ext/users_controller_spec.rb
index 8e9d060589d3..b7ff5445fd2c 100644
--- a/plugins/chat/spec/requests/core_ext/users_controller_spec.rb
+++ b/plugins/chat/spec/requests/core_ext/users_controller_spec.rb
@@ -20,6 +20,35 @@ describe UsersController do
       expect(response.status).to eq(200)
       membership = Chat::UserChatChannelMembership.find_by(user: user, chat_channel: channel)
       expect(membership.following).to eq(true)
     end
   end
+
+  describe "#user_menu_bookmarks" do
+    fab!(:chatters) { Fabricate(:group) }
+    let(:current_user) { Fabricate(:user, group_ids: [chatters.id]) }
+    let(:bookmark_message) { Fabricate(:chat_message) }
+    let(:bookmark_user) { current_user }
+
+    before do
+      register_test_bookmarkable(Chat::MessageBookmarkable)
+      SiteSetting.chat_allowed_groups = [chatters]
+      sign_in(current_user)
+    end
+
+    it "does not return any unread notifications for chat bookmarks that the user no longer has access to" do
+      bookmark_with_reminder =
+        Fabricate(:bookmark, user: current_user, bookmarkable: bookmark_message)
+      BookmarkReminderNotificationHandler.new(bookmark_with_reminder).send_notification
+
+      bookmark_with_reminder.bookmarkable.update!(
+        chat_channel: Fabricate(:private_category_channel),
+      )
+
+      get "/u/#{current_user.username}/user-menu-bookmarks"
+      expect(response.status).to eq(200)
+
+      notifications = response.parsed_body["notifications"]
+      expect(notifications.size).to eq(0)
+    end
+  end
 end
diff --git a/spec/lib/bookmark_query_spec.rb b/spec/lib/bookmark_query_spec.rb
index d54c10d07d25..3bac9c55ca32 100644
--- a/spec/lib/bookmark_query_spec.rb
+++ b/spec/lib/bookmark_query_spec.rb
@@ -103,10 +103,12 @@ RSpec.describe BookmarkQuery do
       end
 
       context "with custom bookmarkable fitering" do
         before { register_test_bookmarkable }
 
+        after { DiscoursePluginRegistry.reset! }
+
         let!(:bookmark5) do
           Fabricate(:bookmark, user: user, bookmarkable: Fabricate(:user, username: "bookmarkking"))
         end
 
         it "allows searching bookmarkables by fields in other tables" do
diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb
index caa114643586..60a40f49fedb 100644
--- a/spec/requests/users_controller_spec.rb
+++ b/spec/requests/users_controller_spec.rb
@@ -6920,12 +6920,11 @@ RSpec.describe UsersController do
 
         get "/u/#{user.username}/user-menu-bookmarks"
         expect(response.status).to eq(200)
 
         notifications = response.parsed_body["notifications"]
-        expect(notifications.size).to eq(1)
-        expect(notifications.first["data"]["bookmark_id"]).to be_nil
+        expect(notifications.size).to eq(0)
 
         bookmarks = response.parsed_body["bookmarks"]
         expect(bookmarks.map { |bookmark| bookmark["id"] }).to contain_exactly(
           bookmark_with_reminder.id,
           bookmark_without_reminder.id,
@@ -6968,10 +6967,28 @@ RSpec.describe UsersController do
         expect(notifications.size).to eq(2)
 
         bookmarks = response.parsed_body["bookmarks"]
         expect(bookmarks.size).to eq(1)
       end
+
+      it "does not return any unread notifications for bookmarks that the user no longer has access to" do
+        bookmark_with_reminder2 = Fabricate(:bookmark, user: user, bookmarkable: Fabricate(:post))
+        TopicUser.change(user.id, bookmark_with_reminder2.bookmarkable.topic, total_msecs_viewed: 1)
+        BookmarkReminderNotificationHandler.new(bookmark_with_reminder2).send_notification
+
+        bookmark_with_reminder2.bookmarkable.topic.update!(
+          archetype: Archetype.private_message,
+          category: nil,
+        )
+
+        get "/u/#{user.username}/user-menu-bookmarks"
+        expect(response.status).to eq(200)
+
+        notifications = response.parsed_body["notifications"]
+        expect(notifications.size).to eq(1)
+        expect(notifications.first["data"]["bookmark_id"]).to eq(bookmark_with_reminder.id)
+      end
     end
   end
 
   describe "#user_menu_messages" do
     fab!(:group1) { Fabricate(:group, has_messages: true, users: [user]) }
diff --git a/spec/services/post_bookmarkable_spec.rb b/spec/services/post_bookmarkable_spec.rb
index dbd1d8855ca5..234a80eb1933 100644
--- a/spec/services/post_bookmarkable_spec.rb
+++ b/spec/services/post_bookmarkable_spec.rb
@@ -99,10 +99,17 @@ RSpec.describe PostBookmarkable do
       bookmark1.reload
       bookmark1.bookmarkable.topic.trash!
       bookmark1.reload
       expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(false)
     end
+
+    it "cannot send reminder if the user cannot access the topic" do
+      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(true)
+      bookmark1.bookmarkable.topic.update!(category: private_category)
+      bookmark1.reload
+      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(false)
+    end
   end
 
   describe "#reminder_handler" do
     it "creates a notification for the user with the correct details" do
       expect { registered_bookmarkable.send_reminder_notification(bookmark1) }.to change {
diff --git a/spec/services/topic_bookmarkable_spec.rb b/spec/services/topic_bookmarkable_spec.rb
index b5aa76859744..594bc6a11826 100644
--- a/spec/services/topic_bookmarkable_spec.rb
+++ b/spec/services/topic_bookmarkable_spec.rb
@@ -95,10 +95,17 @@ RSpec.describe TopicBookmarkable do
       expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(true)
       bookmark1.bookmarkable.trash!
       bookmark1.reload
       expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(false)
     end
+
+    it "cannot send reminder if the user cannot access the topic" do
+      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(true)
+      bookmark1.bookmarkable.update!(category: private_category)
+      bookmark1.reload
+      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(false)
+    end
   end
 
   describe "#reminder_handler" do
     it "creates a notification for the user with the correct details" do
       expect { registered_bookmarkable.send_reminder_notification(bookmark1) }.to change {

Vulnerable code:       notifications = filter_inaccessible_notifications(notifications)
      notifications = filter_inaccessible_notifications(notifications)

  def filter_inaccessible_notifications(notifications)
    topic_ids = notifications.map { |n| n.topic_id }.compact.uniq
    accessible_topic_ids = guardian.can_see_topic_ids(topic_ids: topic_ids)
    notifications.select { |n| n.topic_id.blank? || accessible_topic_ids.include?(n.topic_id) }
  end
      Notification
        .for_user_menu(current_user.id, limit: USER_MENU_LIST_LIMIT)
        .unread
        .where(notification_type: Notification.types[:bookmark_reminder])

    [{ topic: [:tags] }, :user]
    bookmark.bookmarkable.present? && bookmark.bookmarkable.topic.present?
    [:tags, { first_post: :user }]
    bookmark.bookmarkable.present?
      [:chat_channel]
      bookmark.bookmarkable.present? && bookmark.bookmarkable.chat_channel.present?
        expect(notifications.size).to eq(1)
        expect(notifications.first["data"]["bookmark_id"]).to be_nil
Fixed code:       notifications =
        Notification.filter_inaccessible_topic_notifications(current_user.guardian, notifications)
      notifications =
        Notification.filter_inaccessible_topic_notifications(current_user.guardian, notifications)
      BookmarkQuery.new(user: current_user).unread_notifications(limit: USER_MENU_LIST_LIMIT)
  def self.filter_inaccessible_topic_notifications(guardian, notifications)
    topic_ids = notifications.map { |n| n.topic_id }.compact.uniq
    accessible_topic_ids = guardian.can_see_topic_ids(topic_ids: topic_ids)
    notifications.select { |n| n.topic_id.blank? || accessible_topic_ids.include?(n.topic_id) }
  end

    [{ topic: %i[tags category] }, :user]
    bookmark.bookmarkable.present? && bookmark.bookmarkable.topic.present? &&
      self.can_see?(bookmark.user.guardian, bookmark)
    [:category, :tags, { first_post: :user }]
    bookmark.bookmarkable.present? && self.can_see?(bookmark.user.guardian, bookmark)

  def unread_notifications(limit: 20)
    reminder_notifications =
      Notification
        .for_user_menu(@user.id, limit: [limit, 100].min)
        .unread
        .where(notification_type: Notification.types[:bookmark_reminder])

    # We preload associations like we do above for the list to avoid
    # N1s in the can_see? guardian calls for each bookmark.
    bookmarks =
      Bookmark.where(
        id: reminder_notifications.map { |n| n.data_hash[:bookmark_id] }.compact,
        user: @user,
      )
    BookmarkQuery.preload(bookmarks, self)

    reminder_notifications.select do |n|
      bookmark = bookmarks.find { |bm| bm.id == n.data_hash[:bookmark_id] }
      next if bookmark.blank?
      bookmarkable = Bookmark.registered_bookmarkable_from_type(bookmark.bookmarkable_type)
      bookmarkable.can_see?(@guardian, bookmark)
    end
  end
      [{ chat_channel: :chatable }]
      bookmark.bookmarkable.present? && bookmark.bookmarkable.chat_channel.present? &&
        self.can_see?(bookmark.user.guardian, bookmark)

    it "cannot send reminder if the user cannot access the channel" do
      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(true)
      bookmark1.bookmarkable.update!(chat_channel: Fabricate(:private_category_channel))
      bookmark1.reload
      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(false)
    end

  describe "#user_menu_bookmarks" do
    fab!(:chatters) { Fabricate(:group) }
    let(:current_user) { Fabricate(:user, group_ids: [chatters.id]) }
    let(:bookmark_message) { Fabricate(:chat_message) }
    let(:bookmark_user) { current_user }

    before do
      register_test_bookmarkable(Chat::MessageBookmarkable)
      SiteSetting.chat_allowed_groups = [chatters]
      sign_in(current_user)
    end

    it "does not return any unread notifications for chat bookmarks that the user no longer has access to" do
      bookmark_with_reminder =
        Fabricate(:bookmark, user: current_user, bookmarkable: bookmark_message)
      BookmarkReminderNotificationHandler.new(bookmark_with_reminder).send_notification

      bookmark_with_reminder.bookmarkable.update!(
        chat_channel: Fabricate(:private_category_channel),
      )

      get "/u/#{current_user.username}/user-menu-bookmarks"
      expect(response.status).to eq(200)

      notifications = response.parsed_body["notifications"]
      expect(notifications.size).to eq(0)
    end
  end
        after { DiscoursePluginRegistry.reset! }

        expect(notifications.size).to eq(0)

      it "does not return any unread notifications for bookmarks that the user no longer has access to" do
        bookmark_with_reminder2 = Fabricate(:bookmark, user: user, bookmarkable: Fabricate(:post))
        TopicUser.change(user.id, bookmark_with_reminder2.bookmarkable.topic, total_msecs_viewed: 1)
        BookmarkReminderNotificationHandler.new(bookmark_with_reminder2).send_notification

        bookmark_with_reminder2.bookmarkable.topic.update!(
          archetype: Archetype.private_message,
          category: nil,
        )

        get "/u/#{user.username}/user-menu-bookmarks"
        expect(response.status).to eq(200)

        notifications = response.parsed_body["notifications"]
        expect(notifications.size).to eq(1)
        expect(notifications.first["data"]["bookmark_id"]).to eq(bookmark_with_reminder.id)
      end

    it "cannot send reminder if the user cannot access the topic" do
      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(true)
      bookmark1.bookmarkable.topic.update!(category: private_category)
      bookmark1.reload
      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(false)
    end

    it "cannot send reminder if the user cannot access the topic" do
      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(true)
      bookmark1.bookmarkable.update!(category: private_category)
      bookmark1.reload
      expect(registered_bookmarkable.can_send_reminder?(bookmark1)).to eq(false)
    end