discourse/plugins/discourse-policy/app/controllers/discourse_policy/policy_controller.rb
Alan Guo Xiang Tan dcde9de530 SECURITY: Add authorization to policy add-users-to-group
- The `add-users-to-group` attribute on a policy automatically enrolls
  users into a group when they accept the policy. No code path verified
  whether the post author could actually manage the target group.
- Add a `Guardian#can_edit_group?` check in the `post_process_cooked`
  handler so the target group ID is only persisted when the post author
  can manage it.
- Add a `Guardian#can_edit_group?` check in
  `PolicyController#ensure_can_accept` so accept/unaccept requests are
  rejected if the post author's permission to manage the target group
  has since been revoked.
2026-03-19 15:21:28 +00:00

98 lines
2.7 KiB
Ruby
Vendored

# frozen_string_literal: true
class DiscoursePolicy::PolicyController < ::ApplicationController
requires_plugin DiscoursePolicy::PLUGIN_NAME
before_action :ensure_logged_in, :set_post
before_action :ensure_can_accept, only: %i[accept unaccept]
before_action :ensure_can_see_policy_users, only: %i[accepted not_accepted]
def accept
PolicyUser.add!(current_user, @post.post_policy)
@post.publish_change_to_clients!(:policy_change)
@add_users_group&.add(current_user)
render json: success_json
end
def unaccept
PolicyUser.remove!(current_user, @post.post_policy)
@post.publish_change_to_clients!(:policy_change)
@add_users_group&.remove(current_user)
render json: success_json
end
def accepted
users =
@post
.post_policy
.accepted_by
.offset(params[:offset])
.limit(DiscoursePolicy::POLICY_USER_DEFAULT_LIMIT)
render json: { users: serialize_data(users, BasicUserSerializer) }
end
def not_accepted
users =
@post
.post_policy
.not_accepted_by
.offset(params[:offset])
.limit(DiscoursePolicy::POLICY_USER_DEFAULT_LIMIT)
render json: { users: serialize_data(users, BasicUserSerializer) }
end
private
def ensure_can_see_policy_users
post_policy = @post.post_policy
raise Discourse::InvalidAccess if post_policy.private? && !guardian.is_admin?
unless guardian.can_see_groups_members?(post_policy.groups)
render_json_error(I18n.t("discourse_policy.error.no_permission"))
end
end
def ensure_can_accept
if !GroupUser.where(
"group_id in (:group_ids) and user_id = :user_id",
group_ids: @group_ids,
user_id: current_user.id,
).exists?
return render_json_error(I18n.t("discourse_policy.errors.user_missing"))
end
@add_users_group = @post.post_policy.add_users_group
if @add_users_group && !Guardian.new(@post.user).can_edit_group?(@add_users_group)
return render_json_error(I18n.t("discourse_policy.errors.policy_group_inaccessible"))
end
true
end
def set_post
raise Discourse::NotFound if !SiteSetting.policy_enabled
params.require(:post_id)
@post = Post.find_by(id: params[:post_id])
raise Discourse::NotFound if !@post
raise Discourse::NotFound if !guardian.can_see?(@post)
return render_json_error(I18n.t("discourse_policy.errors.no_policy")) if !@post.post_policy
@group_ids = @post.post_policy.groups.pluck(:id)
return render_json_error(I18n.t("discourse_policy.errors.group_not_found")) if @group_ids.blank?
if !@post.user&.in_any_groups?(SiteSetting.create_policy_allowed_groups_map)
return render_json_error(I18n.t("discourse_policy.errors.staff_only"))
end
true
end
end