discourse/plugins/chat/spec/lib/chat/guardian_extensions_spec.rb
Nat ea2971a5aa SECURITY: Chat authorization and disclosure fixes
This PR contains a few chat patches:

- https://patch.discourse.org/patch-triage/1081
   - Read-only category users could create chat threads via `Chat::CreateThread`. Tightened `can_create_thread_in_channel` to require `can_join_chat_channel?` for category channels and the full `Chat::Channel::Policy::MessageCreation` for DMs, plus a 403 handler for the failed policy.
   - `channel_threads_controller.rb`, `create_thread.rb`, `channel_threads_controller_spec.rb`, `create_thread_spec.rb`

- https://patch.discourse.org/patch-triage/1086
   - A user could restore their own self-deleted chat message after losing access to the channel (group revoked, DM membership removed). Added a `can_preview_chat_channel?` short-circuit inside the self-deletion branch of `can_restore_chat?`.
   - `guardian_extensions.rb`, `guardian_extensions_spec.rb`, `channel_messages_controller_spec.rb`

- https://patch.discourse.org/patch-triage/1049
     - Reviewable chat messages exposed unrelated current `last_message` content of a flagged DM channel to moderators (who aren't members). Added an
  `include_last_message?` predicate on `Chat::ChannelSerializer` gated by `can_preview_chat_channel?`, which is false for DM non-members but stays true
  for read-only category members so they keep seeing channel previews.
     - `channel_serializer.rb`, `channel_serializer_spec.rb`, `reviewables_controller_spec.rb`

- https://patch.discourse.org/patch-triage/1047 + https://patch.discourse.org/patch-triage/1053
     - The calendar event API leaked the chat channel block (and its `last_message` body) to anonymous viewers and any user without chat access. Gated
  `include_channel?` with `can_chat? && can_preview_chat_channel?` (excludes anonymous and users not in `chat_allowed_groups`, while preserving read-only
  category access) and passed membership through to the channel serializer.
     - `discourse-calendar/app/serializers/discourse_post_event/event_serializer.rb`, `discourse-calendar/spec/requests/events_controller_spec.rb`

https://github.com/discourse/discourse/security/advisories/GHSA-rw8j-p2gv-q33w
2026-05-19 00:26:04 +01:00

1054 lines
36 KiB
Ruby
Vendored
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# frozen_string_literal: true
RSpec.describe Chat::GuardianExtensions do
fab!(:chatters, :group)
fab!(:user) { Fabricate(:user, group_ids: [chatters.id], refresh_auto_groups: true) }
fab!(:staff) { Fabricate(:admin, refresh_auto_groups: true) }
fab!(:chat_group, :group)
fab!(:channel, :category_channel)
fab!(:dm_channel, :direct_message_channel)
let(:guardian) { Guardian.new(user) }
let(:staff_guardian) { Guardian.new(staff) }
fab!(:private_group_create_post, :group)
fab!(:private_channel) { Fabricate(:private_category_channel, group: private_group_create_post) }
before { SiteSetting.chat_allowed_groups = chatters.id }
describe "#can_chat?" do
context "when the user is not in allowed to chat" do
before { SiteSetting.chat_allowed_groups = "" }
it "cannot chat" do
expect(guardian.can_chat?).to eq(false)
end
context "when the user is a bot" do
let(:guardian) { Discourse.system_user.guardian }
it "can chat" do
expect(guardian.can_chat?).to eq(true)
end
end
context "when user is staff" do
let(:guardian) { staff_guardian }
it "can chat" do
expect(guardian.can_chat?).to eq(true)
end
end
end
context "when user is anonymous" do
let(:guardian) { Guardian.new }
it "cannot chat" do
expect(guardian.can_chat?).to eq(false)
end
end
context "when user is a shadow account" do
fab!(:non_chatter) { Fabricate(:user, refresh_auto_groups: true) }
before { SiteSetting.allow_anonymous_mode = true }
context "when allow_chat_in_anonymous_mode is true" do
before { SiteSetting.allow_chat_in_anonymous_mode = true }
it "allows shadow account to chat if master account can chat" do
anonymous = AnonymousShadowCreator.get(user)
expect(anonymous.id).to be_present
expect(Guardian.new(anonymous).can_chat?).to eq(true)
expect(Guardian.new(user).can_chat?).to eq(true)
end
it "doesn't allow shadow account to chat if master account can not chat" do
anonymous = AnonymousShadowCreator.get(non_chatter)
expect(anonymous.id).to be_present
expect(Guardian.new(anonymous).can_chat?).to eq(false)
expect(Guardian.new(non_chatter).can_chat?).to eq(false)
end
end
context "when allow_chat_in_anonymous_mode is false" do
before { SiteSetting.allow_chat_in_anonymous_mode = false }
it "doesn't allow shadow account to chat even if master account can chat" do
anonymous = AnonymousShadowCreator.get(user)
expect(anonymous.id).to be_present
expect(Guardian.new(anonymous).can_chat?).to eq(false)
expect(Guardian.new(user).can_chat?).to eq(true)
end
it "doesn't allow shadow account to chat if master account can not chat" do
anonymous = AnonymousShadowCreator.get(non_chatter)
expect(anonymous.id).to be_present
expect(Guardian.new(anonymous).can_chat?).to eq(false)
expect(Guardian.new(non_chatter).can_chat?).to eq(false)
end
end
end
it "allows TL1 to chat by default and by extension higher trust levels" do
expect(guardian.can_chat?).to eq(true)
user.change_trust_level!(TrustLevel[3])
expect(guardian.can_chat?).to eq(true)
end
it "allows user in specific group to chat" do
SiteSetting.chat_allowed_groups = chat_group.id
expect(guardian.can_chat?).to eq(false)
chat_group.add(user)
user.reload
expect(guardian.can_chat?).to eq(true)
end
end
describe "chat channel" do
it "only staff can create channels" do
expect(guardian.can_create_chat_channel?).to eq(false)
expect(staff_guardian.can_create_chat_channel?).to eq(true)
end
context "when category channel" do
it "allows staff to edit chat channels" do
expect(guardian.can_edit_chat_channel?(channel)).to eq(false)
expect(staff_guardian.can_edit_chat_channel?(channel)).to eq(true)
end
end
context "when direct message channel" do
context "when member of channel" do
context "when group" do
before do
dm_channel.chatable.update!(group: true)
add_users_to_channel(user, dm_channel)
end
it "allows to edit the channel" do
expect(user.guardian.can_edit_chat_channel?(dm_channel)).to eq(true)
end
end
context "when not group" do
before { dm_channel.add(user) }
it "allows to edit the channel" do
Chat::DirectMessageUser.create(user: user, direct_message: dm_channel.chatable)
expect(user.guardian.can_edit_chat_channel?(dm_channel)).to eq(true)
end
end
end
context "when not member of channel" do
it "doesnt allow to edit the channel" do
expect(user.guardian.can_edit_chat_channel?(dm_channel)).to eq(false)
end
end
end
it "only staff can close chat channels" do
channel.update(status: :open)
expect(guardian.can_change_channel_status?(channel, :closed)).to eq(false)
expect(staff_guardian.can_change_channel_status?(channel, :closed)).to eq(true)
end
it "only staff can open chat channels" do
channel.update(status: :closed)
expect(guardian.can_change_channel_status?(channel, :open)).to eq(false)
expect(staff_guardian.can_change_channel_status?(channel, :open)).to eq(true)
end
it "only staff can archive chat channels" do
channel.update(status: :read_only)
expect(guardian.can_change_channel_status?(channel, :archived)).to eq(false)
expect(staff_guardian.can_change_channel_status?(channel, :archived)).to eq(true)
end
it "only staff can mark chat channels read_only" do
channel.update(status: :open)
expect(guardian.can_change_channel_status?(channel, :read_only)).to eq(false)
expect(staff_guardian.can_change_channel_status?(channel, :read_only)).to eq(true)
end
describe "#can_join_chat_channel?" do
context "for direct message channels" do
fab!(:chatable, :direct_message)
fab!(:channel) { Fabricate(:direct_message_channel, chatable: chatable) }
it "returns false if the user is not part of the direct message" do
expect(guardian.can_join_chat_channel?(channel)).to eq(false)
end
it "returns true if the user is part of the direct message" do
Chat::DirectMessageUser.create!(user: user, direct_message: chatable)
expect(guardian.can_join_chat_channel?(channel)).to eq(true)
end
end
context "for category channel" do
fab!(:group)
fab!(:group_user) { Fabricate(:group_user, group: group, user: user) }
it "returns true if the user can join the category" do
category =
Fabricate(
:private_category,
group: group,
permission_type: CategoryGroup.permission_types[:readonly],
)
channel.update(chatable: category)
guardian = Guardian.new(user)
expect(guardian.can_join_chat_channel?(channel)).to eq(false)
category =
Fabricate(
:private_category,
group: group,
permission_type: CategoryGroup.permission_types[:create_post],
)
channel.update(chatable: category)
guardian = Guardian.new(user)
expect(guardian.can_join_chat_channel?(channel)).to eq(true)
category =
Fabricate(
:private_category,
group: group,
permission_type: CategoryGroup.permission_types[:full],
)
channel.update(chatable: category)
guardian = Guardian.new(user)
expect(guardian.can_join_chat_channel?(channel)).to eq(true)
end
end
end
describe "#can_post_in_chatable?" do
alias_matcher :be_able_to_post_in_chatable, :be_can_post_in_chatable
context "when channel is a category channel" do
context "when post_allowed_category_ids given" do
context "when no chatable given" do
it "returns false" do
expect(guardian).not_to be_able_to_post_in_chatable(
nil,
post_allowed_category_ids: [channel.chatable.id],
)
end
end
context "when user is anonymous" do
it "returns false" do
expect(Guardian.new).not_to be_able_to_post_in_chatable(
channel.chatable,
post_allowed_category_ids: [channel.chatable.id],
)
end
end
context "when user is admin" do
it "returns true" do
guardian = Fabricate(:admin).guardian
expect(guardian).to be_able_to_post_in_chatable(
channel.chatable,
post_allowed_category_ids: [channel.chatable.id],
)
end
end
context "when user is a shadow account" do
fab!(:non_chatter) { Fabricate(:user, refresh_auto_groups: true) }
before do
SiteSetting.allow_anonymous_mode = true
private_group_create_post.add(user)
end
context "when allow_chat_in_anonymous_mode is true" do
before { SiteSetting.allow_chat_in_anonymous_mode = true }
it "allows shadow account to chat if master account can chat" do
anonymous = AnonymousShadowCreator.get(user)
expect(anonymous.id).to be_present
expect(
Guardian.new(anonymous).can_post_in_chatable?(private_channel.chatable),
).to eq(true)
expect(Guardian.new(user).can_post_in_chatable?(private_channel.chatable)).to eq(
true,
)
end
it "doesn't allow shadow account to chat if master account can not chat" do
anonymous = AnonymousShadowCreator.get(non_chatter)
expect(anonymous.id).to be_present
expect(
Guardian.new(anonymous).can_post_in_chatable?(private_channel.chatable),
).to eq(false)
expect(
Guardian.new(non_chatter).can_post_in_chatable?(private_channel.chatable),
).to eq(false)
end
end
context "when allow_chat_in_anonymous_mode is false" do
before { SiteSetting.allow_chat_in_anonymous_mode = false }
it "doesn't allow shadow account to chat even if master account can chat" do
anonymous = AnonymousShadowCreator.get(user)
expect(anonymous.id).to be_present
expect(Guardian.new(anonymous).can_chat?).to eq(false)
expect(Guardian.new(user).can_chat?).to eq(true)
end
it "doesn't allow shadow account to chat if master account can not chat" do
anonymous = AnonymousShadowCreator.get(non_chatter)
expect(anonymous.id).to be_present
expect(Guardian.new(anonymous).can_chat?).to eq(false)
expect(Guardian.new(non_chatter).can_chat?).to eq(false)
end
end
end
context "when chatable id is part of allowed ids" do
it "returns true" do
expect(guardian).to be_able_to_post_in_chatable(
channel.chatable,
post_allowed_category_ids: [channel.chatable.id],
)
end
end
context "when chatable id is not part of allowed ids" do
it "returns false" do
expect(guardian).not_to be_able_to_post_in_chatable(
channel.chatable,
post_allowed_category_ids: [-1],
)
end
end
end
context "when no post_allowed_category_ids given" do
context "when no chatable given" do
it "returns false" do
expect(guardian).not_to be_able_to_post_in_chatable(nil)
end
end
context "when user is anonymous" do
it "returns false" do
expect(Guardian.new).not_to be_able_to_post_in_chatable(channel.chatable)
end
end
context "when user is admin" do
it "returns true" do
guardian = Fabricate(:admin).guardian
expect(guardian).to be_able_to_post_in_chatable(channel.chatable)
end
end
context "when chatable id is part of allowed ids" do
it "returns true" do
expect(guardian).to be_able_to_post_in_chatable(channel.chatable)
end
end
context "when user can't post in chatable" do
fab!(:group)
fab!(:channel) { Fabricate(:private_category_channel, group: group) }
before do
channel.chatable.category_groups.first.update!(
permission_type: CategoryGroup.permission_types[:readonly],
)
group.add(user)
channel.add(user)
end
it "returns false" do
expect(guardian).not_to be_able_to_post_in_chatable(channel.chatable)
end
end
end
end
context "when channel is a direct message channel" do
let(:channel) { Fabricate(:direct_message_channel) }
it "returns true" do
expect(guardian).to be_able_to_post_in_chatable(channel.chatable)
end
end
end
describe "#can_flag_in_chat_channel?" do
alias_matcher :be_able_to_flag_in_chat_channel, :be_can_flag_in_chat_channel
context "when channel is a direct message channel" do
let(:channel) { Fabricate(:direct_message_channel) }
it "returns false" do
expect(guardian).not_to be_able_to_flag_in_chat_channel(channel)
end
end
context "when channel is a category channel" do
it "returns true" do
expect(guardian).to be_able_to_flag_in_chat_channel(channel)
end
end
context "with a private channel" do
let(:private_group) { Fabricate(:group) }
let(:private_category) { Fabricate(:private_category, group: private_group) }
let(:private_channel) { Fabricate(:category_channel, chatable: private_category) }
context "when the user can't see the channel" do
it "returns false" do
expect(guardian).not_to be_able_to_flag_in_chat_channel(private_channel)
end
end
context "when the user can see the channel" do
before { private_group.add(user) }
it "returns true" do
expect(guardian).to be_able_to_flag_in_chat_channel(private_channel)
end
end
end
end
describe "#can_flag_chat_message?" do
let!(:message) { Fabricate(:chat_message, chat_channel: channel) }
before { SiteSetting.chat_message_flag_allowed_groups = "" }
context "when user isn't staff" do
it "returns false" do
expect(guardian.can_flag_chat_message?(message)).to eq(false)
end
end
context "when user is staff" do
it "returns true" do
expect(staff_guardian.can_flag_chat_message?(message)).to eq(true)
end
end
end
describe "#can_moderate_chat?" do
context "for category channel" do
fab!(:category) { Fabricate(:category, read_restricted: true) }
before { channel.update(chatable: category) }
it "returns true for staff and false for regular users" do
expect(staff_guardian.can_moderate_chat?(channel.chatable)).to eq(true)
expect(guardian.can_moderate_chat?(channel.chatable)).to eq(false)
end
context "when enable_category_group_moderation is true" do
before { SiteSetting.enable_category_group_moderation = true }
it "returns true if the regular user is part of the reviewable groups for the category" do
moderator = Fabricate(:user)
mods = Fabricate(:group)
mods.add(moderator)
Fabricate(:category_moderation_group, category:, group: mods)
expect(Guardian.new(Fabricate(:admin)).can_moderate_chat?(channel.chatable)).to eq(true)
expect(Guardian.new(moderator).can_moderate_chat?(channel.chatable)).to eq(true)
end
end
end
context "for DM channel" do
fab!(:dm_channel) { Chat::DirectMessage.create! }
before { channel.update(chatable_type: "DirectMessageType", chatable: dm_channel) }
it "returns true for staff and false for regular users" do
expect(staff_guardian.can_moderate_chat?(channel.chatable)).to eq(true)
expect(guardian.can_moderate_chat?(channel.chatable)).to eq(false)
end
end
end
describe "#can_restore_chat?" do
fab!(:message) { Fabricate(:chat_message, chat_channel: channel, user: user) }
fab!(:chatable, :category)
context "when channel is closed" do
before { channel.update!(status: :closed) }
it "disallows a owner to restore" do
expect(guardian.can_restore_chat?(message, chatable)).to eq(false)
end
it "allows a staff to restore" do
expect(staff_guardian.can_restore_chat?(message, chatable)).to eq(true)
end
end
context "when chatable is a direct message" do
fab!(:chatable) { Chat::DirectMessage.create! }
it "allows owner to restore when deleted by owner" do
message.trash!(guardian.user)
expect(guardian.can_restore_chat?(message, chatable)).to eq(true)
end
it "disallow owner to restore when deleted by staff" do
message.trash!(staff_guardian.user)
expect(guardian.can_restore_chat?(message, chatable)).to eq(false)
end
it "allows staff to restore" do
expect(staff_guardian.can_restore_chat?(message, chatable)).to eq(true)
end
end
context "when user is not owner of the message" do
fab!(:message) { Fabricate(:chat_message, chat_channel: channel, user: Fabricate(:user)) }
context "when chatable is a category" do
context "when category is not restricted" do
it "allows staff to restore" do
expect(staff_guardian.can_restore_chat?(message, chatable)).to eq(true)
end
it "disallows any user to restore" do
expect(guardian.can_restore_chat?(message, chatable)).to eq(false)
end
end
context "when category is restricted" do
fab!(:chatable) { Fabricate(:category, read_restricted: true) }
it "allows staff to restore" do
expect(staff_guardian.can_restore_chat?(message, chatable)).to eq(true)
end
it "disallows any user to restore" do
expect(guardian.can_restore_chat?(message, chatable)).to eq(false)
end
context "when group moderation is enabled" do
before { SiteSetting.enable_category_group_moderation = true }
it "allows a group moderator to restore" do
moderator = Fabricate(:user)
mods = Fabricate(:group)
mods.add(moderator)
Fabricate(:category_moderation_group, category: chatable, group: mods)
expect(Guardian.new(moderator).can_restore_chat?(message, chatable)).to eq(true)
end
end
end
context "when chatable is a direct message" do
fab!(:chatable) { Chat::DirectMessage.create! }
it "allows staff to restore" do
expect(staff_guardian.can_restore_chat?(message, chatable)).to eq(true)
end
it "disallows any user to restore" do
expect(guardian.can_restore_chat?(message, chatable)).to eq(false)
end
end
end
end
context "when user is owner of the message" do
context "when chatable is a category" do
it "allows owner to restore when deleted by owner" do
message.trash!(guardian.user)
expect(guardian.can_restore_chat?(message, chatable)).to eq(true)
end
it "disallows owner to restore when deleted by staff" do
message.trash!(staff_guardian.user)
expect(guardian.can_restore_chat?(message, chatable)).to eq(false)
end
context "when category is restricted" do
fab!(:chatable) { Fabricate(:category, read_restricted: true) }
it "disallows to restore if owner can't see category" do
expect(guardian.can_restore_chat?(message, chatable)).to eq(false)
end
it "allows staff to restore" do
expect(staff_guardian.can_restore_chat?(message, chatable)).to eq(true)
end
end
end
context "when chatable is a direct message" do
fab!(:chatable) { Chat::DirectMessage.create! }
it "allows staff to restore" do
expect(staff_guardian.can_restore_chat?(message, chatable)).to eq(true)
end
it "allows owner to restore when deleted by owner" do
message.trash!(guardian.user)
expect(guardian.can_restore_chat?(message, chatable)).to eq(true)
end
it "disallow owner to restore when deleted by staff" do
message.trash!(staff_guardian.user)
expect(guardian.can_restore_chat?(message, chatable)).to eq(false)
end
end
context "when the owner has lost access to a private category channel" do
fab!(:revoke_group, :group)
fab!(:revoked_category) { Fabricate(:private_category, group: revoke_group) }
fab!(:revoked_channel) { Fabricate(:chat_channel, chatable: revoked_category) }
fab!(:message) { Fabricate(:chat_message, chat_channel: revoked_channel, user: user) }
before do
revoke_group.add(user)
message.trash!(guardian.user)
GroupUser.where(group: revoke_group, user: user).destroy_all
end
it "disallows owner to restore" do
expect(guardian.can_restore_chat?(message, revoked_category)).to eq(false)
end
end
context "when the owner is no longer in a direct message channel" do
fab!(:other_user, :user)
fab!(:dm_channel) { Fabricate(:direct_message_channel, users: [user, other_user]) }
fab!(:message) { Fabricate(:chat_message, chat_channel: dm_channel, user: user) }
before do
message.trash!(guardian.user)
dm_channel.chatable.direct_message_users.find_by!(user: user).destroy!
end
it "disallows owner to restore" do
expect(guardian.can_restore_chat?(message, dm_channel.chatable)).to eq(false)
end
end
end
end
describe "#can_edit_chat" do
fab!(:message) { Fabricate(:chat_message, chat_channel: channel) }
context "when user is staff" do
it "returns true" do
expect(staff_guardian.can_edit_chat?(message)).to eq(true)
end
end
context "when user is not staff" do
it "returns false" do
expect(guardian.can_edit_chat?(message)).to eq(false)
end
end
context "when user is owner of the message" do
fab!(:message) { Fabricate(:chat_message, chat_channel: channel, user: user) }
it "returns true" do
expect(guardian.can_edit_chat?(message)).to eq(true)
end
end
end
describe "#can_delete_category?" do
alias_matcher :be_able_to_delete_category, :be_can_delete_category
let(:category) { channel.chatable }
context "when user is staff" do
context "when category has no channel" do
before do
category.category_channel.destroy
category.reload
end
it "allows to delete the category" do
expect(staff_guardian).to be_able_to_delete_category(category)
end
end
context "when category has a channel" do
context "when channel has no messages" do
it "allows to delete the category" do
expect(staff_guardian).to be_able_to_delete_category(category)
end
end
context "when channel has messages" do
let!(:message) { Fabricate(:chat_message, chat_channel: channel) }
it "does not allow to delete the category" do
expect(staff_guardian).not_to be_able_to_delete_category(category)
end
end
end
end
context "when user is not staff" do
context "when category has no channel" do
before do
category.category_channel.destroy
category.reload
end
it "does not allow to delete the category" do
expect(guardian).not_to be_able_to_delete_category(category)
end
end
context "when category has a channel" do
context "when channel has no messages" do
it "does not allow to delete the category" do
expect(guardian).not_to be_able_to_delete_category(category)
end
end
context "when channel has messages" do
let!(:message) { Fabricate(:chat_message, chat_channel: channel) }
it "does not allow to delete the category" do
expect(guardian).not_to be_able_to_delete_category(category)
end
end
end
end
end
end
describe "#can_create_channel_message?" do
context "when user is staff" do
it "returns true if the channel is open" do
channel.update!(status: :open)
expect(staff_guardian.can_create_channel_message?(channel)).to eq(true)
end
it "returns true if the channel is closed" do
channel.update!(status: :closed)
expect(staff_guardian.can_create_channel_message?(channel)).to eq(true)
end
it "returns false if the channel is archived" do
channel.update!(status: :archived)
expect(staff_guardian.can_create_channel_message?(channel)).to eq(false)
end
context "for direct message channels" do
it "returns true if the channel is open" do
dm_channel.update!(status: :open)
expect(staff_guardian.can_create_channel_message?(dm_channel)).to eq(true)
end
end
end
context "when user is not staff" do
it "returns true if the channel is open" do
channel.update!(status: :open)
expect(guardian.can_create_channel_message?(channel)).to eq(true)
end
it "returns false if the channel is closed" do
channel.update!(status: :closed)
expect(guardian.can_create_channel_message?(channel)).to eq(false)
end
it "returns false if the channel is archived" do
channel.update!(status: :archived)
expect(guardian.can_create_channel_message?(channel)).to eq(false)
end
end
end
describe "#can_send_direct_message?" do
fab!(:other_user, :user)
fab!(:dm_channel) { Fabricate(:direct_message_channel, users: [user, other_user]) }
alias_matcher :be_able_to_send_direct_message, :be_can_send_direct_message
context "when sender is chatting to self" do
let(:dm_channel_solo) { Fabricate(:direct_message_channel, users: [user]) }
it "returns true" do
expect(guardian).to be_able_to_send_direct_message(dm_channel_solo)
end
end
context "when sender is not in chat enabled groups" do
before { SiteSetting.chat_allowed_groups = "" }
it "returns false" do
expect(guardian).not_to be_able_to_send_direct_message(dm_channel)
end
end
context "when sender is suspended" do
before do
UserSuspender.new(
user,
suspended_till: 1.day.from_now,
by_user: Discourse.system_user,
reason: "spam",
).suspend
end
it "returns false" do
expect(guardian).not_to be_able_to_send_direct_message(dm_channel)
end
end
context "when sender is a bot" do
before { user.id = -1 }
it "returns true" do
expect(guardian).to be_able_to_send_direct_message(dm_channel)
end
end
end
describe "#allowing_direct_messages?" do
context "when user has disabled private messages" do
before { user.user_option.update!(allow_private_messages: false) }
it "returns false" do
expect(guardian.allowing_direct_messages?).to eq(false)
end
end
context "when user has enabled private messages" do
it "returns true" do
expect(guardian.allowing_direct_messages?).to eq(true)
end
end
end
describe "#recipient_can_chat?" do
fab!(:other_user) { Fabricate(:user, groups: [chatters]) }
fab!(:dm_channel) { Fabricate(:direct_message_channel, users: [user, other_user]) }
alias_matcher :be_able_to_chat, :be_recipient_can_chat
context "when target user is not in chat enabled groups" do
before { SiteSetting.chat_allowed_groups = "" }
it "returns false" do
expect(guardian).not_to be_able_to_chat(other_user)
end
end
context "when target user is not in direct message enabled groups" do
before { SiteSetting.direct_message_enabled_groups = Group::AUTO_GROUPS[:admins] }
it "returns true" do
expect(guardian).to be_able_to_chat(other_user)
end
end
context "when target user has disabled chat" do
before { other_user.user_option.update!(chat_enabled: false) }
it "returns false" do
expect(guardian).not_to be_able_to_chat(other_user)
end
end
end
describe "#recipient_not_muted?" do
fab!(:other_user, :user)
context "when target user is not muted" do
it "returns true" do
expect(guardian.recipient_not_muted?(other_user)).to eq(true)
end
end
context "when target user is muted" do
before { MutedUser.create!(user: user, muted_user: other_user) }
it "returns false" do
expect(guardian.recipient_not_muted?(other_user)).to eq(false)
end
end
end
describe "#recipient_not_ignored?" do
fab!(:other_user, :user)
context "when target user is not ignored" do
it "returns true" do
expect(guardian.recipient_not_ignored?(other_user)).to eq(true)
end
end
context "when target user is ignored" do
before do
IgnoredUser.create!(user: user, ignored_user: other_user, expiring_at: 1.day.from_now)
end
it "returns false" do
expect(guardian.recipient_not_ignored?(other_user)).to eq(false)
end
end
end
describe "#recipient_allows_direct_messages?" do
fab!(:other_user, :user)
alias_matcher :be_able_to_receive_direct_message, :be_recipient_allows_direct_messages
context "when target user has disabled private messages" do
before { other_user.user_option.update(allow_private_messages: false) }
it "returns false" do
expect(guardian).not_to be_able_to_receive_direct_message(other_user)
end
end
context "when target user is suspended" do
before do
UserSuspender.new(
other_user,
suspended_till: 1.day.from_now,
by_user: Discourse.system_user,
reason: "spam",
).suspend
end
it "returns false" do
expect(guardian).not_to be_able_to_receive_direct_message(other_user)
end
end
context "when sender is ignored by target user" do
before do
IgnoredUser.create!(user: other_user, ignored_user: user, expiring_at: 1.day.from_now)
end
it "returns false" do
expect(guardian).not_to be_able_to_receive_direct_message(other_user)
end
end
context "when sender is muted by target user" do
before { MutedUser.create!(user: other_user, muted_user: user) }
it "returns false" do
expect(guardian).not_to be_able_to_receive_direct_message(other_user)
end
end
context "when staff is muted by target user" do
before { MutedUser.create!(user: other_user, muted_user: staff) }
it "returns true" do
expect(staff_guardian).to be_able_to_receive_direct_message(other_user)
end
end
context "when staff is ignored by target user" do
before do
IgnoredUser.create!(user: other_user, ignored_user: staff, expiring_at: 1.day.from_now)
end
it "returns true" do
expect(staff_guardian).to be_able_to_receive_direct_message(other_user)
end
end
end
describe "#can_manage_chat_message_pin?" do
fab!(:pin_channel, :chat_channel)
fab!(:message) { Fabricate(:chat_message, chat_channel: pin_channel) }
fab!(:pin_dm_channel) { Fabricate(:direct_message_channel, users: [user, Fabricate(:user)]) }
fab!(:dm_message) { Fabricate(:chat_message, chat_channel: pin_dm_channel) }
context "when user cannot chat" do
before { SiteSetting.chat_allowed_groups = Group::AUTO_GROUPS[:admins] }
it "returns false" do
expect(guardian.can_manage_chat_message_pin?(message)).to eq(false)
end
end
context "for category channels" do
context "when user is not staff" do
it "returns false" do
expect(guardian.can_manage_chat_message_pin?(message)).to eq(false)
end
end
context "when user is staff" do
it "returns true" do
expect(staff_guardian.can_manage_chat_message_pin?(message)).to eq(true)
end
end
context "when user is in pinning group but cannot access the channel" do
fab!(:private_group, :group)
fab!(:private_category) { Fabricate(:private_category, group: private_group) }
fab!(:private_pin_channel) { Fabricate(:category_channel, chatable: private_category) }
fab!(:private_message) { Fabricate(:chat_message, chat_channel: private_pin_channel) }
before do
SiteSetting.chat_pinning_messages_allowed_groups = "#{Group::AUTO_GROUPS[:trust_level_0]}"
end
it "returns false" do
expect(guardian.can_manage_chat_message_pin?(private_message)).to eq(false)
end
end
context "when user is in pinning group and can access the channel" do
fab!(:accessible_group, :group)
fab!(:accessible_category) { Fabricate(:private_category, group: accessible_group) }
fab!(:accessible_channel) { Fabricate(:category_channel, chatable: accessible_category) }
fab!(:accessible_message) { Fabricate(:chat_message, chat_channel: accessible_channel) }
before do
accessible_group.add(user)
SiteSetting.chat_pinning_messages_allowed_groups = "#{Group::AUTO_GROUPS[:trust_level_0]}"
end
it "returns true" do
expect(guardian.can_manage_chat_message_pin?(accessible_message)).to eq(true)
end
end
end
context "for direct message channels" do
context "when user is a member" do
it "returns true" do
expect(guardian.can_manage_chat_message_pin?(dm_message)).to eq(true)
end
end
context "when user is not a member" do
fab!(:other_user) { Fabricate(:user, group_ids: [chatters.id], refresh_auto_groups: true) }
let(:other_guardian) { Guardian.new(other_user) }
it "returns false" do
expect(other_guardian.can_manage_chat_message_pin?(dm_message)).to eq(false)
end
end
end
end
describe "#can_export_entity?" do
fab!(:moderator)
it "only allows admins to export chat_message" do
expect(Guardian.new(user).can_export_entity?("chat_message")).to eq(false)
expect(Guardian.new(moderator).can_export_entity?("chat_message")).to eq(false)
expect(staff_guardian.can_export_entity?("chat_message")).to eq(true)
end
end
end