gitlab-org--gitlab-foss/lib/gitlab/rack_attack.rb

100 lines
3.7 KiB
Ruby

# frozen_string_literal: true
# Integration specs for throttling can be found in:
# spec/requests/rack_attack_global_spec.rb
module Gitlab
module RackAttack
def self.configure(rack_attack)
# This adds some methods used by our throttles to the `Rack::Request`
rack_attack::Request.include(Gitlab::RackAttack::Request)
# Send the Retry-After header so clients (e.g. python-gitlab) can make good choices about delays
Rack::Attack.throttled_response_retry_after_header = true
# Configure the throttles
configure_throttles(rack_attack)
end
def self.configure_throttles(rack_attack)
throttle_or_track(rack_attack, 'throttle_unauthenticated', Gitlab::Throttle.unauthenticated_options) do |req|
if !req.should_be_skipped? &&
Gitlab::Throttle.settings.throttle_unauthenticated_enabled &&
req.unauthenticated?
req.ip
end
end
throttle_or_track(rack_attack, 'throttle_authenticated_api', Gitlab::Throttle.authenticated_api_options) do |req|
if req.api_request? &&
Gitlab::Throttle.settings.throttle_authenticated_api_enabled
req.authenticated_user_id([:api])
end
end
# Product analytics feature is in experimental stage.
# At this point we want to limit amount of events registered
# per application (aid stands for application id).
throttle_or_track(rack_attack, 'throttle_product_analytics_collector', limit: 100, period: 60) do |req|
if req.product_analytics_collector_request?
req.params['aid']
end
end
throttle_or_track(rack_attack, 'throttle_authenticated_web', Gitlab::Throttle.authenticated_web_options) do |req|
if req.web_request? &&
Gitlab::Throttle.settings.throttle_authenticated_web_enabled
req.authenticated_user_id([:api, :rss, :ics])
end
end
throttle_or_track(rack_attack, 'throttle_unauthenticated_protected_paths', Gitlab::Throttle.protected_paths_options) do |req|
if req.post? &&
!req.should_be_skipped? &&
req.protected_path? &&
Gitlab::Throttle.protected_paths_enabled? &&
req.unauthenticated?
req.ip
end
end
throttle_or_track(rack_attack, 'throttle_authenticated_protected_paths_api', Gitlab::Throttle.protected_paths_options) do |req|
if req.post? &&
req.api_request? &&
req.protected_path? &&
Gitlab::Throttle.protected_paths_enabled?
req.authenticated_user_id([:api])
end
end
throttle_or_track(rack_attack, 'throttle_authenticated_protected_paths_web', Gitlab::Throttle.protected_paths_options) do |req|
if req.post? &&
req.web_request? &&
req.protected_path? &&
Gitlab::Throttle.protected_paths_enabled?
req.authenticated_user_id([:api, :rss, :ics])
end
end
rack_attack.safelist('throttle_bypass_header') do |req|
Gitlab::Throttle.bypass_header.present? &&
req.get_header(Gitlab::Throttle.bypass_header) == '1'
end
end
def self.throttle_or_track(rack_attack, throttle_name, *args, &block)
if track?(throttle_name)
rack_attack.track(throttle_name, *args, &block)
else
rack_attack.throttle(throttle_name, *args, &block)
end
end
def self.track?(name)
dry_run_config = ENV['GITLAB_THROTTLE_DRY_RUN'].to_s.strip
return false if dry_run_config.empty?
return true if dry_run_config == '*'
dry_run_config.split(',').map(&:strip).include?(name)
end
end
end
::Gitlab::RackAttack.prepend_if_ee('::EE::Gitlab::RackAttack')