0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-05 17:25:34 +08:00
discourse/app/serializers/directory_item_serializer.rb
Isaac Janzen c87983792b
SECURITY: /directory_items leaks restricted user-field values (#41476)
## Summary

Prevent the exposure of restricted user-field values in the
`/directory_items.json` endpoint by enforcing profile visibility checks.
The directory item serializer now correctly respects site-wide profile
privacy settings and individual user profile visibility preferences.

## Source

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

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

62 lines
1.5 KiB
Ruby
Vendored

# frozen_string_literal: true
class DirectoryItemSerializer < ApplicationSerializer
class UserSerializer < UserNameSerializer
include UserPrimaryGroupMixin
attributes :user_fields
def user_fields
fields = {}
user_custom_field_map = @options[:user_custom_field_map] || {}
searchable_fields = @options[:searchable_fields] || []
object.user_custom_fields.each do |custom_field|
user_field_id = user_custom_field_map[custom_field.name]
next unless user_field_id
current_value = fields.dig(user_field_id, :value)
current_value = Array(current_value) if current_value
new_value = current_value ? current_value << custom_field.value : custom_field.value
is_searchable = searchable_fields.any? { |field| field.id == user_field_id }
fields[user_field_id] = {
value: new_value.is_a?(Array) ? new_value : [new_value],
searchable: is_searchable,
}
end
fields
end
def include_user_fields?
@options[:user_custom_field_map].present? && scope.public_can_see_profiles? &&
!scope.restrict_user_fields?(object)
end
end
has_one :user, embed: :objects, serializer: UserSerializer
attributes :id
def id
object.user_id
end
private
def attributes
hash = super
@options[:attributes].each { |attr| hash.merge!("#{attr}": object[attr]) }
if object.period_type == DirectoryItem.period_types[:all]
hash.merge!(time_read: object.user_stat.time_read)
end
hash
end
end