SECURITY: Update to exclude tag topic filter (#20006)

Ignores tags specified in exclude_tag topics param that a user does not
have access to.

Co-authored-by: Blake Erickson <o.blakeerickson@gmail.com>
This commit is contained in:
Bianca Nenciu 2023-01-25 18:56:22 +02:00 committed by GitHub
parent 105fee978d
commit f55e0fe791
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 19 additions and 8 deletions

View File

@ -735,14 +735,17 @@ class TopicQuery
result = result.where.not(id: TopicTag.distinct.pluck(:topic_id)) result = result.where.not(id: TopicTag.distinct.pluck(:topic_id))
end end
result = result.where(<<~SQL, name: @options[:exclude_tag]) if @options[:exclude_tag].present? if @options[:exclude_tag].present? &&
topics.id NOT IN ( !DiscourseTagging.hidden_tag_names(@guardian).include?(@options[:exclude_tag])
SELECT topic_tags.topic_id result = result.where(<<~SQL, name: @options[:exclude_tag])
FROM topic_tags topics.id NOT IN (
INNER JOIN tags ON tags.id = topic_tags.tag_id SELECT topic_tags.topic_id
WHERE tags.name = :name FROM topic_tags
) INNER JOIN tags ON tags.id = topic_tags.tag_id
SQL WHERE tags.name = :name
)
SQL
end
end end
result = apply_ordering(result, options) result = apply_ordering(result, options)

View File

@ -409,6 +409,9 @@ RSpec.describe TopicQuery do
fab!(:tagged_topic3) { Fabricate(:topic, tags: [tag, other_tag]) } fab!(:tagged_topic3) { Fabricate(:topic, tags: [tag, other_tag]) }
fab!(:tagged_topic4) { Fabricate(:topic, tags: [uppercase_tag]) } fab!(:tagged_topic4) { Fabricate(:topic, tags: [uppercase_tag]) }
fab!(:no_tags_topic) { Fabricate(:topic) } fab!(:no_tags_topic) { Fabricate(:topic) }
fab!(:tag_group) do
Fabricate(:tag_group, permissions: { "staff" => 1 }, tag_names: [other_tag.name])
end
let(:synonym) { Fabricate(:tag, target_tag: tag, name: "synonym") } let(:synonym) { Fabricate(:tag, target_tag: tag, name: "synonym") }
it "excludes a tag if desired" do it "excludes a tag if desired" do
@ -416,6 +419,11 @@ RSpec.describe TopicQuery do
expect(topics.any? { |t| t.tags.include?(tag) }).to eq(false) expect(topics.any? { |t| t.tags.include?(tag) }).to eq(false)
end end
it "does not exclude a tagged topic without permission" do
topics = TopicQuery.new(user, exclude_tag: other_tag.name).list_latest.topics
expect(topics.map(&:id)).to include(tagged_topic2.id)
end
it "returns topics with the tag when filtered to it" do it "returns topics with the tag when filtered to it" do
expect(TopicQuery.new(moderator, tags: tag.name).list_latest.topics).to contain_exactly( expect(TopicQuery.new(moderator, tags: tag.name).list_latest.topics).to contain_exactly(
tagged_topic1, tagged_topic1,