SECURITY: Ensure users can see the topic before setting a topic timer. (#10841)

SECURITY: Ensure users can see the topic before setting a topic timer. (#10841)

diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb
index 9b45385..07a2a6b 100644
--- a/app/controllers/topics_controller.rb
+++ b/app/controllers/topics_controller.rb
@@ -453,6 +453,7 @@ class TopicsController < ApplicationController
     params.require(:duration) if based_on_last_post
 
     topic = Topic.find_by(id: params[:topic_id])
+    guardian.ensure_can_see!(topic)
     guardian.ensure_can_moderate!(topic)
 
     options = {
diff --git a/app/jobs/regular/publish_topic_to_category.rb b/app/jobs/regular/publish_topic_to_category.rb
index 79df028..ca0010e 100644
--- a/app/jobs/regular/publish_topic_to_category.rb
+++ b/app/jobs/regular/publish_topic_to_category.rb
@@ -9,6 +9,8 @@ module Jobs
       topic = topic_timer.topic
       return if topic.blank?
 
+      return unless Guardian.new(topic_timer.user).can_see?(topic)
+
       TopicTimer.transaction do
         TopicPublisher.new(topic, Discourse.system_user, topic_timer.category_id).publish!
       end
diff --git a/spec/jobs/publish_topic_to_category_spec.rb b/spec/jobs/publish_topic_to_category_spec.rb
index 559065f..7ec605e 100644
--- a/spec/jobs/publish_topic_to_category_spec.rb
+++ b/spec/jobs/publish_topic_to_category_spec.rb
@@ -67,6 +67,8 @@ RSpec.describe Jobs::PublishTopicToCategory do
           .to change { topic.private_message? }.to(true)
       end
 
+      topic.allowed_users << topic.public_topic_timer.user
+
       now = freeze_time
 
       message = MessageBus.track_publish do
@@ -85,6 +87,35 @@ RSpec.describe Jobs::PublishTopicToCategory do
       expect(message.data[:reload_topic]).to be_present
       expect(message.data[:refresh_stream]).to be_present
     end
+
+    it "does nothing if the user can't see the PM" do
+      non_participant_TL4_user = Fabricate(:trust_level_4)
+      topic.convert_to_private_message(Discourse.system_user)
+      timer = topic.public_topic_timer
+      timer.update!(user: non_participant_TL4_user)
+
+      described_class.new.execute(topic_timer_id: topic.public_topic_timer.id)
+
+      topic.reload
+      expect(topic.private_message?).to eq(true)
+      expect(topic.category).not_to eq(another_category)
+    end
+
+    it "works if the user can see the PM" do
+      tl4_user = Fabricate(:trust_level_4)
+      topic.convert_to_private_message(Discourse.system_user)
+
+      topic.allowed_users << tl4_user
+
+      timer = topic.public_topic_timer
+      timer.update!(user: tl4_user)
+
+      described_class.new.execute(topic_timer_id: topic.public_topic_timer.id)
+
+      topic.reload
+      expect(topic.private_message?).to eq(false)
+      expect(topic.category).to eq(another_category)
+    end
   end
 
   describe 'when new category has a default auto-close' do
diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb
index 6de7c1f..c918181 100644
--- a/spec/requests/topics_controller_spec.rb
+++ b/spec/requests/topics_controller_spec.rb
@@ -3028,6 +3028,23 @@ RSpec.describe TopicsController do
         end
       end
     end
+
+    context 'when logged in as a TL4 user' do
+      it "raises an error if the user can't see the topic" do
+        user.update!(trust_level: TrustLevel[4])
+        sign_in(user)
+
+        pm_topic = Fabricate(:private_message_topic)
+
+        post "/t/#{pm_topic.id}/timer.json", params: {
+          time: '24',
+          status_type: TopicTimer.types[1]
+        }
+
+        expect(response.status).to eq(403)
+        expect(response.parsed_body["error_type"]).to eq('invalid_access')
+      end
+    end
   end
 
   describe '#invite' do

GitHub sha: a8c47e7c

1 Like

This commit appears in #10841 which was approved by eviltrout. It was merged by romanrizzi.

It feels like a bug to me that Guardian#can_moderate? does not check if the user can see the topic. Can I strange that a user can moderate a topic he can’t see.

1 Like

DEV: Users must be able to see a topic to moderate it. (#10906)