0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-05 23:04:22 +08:00
discourse/plugins/discourse-presence/plugin.rb
Isaac Janzen 00afbffa10
SECURITY: Authorization bypass in wiki edit presence leaks editor identities (#41474)
## Summary

Correctly restrict wiki edit presence information to authorized users by
intersecting global edit permissions with topic-level security groups.
This prevents users outside of a private category from observing editor
identities via the presence API.

## Source

- Patch Triage: https://patch.discourse.org/patch-triage/1402

Co-authored-by: discourse-patch-triage
<272280883+discourse-patch-triage[bot]@users.noreply.github.com>
2026-07-06 12:53:23 -05:00

113 lines
4.1 KiB
Ruby
Vendored

# frozen_string_literal: true
# name: discourse-presence
# about: Show which users are replying to a topic, or editing a post
# version: 2.0
# authors: André Pereira, David Taylor, tgxworld
# url: https://github.com/discourse/discourse/tree/main/plugins/discourse-presence
enabled_site_setting :presence_enabled
register_asset "stylesheets/presence.scss"
after_initialize do
register_presence_channel_prefix("discourse-presence") do |channel_name|
staff_groups = [::Group::AUTO_GROUPS[:admins], ::Group::AUTO_GROUPS[:moderators]]
if topic_id = channel_name[%r{/discourse-presence/reply/(\d+)}, 1]
topic = Topic.find(topic_id)
config = PresenceChannel::Config.new
if topic.private_message?
config.allowed_user_ids = topic.allowed_users.pluck(:id)
config.allowed_group_ids = topic.allowed_groups.pluck(:group_id) + staff_groups
elsif secure_group_ids = topic.secure_group_ids
config.allowed_group_ids = secure_group_ids + [::Group::AUTO_GROUPS[:admins]]
else
# config.public=true would make data available to anon, so use the tl0 group instead
config.allowed_group_ids = [::Group::AUTO_GROUPS[:trust_level_0]]
end
config
elsif topic_id = channel_name[%r{/discourse-presence/whisper/(\d+)}, 1]
Topic.find(topic_id) # Just ensure it exists
PresenceChannel::Config.new(allowed_group_ids: SiteSetting.whispers_allowed_groups_map)
elsif post_id = channel_name[%r{/discourse-presence/edit/(\d+)}, 1]
post = Post.find(post_id)
topic = Topic.find(post.topic_id)
config = PresenceChannel::Config.new
config.allowed_group_ids = staff_groups
# Locked posts are staff only
next config if post.locked?
# Whispers posts are for allowed whisper groups
if post.whisper?
config.allowed_group_ids += SiteSetting.whispers_allowed_groups_map
next config
end
config.allowed_user_ids = [post.user_id]
if topic.private_message? && post.wiki
# Ignore trust level and just publish to all allowed groups since
# trying to figure out which users in the allowed groups have
# the necessary trust levels can lead to a large array of user ids
# if the groups are big.
config.allowed_user_ids += topic.allowed_users.pluck(:id)
config.allowed_group_ids += topic.allowed_groups.pluck(:id)
elsif post.wiki
wiki_post_allowed_group_ids = SiteSetting.edit_wiki_post_allowed_groups_map
if secure_group_ids = topic.secure_group_ids
wiki_post_allowed_group_ids &= secure_group_ids
end
config.allowed_group_ids += wiki_post_allowed_group_ids
end
if !topic.private_message? && SiteSetting.edit_all_post_groups_map.present?
edit_all_post_group_ids = SiteSetting.edit_all_post_groups_map
if secure_group_ids = topic.secure_group_ids
edit_all_post_group_ids &= secure_group_ids
end
config.allowed_group_ids += edit_all_post_group_ids
end
if SiteSetting.enable_category_group_moderation? && topic.category
config.allowed_group_ids.push(*topic.category.moderating_groups.pluck(:id))
end
config.allowed_group_ids.uniq!
config
elsif post_id = channel_name[%r{/discourse-presence/translate/(\d+)}, 1]
post = Post.find(post_id)
topic = Topic.find(post.topic_id)
config = PresenceChannel::Config.new
config.allowed_group_ids = staff_groups
config.allowed_user_ids = []
if SiteSetting.content_localization_enabled
config.allowed_group_ids += SiteSetting.content_localization_allowed_groups_map
end
if topic.private_message?
config.allowed_user_ids += topic.allowed_users.pluck(:id)
config.allowed_group_ids += topic.allowed_groups.pluck(:group_id)
elsif secure_group_ids = topic.secure_group_ids
config.allowed_group_ids += secure_group_ids
end
if SiteSetting.content_localization_allow_author_localization
config.allowed_user_ids += [post.user_id]
end
config.allowed_group_ids.uniq!
config
end
rescue ActiveRecord::RecordNotFound
nil
end
end