0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-06 05:42:36 +08:00
discourse/app/controllers/user_actions_controller.rb
Mark VanLandingham ca893a8608
FIX: Bound user-actions index limit at 100 (#42361)
## Summary

The public `GET /user_actions.json` endpoint accepted an unbounded
client-supplied `limit` and forwarded it directly into the activity
query, allowing an anonymous request to materialize and serialize an
arbitrarily large number of actions. The controller now caps the
effective limit at 100 while preserving the default of 30 and smaller
caller-requested values, so oversized requests return a bounded page
without excessive resource use. Public-action visibility and
authorization filtering are unchanged.

## Source

- Patch Triage: https://patch.discourse.org/patch-triage/1588
2026-08-05 11:52:53 -05:00

69 lines
2.1 KiB
Ruby
Vendored

# frozen_string_literal: true
class UserActionsController < ApplicationController
def index
user_actions_params.require(:username)
user =
fetch_user_from_params(
include_inactive:
current_user.try(:staff?) || (current_user && SiteSetting.show_inactive_accounts),
)
offset = [0, user_actions_params[:offset].to_i].max
action_types = (user_actions_params[:filter] || "").split(",").map(&:to_i)
limit = [user_actions_params.fetch(:limit, 30).to_i, 100].min
ensure_user_actions_visible!(user, action_types)
if action_types.empty? && !guardian.can_see_user_actions?(user, UserAction.private_types)
action_types = UserAction.types.values - UserAction.private_types
end
opts = {
user_id: user.id,
user: user,
offset: offset,
limit: limit,
action_types: action_types,
guardian: guardian,
ignore_private_messages: params[:filter].blank?,
acting_username: params[:acting_username],
}
stream = UserAction.stream(opts).to_a
response = { user_actions: serialize_data(stream, UserActionSerializer) }
if guardian.can_lazy_load_categories?
category_ids = stream.map(&:category_id).compact.uniq
categories = Category.secured(guardian).with_parents(category_ids)
response[:categories] = serialize_data(categories, CategoryBadgeSerializer)
end
render json: response
end
def show
params.require(:id)
stream_item = UserAction.stream_item(params[:id], guardian)
raise Discourse::NotFound if stream_item.blank?
user = User.find_by(id: stream_item.target_user_id)
raise Discourse::NotFound if user.blank?
ensure_user_actions_visible!(user, [stream_item.action_type])
render_serialized(stream_item, UserActionSerializer)
end
private
def ensure_user_actions_visible!(user, action_types)
raise Discourse::NotFound unless guardian.can_see_profile?(user)
raise Discourse::NotFound unless guardian.can_see_user_actions?(user, action_types)
end
def user_actions_params
@user_actions_params ||= params.permit(:username, :filter, :offset, :acting_username, :limit)
end
end