mirror of
https://github.com/discourse/discourse.git
synced 2026-03-04 01:15:08 +08:00
Empty-scopes bypass allows untrusted client registration via `UserApiKeyClientsController#create` — sending `scopes=","` creates a client with zero persisted scopes, bypassing downstream scope restrictions. This hardens the param to avoid this kind of empty scope registration.
67 lines
1.9 KiB
Ruby
67 lines
1.9 KiB
Ruby
# frozen_string_literal: true
|
|
class UserApiKeyClientsController < ApplicationController
|
|
layout "no_ember"
|
|
|
|
skip_before_action :check_xhr, :preload_json, :verify_authenticity_token
|
|
|
|
def show
|
|
params.require(:client_id)
|
|
client = UserApiKeyClient.find_by(client_id: params[:client_id])
|
|
raise Discourse::InvalidParameters unless client && client.auth_redirect.present?
|
|
head :ok
|
|
end
|
|
|
|
def create
|
|
rate_limit unless skip_rate_limit?
|
|
require_params
|
|
validate_params
|
|
ensure_new_client
|
|
|
|
client = UserApiKeyClient.new(client_id: params[:client_id])
|
|
client.application_name = params[:application_name]
|
|
client.public_key = params[:public_key]
|
|
client.auth_redirect = params[:auth_redirect]
|
|
|
|
ActiveRecord::Base.transaction do
|
|
client.save!
|
|
@scopes.each { |scope| client.scopes.create!(name: scope) }
|
|
end
|
|
|
|
if client.persisted?
|
|
render json: success_json
|
|
else
|
|
render json: failed_json
|
|
end
|
|
end
|
|
|
|
def skip_rate_limit?
|
|
SiteSetting
|
|
.create_user_api_key_client_ip_rate_limit_override_ips
|
|
.split("|")
|
|
.include?(request.remote_ip)
|
|
end
|
|
|
|
def rate_limit
|
|
RateLimiter.new(
|
|
nil,
|
|
"user-api-key-clients-#{request.remote_ip}",
|
|
SiteSetting.user_api_key_clients_create_per_day,
|
|
24.hours,
|
|
).performed!
|
|
end
|
|
|
|
def require_params
|
|
%i[client_id application_name public_key auth_redirect scopes].each { |p| params.require(p) }
|
|
@scopes = params[:scopes].to_s.split(",").map(&:strip).reject(&:blank?)
|
|
raise Discourse::InvalidParameters.new(:scopes) if @scopes.empty?
|
|
end
|
|
|
|
def validate_params
|
|
raise Discourse::InvalidAccess unless UserApiKeyClientScope.allowed.superset?(Set.new(@scopes))
|
|
OpenSSL::PKey::RSA.new(params[:public_key])
|
|
end
|
|
|
|
def ensure_new_client
|
|
raise Discourse::InvalidAccess if UserApiKeyClient.where(client_id: params[:client_id]).exists?
|
|
end
|
|
end
|