FIX: Introduce Guardian::BasicUser for oneboxing checks (#24681)

Through internal discussion, it has become clear that
we need a conceptual Guardian user that bridges the
gap between anon users and a logged in forum user with
an absolute baseline level of access to public topics,
which can be used in cases where:

1. Automated systems are running which shouldn't see any
   private data
1. A baseline level of user access is needed

In this case we are fixing the latter; when oneboxing a local
topic, and we are linking to a topic in another category from
the current one, we need to operate off a baseline level of
access, since not all users have access to the same categories,
and we don't want e.g. editing a post with an internal link to
expose sensitive internal information.
This commit is contained in:
Martin Brennan
2023-12-05 09:25:23 +10:00
committed by GitHub
parent 7756c210da
commit de983796e1
4 changed files with 166 additions and 5 deletions

View File

@@ -932,4 +932,92 @@ RSpec.describe Oneboxer do
expect(Oneboxer.preview(url)).to eq("Custom Onebox for Wizard")
end
end
describe ".local_topic" do
fab!(:topic)
fab!(:user)
let(:url) { topic.url }
let(:route) { Discourse.route_for(url) }
context "when user_id is not provided" do
let(:opts) { {} }
it "returns nil if the topic is a private message" do
topic.update!(archetype: Archetype.private_message, category: nil)
expect(Oneboxer.local_topic(url, route, opts)).to eq(nil)
end
it "returns nil if basic user cannot see the topic" do
topic.update!(category: Fabricate(:private_category, group: Fabricate(:group)))
expect(Oneboxer.local_topic(url, route, opts)).to eq(nil)
end
it "returns topic if basic user can see the topic" do
expect(Oneboxer.local_topic(url, route, opts)).to eq(topic)
end
end
context "when user_id is provided" do
context "when category_id is provided" do
fab!(:category)
let(:opts) { { category_id: category.id, user_id: user.id } }
before { topic.update!(category: category) }
it "returns nil if the user cannot see the category" do
category.update!(read_restricted: true)
expect(Oneboxer.local_topic(url, route, opts)).to eq(nil)
end
it "returns the topic if the user can see the category" do
expect(Oneboxer.local_topic(url, route, opts)).to eq(topic)
end
it "returns nil if basic user users cannot see the topic" do
topic.update!(category: Fabricate(:private_category, group: Fabricate(:group)))
expect(Oneboxer.local_topic(url, route, opts)).to eq(nil)
end
it "returns nil if the topic is a private message" do
topic.update!(archetype: Archetype.private_message, category: nil)
expect(Oneboxer.local_topic(url, route, opts)).to eq(nil)
end
context "when category_id is mismatched" do
fab!(:other_category) { Fabricate(:private_category, group: Fabricate(:group)) }
before { topic.update!(category: other_category) }
it "returns nil if the basic user cannot see the topic" do
expect(Oneboxer.local_topic(url, route, opts)).to eq(nil)
end
it "returns topic if the basic user can see the topic" do
other_category.update!(read_restricted: false)
expect(Oneboxer.local_topic(url, route, opts)).to eq(topic)
end
end
end
context "when topic_id is provided" do
let(:opts) { { topic_id: topic.id, user_id: user.id } }
it "returns nil if the user cannot see the topic" do
topic.update!(category: Fabricate(:private_category, group: Fabricate(:group)))
expect(Oneboxer.local_topic(url, route, opts)).to eq(nil)
end
it "returns the topic if the user can see the topic" do
expect(Oneboxer.local_topic(url, route, opts)).to eq(topic)
end
it "returns nil if the topic is a private message" do
topic.update!(archetype: Archetype.private_message, category: nil)
expect(Oneboxer.local_topic(url, route, opts)).to eq(nil)
end
end
end
end
end