SECURITY: Don't allow moderators to list PMs of all groups.

* Also return 404 when a user is trying to list PMs of a group that
cannot be accessed by the user.
This commit is contained in:
Guo Xiang Tan 2020-09-08 10:31:28 +08:00 committed by Régis Hanol
parent 265eb1c7f9
commit 1f6e8b642d
4 changed files with 54 additions and 29 deletions

View File

@ -143,22 +143,37 @@ class ListController < ApplicationController
end end
def self.generate_message_route(action) def self.generate_message_route(action)
define_method("#{action}") do case action
if action == :private_messages_tag && !guardian.can_tag_pms? when :private_messages_tag
raise Discourse::NotFound define_method("#{action}") do
raise Discourse::NotFound if !guardian.can_tag_pms?
message_route(action)
end end
when :private_messages_group, :private_messages_group_archive
define_method("#{action}") do
group = Group.find_by(name: params[:group_name])
raise Discourse::NotFound unless guardian.can_see_group_messages?(group)
list_opts = build_topic_list_options message_route(action)
target_user = fetch_user_from_params({ include_inactive: current_user.try(:staff?) }, [:user_stat, :user_option]) end
guardian.ensure_can_see_private_messages!(target_user.id) else
list = generate_list_for(action.to_s, target_user, list_opts) define_method("#{action}") do
url_prefix = "topics" message_route(action)
list.more_topics_url = construct_url_with(:next, list_opts, url_prefix) end
list.prev_topics_url = construct_url_with(:prev, list_opts, url_prefix)
respond_with_list(list)
end end
end end
def message_route(action)
target_user = fetch_user_from_params({ include_inactive: current_user.try(:staff?) }, [:user_stat, :user_option])
guardian.ensure_can_see_private_messages!(target_user.id)
list_opts = build_topic_list_options
list = generate_list_for(action.to_s, target_user, list_opts)
url_prefix = "topics"
list.more_topics_url = construct_url_with(:next, list_opts, url_prefix)
list.prev_topics_url = construct_url_with(:prev, list_opts, url_prefix)
respond_with_list(list)
end
%i{ %i{
private_messages private_messages
private_messages_sent private_messages_sent

View File

@ -532,22 +532,15 @@ class TopicQuery
result = Topic.includes(:tags) result = Topic.includes(:tags)
if type == :group if type == :group
result = result.includes(:allowed_users) result = result
result = result.where(" .includes(:allowed_users)
topics.id IN ( .joins("INNER JOIN topic_allowed_groups tag ON tag.topic_id = topics.id AND tag.group_id IN (SELECT id FROM groups WHERE name ilike '#{sanitize_sql_array([@options[:group_name]])}')")
SELECT topic_id FROM topic_allowed_groups
WHERE ( unless user.admin?
group_id IN ( result = result.joins("INNER JOIN group_users gu ON gu.group_id = tag.group_id AND gu.user_id = #{user.id.to_i}")
SELECT group_id end
FROM group_users
WHERE user_id = #{user.id.to_i} result
OR #{user.staff?}
)
)
AND group_id IN (SELECT id FROM groups WHERE name ilike ?)
)",
@options[:group_name]
)
elsif type == :user elsif type == :user
result = result.includes(:allowed_users) result = result.includes(:allowed_users)
result = result.where("topics.id IN (SELECT topic_id FROM topic_allowed_users WHERE user_id = #{user.id.to_i})") result = result.where("topics.id IN (SELECT topic_id FROM topic_allowed_users WHERE user_id = #{user.id.to_i})")

View File

@ -1097,7 +1097,15 @@ describe TopicQuery do
expect(topics).to contain_exactly(group_message) expect(topics).to contain_exactly(group_message)
end end
it 'should return the right list for a user not part of the group' do it "should not allow a moderator not part of the group to view the group's messages" do
topics = TopicQuery.new(nil, group_name: group.name)
.list_private_messages_group(Fabricate(:moderator))
.topics
expect(topics).to eq([])
end
it "should not allow a user not part of the group to view the group's messages" do
topics = TopicQuery.new(nil, group_name: group.name) topics = TopicQuery.new(nil, group_name: group.name)
.list_private_messages_group(Fabricate(:user)) .list_private_messages_group(Fabricate(:user))
.topics .topics

View File

@ -183,8 +183,17 @@ RSpec.describe ListController do
describe 'with unicode_usernames' do describe 'with unicode_usernames' do
before { SiteSetting.unicode_usernames = false } before { SiteSetting.unicode_usernames = false }
it 'should return the right response when user does not belong to group' do
Fabricate(:private_message_topic, allowed_groups: [group])
group.remove(user)
get "/topics/private-messages-group/#{user.username}/#{group.name}.json"
expect(response.status).to eq(404)
end
it 'should return the right response' do it 'should return the right response' do
group.add(user)
topic = Fabricate(:private_message_topic, allowed_groups: [group]) topic = Fabricate(:private_message_topic, allowed_groups: [group])
get "/topics/private-messages-group/#{user.username}/#{group.name}.json" get "/topics/private-messages-group/#{user.username}/#{group.name}.json"