diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-22 06:09:39 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-22 06:09:39 +0300 |
commit | f8edcff7e9aff93f8ac605c19e542204b0ed9ba2 (patch) | |
tree | fe45e8bc69f5c68c6d4ee7505a4d61c4fdb70299 /lib | |
parent | d61d19da54b0fb8fd54df4007fa95cd39db17e57 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api/helpers.rb | 10 | ||||
-rw-r--r-- | lib/api/helpers/rate_limiter.rb | 17 | ||||
-rw-r--r-- | lib/api/issues.rb | 6 | ||||
-rw-r--r-- | lib/api/merge_requests.rb | 3 | ||||
-rw-r--r-- | lib/gitlab/application_rate_limiter.rb | 32 |
5 files changed, 54 insertions, 14 deletions
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index 0b5a471ea12..95c81c14bf9 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -695,6 +695,16 @@ module API unprocessable_entity!('User must be authenticated to use search') end + def validate_search_rate_limit! + return unless Feature.enabled?(:rate_limit_issuable_searches) + + if current_user + check_rate_limit!(:search_rate_limit, scope: [current_user]) + else + check_rate_limit!(:search_rate_limit_unauthenticated, scope: [ip_address]) + end + end + private # rubocop:disable Gitlab/ModuleWithInstanceVariables diff --git a/lib/api/helpers/rate_limiter.rb b/lib/api/helpers/rate_limiter.rb index 03f3cd649b1..be92277c25a 100644 --- a/lib/api/helpers/rate_limiter.rb +++ b/lib/api/helpers/rate_limiter.rb @@ -10,25 +10,14 @@ module API # See app/controllers/concerns/check_rate_limit.rb for Rails controllers version module RateLimiter def check_rate_limit!(key, scope:, **options) - return if bypass_header_set? - return unless rate_limiter.throttled?(key, scope: scope, **options) - - rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user) + return unless Gitlab::ApplicationRateLimiter.throttled_request?( + request, current_user, key, scope: scope, **options + ) return yield if block_given? render_api_error!({ error: _('This endpoint has been requested too many times. Try again later.') }, 429) end - - private - - def rate_limiter - ::Gitlab::ApplicationRateLimiter - end - - def bypass_header_set? - ::Gitlab::Throttle.bypass_header.present? && request.get_header(Gitlab::Throttle.bypass_header) == '1' - end end end end diff --git a/lib/api/issues.rb b/lib/api/issues.rb index b08819e34e3..7b6306938cf 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -116,6 +116,7 @@ module API get '/issues_statistics' do authenticate! unless params[:scope] == 'all' validate_anonymous_search_access! if params[:search].present? + validate_search_rate_limit! if declared_params[:search].present? present issues_statistics, with: Grape::Presenters::Presenter end @@ -134,6 +135,7 @@ module API get do authenticate! unless params[:scope] == 'all' validate_anonymous_search_access! if params[:search].present? + validate_search_rate_limit! if declared_params[:search].present? issues = paginate(find_issues) options = { @@ -173,6 +175,7 @@ module API end get ":id/issues" do validate_anonymous_search_access! if declared_params[:search].present? + validate_search_rate_limit! if declared_params[:search].present? issues = paginate(find_issues(group_id: user_group.id, include_subgroups: true)) options = { @@ -192,6 +195,7 @@ module API end get ":id/issues_statistics" do validate_anonymous_search_access! if declared_params[:search].present? + validate_search_rate_limit! if declared_params[:search].present? present issues_statistics(group_id: user_group.id, include_subgroups: true), with: Grape::Presenters::Presenter end @@ -211,6 +215,7 @@ module API end get ":id/issues" do validate_anonymous_search_access! if declared_params[:search].present? + validate_search_rate_limit! if declared_params[:search].present? issues = paginate(find_issues(project_id: user_project.id)) options = { @@ -230,6 +235,7 @@ module API end get ":id/issues_statistics" do validate_anonymous_search_access! if declared_params[:search].present? + validate_search_rate_limit! if declared_params[:search].present? present issues_statistics(project_id: user_project.id), with: Grape::Presenters::Presenter end diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index a9572cf7ce6..8a665b71bdb 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -149,6 +149,7 @@ module API get feature_category: :code_review, urgency: :low do authenticate! unless params[:scope] == 'all' validate_anonymous_search_access! if params[:search].present? + validate_search_rate_limit! if declared_params[:search].present? merge_requests = find_merge_requests present merge_requests, serializer_options_for(merge_requests) @@ -177,6 +178,7 @@ module API end get ":id/merge_requests", feature_category: :code_review, urgency: :low do validate_anonymous_search_access! if declared_params[:search].present? + validate_search_rate_limit! if declared_params[:search].present? merge_requests = find_merge_requests(group_id: user_group.id, include_subgroups: true) present merge_requests, serializer_options_for(merge_requests).merge(group: user_group) @@ -244,6 +246,7 @@ module API get ":id/merge_requests", feature_category: :code_review, urgency: :low do authorize! :read_merge_request, user_project validate_anonymous_search_access! if declared_params[:search].present? + validate_search_rate_limit! if declared_params[:search].present? merge_requests = find_merge_requests(project_id: user_project.id) diff --git a/lib/gitlab/application_rate_limiter.rb b/lib/gitlab/application_rate_limiter.rb index 5b1bf99e297..a788586ebec 100644 --- a/lib/gitlab/application_rate_limiter.rb +++ b/lib/gitlab/application_rate_limiter.rb @@ -115,6 +115,38 @@ module Gitlab value > threshold_value end + # Similar to #throttled? above but checks for the bypass header in the request and logs the request when it is over the rate limit + # + # @param request [Http::Request] - Web request used to check the header and log + # @param current_user [User] Current user of the request, it can be nil + # @param key [Symbol] Key attribute registered in `.rate_limits` + # @param scope [Array<ActiveRecord>] Array of ActiveRecord models, Strings + # or Symbols to scope throttling to a specific request (e.g. per user + # per project) + # @param resource [ActiveRecord] An ActiveRecord model to count an action + # for (e.g. limit unique project (resource) downloads (action) to five + # per user (scope)) + # @param threshold [Integer] Optional threshold value to override default + # one registered in `.rate_limits` + # @param interval [Integer] Optional interval value to override default + # one registered in `.rate_limits` + # @param users_allowlist [Array<String>] Optional list of usernames to + # exclude from the limit. This param will only be functional if Scope + # includes a current user. + # @param peek [Boolean] Optional. When true the key will not be + # incremented but the current throttled state will be returned. + # + # @return [Boolean] Whether or not a request should be throttled + def throttled_request?(request, current_user, key, scope:, **options) + if ::Gitlab::Throttle.bypass_header.present? && request.get_header(Gitlab::Throttle.bypass_header) == '1' + return false + end + + throttled?(key, scope: scope, **options).tap do |throttled| + log_request(request, "#{key}_request_limit".to_sym, current_user) if throttled + end + end + # Returns the current rate limited state without incrementing the count. # # @param key [Symbol] Key attribute registered in `.rate_limits` |