mirror of
https://github.com/samsonjs/rack-attack.git
synced 2026-03-25 09:25:49 +00:00
108 lines
3.3 KiB
Ruby
108 lines
3.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rack'
|
|
require 'forwardable'
|
|
require 'rack/attack/path_normalizer'
|
|
require 'rack/attack/request'
|
|
require "ipaddr"
|
|
|
|
require 'rack/attack/railtie' if defined?(::Rails)
|
|
|
|
module Rack
|
|
class Attack
|
|
class Error < StandardError; end
|
|
class MisconfiguredStoreError < Error; end
|
|
class MissingStoreError < Error; end
|
|
|
|
autoload :Configuration, 'rack/attack/configuration'
|
|
autoload :Cache, 'rack/attack/cache'
|
|
autoload :Check, 'rack/attack/check'
|
|
autoload :Throttle, 'rack/attack/throttle'
|
|
autoload :Safelist, 'rack/attack/safelist'
|
|
autoload :Blocklist, 'rack/attack/blocklist'
|
|
autoload :Track, 'rack/attack/track'
|
|
autoload :StoreProxy, 'rack/attack/store_proxy'
|
|
autoload :DalliProxy, 'rack/attack/store_proxy/dalli_proxy'
|
|
autoload :MemCacheStoreProxy, 'rack/attack/store_proxy/mem_cache_store_proxy'
|
|
autoload :RedisProxy, 'rack/attack/store_proxy/redis_proxy'
|
|
autoload :RedisStoreProxy, 'rack/attack/store_proxy/redis_store_proxy'
|
|
autoload :RedisCacheStoreProxy, 'rack/attack/store_proxy/redis_cache_store_proxy'
|
|
autoload :ActiveSupportRedisStoreProxy, 'rack/attack/store_proxy/active_support_redis_store_proxy'
|
|
autoload :Fail2Ban, 'rack/attack/fail2ban'
|
|
autoload :Allow2Ban, 'rack/attack/allow2ban'
|
|
|
|
class << self
|
|
attr_accessor :enabled, :notifier
|
|
attr_reader :configuration
|
|
|
|
def instrument(request)
|
|
if notifier
|
|
event_type = request.env["rack.attack.match_type"]
|
|
notifier.instrument("#{event_type}.rack_attack", request: request)
|
|
|
|
# Deprecated: Keeping just for backwards compatibility
|
|
notifier.instrument("rack.attack", request: request)
|
|
end
|
|
end
|
|
|
|
def cache
|
|
@cache ||= Cache.new
|
|
end
|
|
|
|
def clear!
|
|
warn "[DEPRECATION] Rack::Attack.clear! is deprecated. Please use Rack::Attack.clear_configuration instead"
|
|
@configuration.clear_configuration
|
|
end
|
|
|
|
extend Forwardable
|
|
def_delegators(
|
|
:@configuration,
|
|
:safelist,
|
|
:blocklist,
|
|
:blocklist_ip,
|
|
:safelist_ip,
|
|
:throttle,
|
|
:track,
|
|
:blocklisted_response,
|
|
:blocklisted_response=,
|
|
:throttled_response,
|
|
:throttled_response=,
|
|
:clear_configuration,
|
|
:safelists,
|
|
:blocklists,
|
|
:throttles,
|
|
:tracks
|
|
)
|
|
end
|
|
|
|
# Set defaults
|
|
@enabled = true
|
|
@notifier = ActiveSupport::Notifications if defined?(ActiveSupport::Notifications)
|
|
@configuration = Configuration.new
|
|
|
|
attr_reader :configuration
|
|
|
|
def initialize(app)
|
|
@app = app
|
|
@configuration = self.class.configuration
|
|
end
|
|
|
|
def call(env)
|
|
return @app.call(env) unless self.class.enabled
|
|
|
|
env['PATH_INFO'] = PathNormalizer.normalize_path(env['PATH_INFO'])
|
|
request = Rack::Attack::Request.new(env)
|
|
|
|
if configuration.safelisted?(request)
|
|
@app.call(env)
|
|
elsif configuration.blocklisted?(request)
|
|
configuration.blocklisted_response.call(env)
|
|
elsif configuration.throttled?(request)
|
|
configuration.throttled_response.call(env)
|
|
else
|
|
configuration.tracked?(request)
|
|
@app.call(env)
|
|
end
|
|
end
|
|
end
|
|
end
|