From df354cd1418c0cabbe63674c6e9aefc83d4781ac Mon Sep 17 00:00:00 2001 From: fatkodima Date: Fri, 11 Oct 2019 16:17:07 +0300 Subject: [PATCH 1/7] Make discriminators case-insensitive by default --- lib/rack/attack.rb | 5 +++- lib/rack/attack/throttle.rb | 11 ++++++-- spec/rack_attack_throttle_spec.rb | 44 +++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/rack/attack.rb b/lib/rack/attack.rb index f209d59..b02dd39 100644 --- a/lib/rack/attack.rb +++ b/lib/rack/attack.rb @@ -32,7 +32,7 @@ module Rack autoload :Allow2Ban, 'rack/attack/allow2ban' class << self - attr_accessor :enabled, :notifier + attr_accessor :enabled, :notifier, :discriminator_normalizer attr_reader :configuration def instrument(request) @@ -84,6 +84,9 @@ module Rack # Set defaults @enabled = true @notifier = ActiveSupport::Notifications if defined?(ActiveSupport::Notifications) + @discriminator_normalizer = lambda do |discriminator| + discriminator.to_s.strip.downcase + end @configuration = Configuration.new attr_reader :configuration diff --git a/lib/rack/attack/throttle.rb b/lib/rack/attack/throttle.rb index 96c0f3b..1cc50f4 100644 --- a/lib/rack/attack/throttle.rb +++ b/lib/rack/attack/throttle.rb @@ -23,8 +23,7 @@ module Rack end def matched_by?(request) - discriminator = block.call(request) - + discriminator = discriminator_for(request) return false unless discriminator current_period = period_for(request) @@ -50,6 +49,14 @@ module Rack private + def discriminator_for(request) + discriminator = block.call(request) + if discriminator && Rack::Attack.discriminator_normalizer + discriminator = Rack::Attack.discriminator_normalizer.call(discriminator) + end + discriminator + end + def period_for(request) period.respond_to?(:call) ? period.call(request) : period end diff --git a/spec/rack_attack_throttle_spec.rb b/spec/rack_attack_throttle_spec.rb index dcb1e41..feb599c 100644 --- a/spec/rack_attack_throttle_spec.rb +++ b/spec/rack_attack_throttle_spec.rb @@ -144,3 +144,47 @@ describe 'Rack::Attack.throttle with block retuning nil' do end end end + +describe 'Rack::Attack.throttle with discriminator_normalizer' do + before do + @period = 60 + @emails = [ + "person@example.com", + "PERSON@example.com ", + " person@example.com\r\n ", + ] + Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new + Rack::Attack.throttle('logins/email', limit: 4, period: @period) do |req| + if req.path == '/login' && req.post? + req.params['email'] + end + end + end + + it 'should not differentiate requests when discriminator_normalizer is enabled' do + post_logins + key = "rack::attack:#{Time.now.to_i / @period}:logins/email:person@example.com" + _(Rack::Attack.cache.store.read(key)).must_equal 3 + end + + it 'should differentiate requests when discriminator_normalizer is disabled' do + begin + prev = Rack::Attack.discriminator_normalizer + Rack::Attack.discriminator_normalizer = nil + + post_logins + @emails.each do |email| + key = "rack::attack:#{Time.now.to_i / @period}:logins/email:#{email}" + _(Rack::Attack.cache.store.read(key)).must_equal 1 + end + ensure + Rack::Attack.discriminator_normalizer = prev + end + end + + def post_logins + @emails.each do |email| + post '/login', email: email + end + end +end From e131750a6bf49549c9c07596490b177cd2f56e56 Mon Sep 17 00:00:00 2001 From: fatkodima Date: Thu, 24 Oct 2019 02:48:32 +0300 Subject: [PATCH 2/7] Make store proxies lookup dynamic --- lib/rack/attack.rb | 13 +++++---- lib/rack/attack/base_proxy.rb | 27 +++++++++++++++++++ lib/rack/attack/cache.rb | 7 ++++- lib/rack/attack/store_proxy.rb | 21 --------------- .../active_support_redis_store_proxy.rb | 4 +-- lib/rack/attack/store_proxy/dalli_proxy.rb | 4 +-- .../store_proxy/mem_cache_store_proxy.rb | 4 +-- .../store_proxy/redis_cache_store_proxy.rb | 4 +-- lib/rack/attack/store_proxy/redis_proxy.rb | 6 ++--- .../attack/store_proxy/redis_store_proxy.rb | 2 +- 10 files changed, 51 insertions(+), 41 deletions(-) create mode 100644 lib/rack/attack/base_proxy.rb delete mode 100644 lib/rack/attack/store_proxy.rb diff --git a/lib/rack/attack.rb b/lib/rack/attack.rb index b02dd39..afb5b08 100644 --- a/lib/rack/attack.rb +++ b/lib/rack/attack.rb @@ -6,6 +6,12 @@ require 'rack/attack/cache' require 'rack/attack/configuration' require 'rack/attack/path_normalizer' require 'rack/attack/request' +require 'rack/attack/store_proxy/dalli_proxy' +require 'rack/attack/store_proxy/mem_cache_store_proxy' +require 'rack/attack/store_proxy/redis_proxy' +require 'rack/attack/store_proxy/redis_store_proxy' +require 'rack/attack/store_proxy/redis_cache_store_proxy' +require 'rack/attack/store_proxy/active_support_redis_store_proxy' require 'rack/attack/railtie' if defined?(::Rails) @@ -21,13 +27,6 @@ module Rack 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' diff --git a/lib/rack/attack/base_proxy.rb b/lib/rack/attack/base_proxy.rb new file mode 100644 index 0000000..3e3c28a --- /dev/null +++ b/lib/rack/attack/base_proxy.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'delegate' + +module Rack + class Attack + class BaseProxy < SimpleDelegator + class << self + def proxies + @@proxies ||= [] + end + + def inherited(klass) + proxies << klass + end + + def lookup(store) + proxies.find { |proxy| proxy.handle?(store) } + end + + def handle?(_store) + raise NotImplementedError + end + end + end + end +end diff --git a/lib/rack/attack/cache.rb b/lib/rack/attack/cache.rb index c74bc2a..0e1f606 100644 --- a/lib/rack/attack/cache.rb +++ b/lib/rack/attack/cache.rb @@ -14,7 +14,12 @@ module Rack attr_reader :store def store=(store) - @store = StoreProxy.build(store) + @store = + if (proxy = BaseProxy.lookup(store)) + proxy.new(store) + else + store + end end def count(unprefixed_key, period) diff --git a/lib/rack/attack/store_proxy.rb b/lib/rack/attack/store_proxy.rb deleted file mode 100644 index 55c63e2..0000000 --- a/lib/rack/attack/store_proxy.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module Rack - class Attack - module StoreProxy - PROXIES = [ - DalliProxy, - MemCacheStoreProxy, - RedisStoreProxy, - RedisProxy, - RedisCacheStoreProxy, - ActiveSupportRedisStoreProxy - ].freeze - - def self.build(store) - klass = PROXIES.find { |proxy| proxy.handle?(store) } - klass ? klass.new(store) : store - end - end - end -end diff --git a/lib/rack/attack/store_proxy/active_support_redis_store_proxy.rb b/lib/rack/attack/store_proxy/active_support_redis_store_proxy.rb index 68f0326..d2c0e3b 100644 --- a/lib/rack/attack/store_proxy/active_support_redis_store_proxy.rb +++ b/lib/rack/attack/store_proxy/active_support_redis_store_proxy.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -require 'delegate' +require 'rack/attack/base_proxy' module Rack class Attack module StoreProxy - class ActiveSupportRedisStoreProxy < SimpleDelegator + class ActiveSupportRedisStoreProxy < BaseProxy def self.handle?(store) defined?(::Redis) && defined?(::ActiveSupport::Cache::RedisStore) && diff --git a/lib/rack/attack/store_proxy/dalli_proxy.rb b/lib/rack/attack/store_proxy/dalli_proxy.rb index 360e219..48198bb 100644 --- a/lib/rack/attack/store_proxy/dalli_proxy.rb +++ b/lib/rack/attack/store_proxy/dalli_proxy.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -require 'delegate' +require 'rack/attack/base_proxy' module Rack class Attack module StoreProxy - class DalliProxy < SimpleDelegator + class DalliProxy < BaseProxy def self.handle?(store) return false unless defined?(::Dalli) diff --git a/lib/rack/attack/store_proxy/mem_cache_store_proxy.rb b/lib/rack/attack/store_proxy/mem_cache_store_proxy.rb index f8c036c..122037f 100644 --- a/lib/rack/attack/store_proxy/mem_cache_store_proxy.rb +++ b/lib/rack/attack/store_proxy/mem_cache_store_proxy.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -require 'delegate' +require 'rack/attack/base_proxy' module Rack class Attack module StoreProxy - class MemCacheStoreProxy < SimpleDelegator + class MemCacheStoreProxy < BaseProxy def self.handle?(store) defined?(::Dalli) && defined?(::ActiveSupport::Cache::MemCacheStore) && diff --git a/lib/rack/attack/store_proxy/redis_cache_store_proxy.rb b/lib/rack/attack/store_proxy/redis_cache_store_proxy.rb index 9d1be74..00670f0 100644 --- a/lib/rack/attack/store_proxy/redis_cache_store_proxy.rb +++ b/lib/rack/attack/store_proxy/redis_cache_store_proxy.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -require 'delegate' +require 'rack/attack/base_proxy' module Rack class Attack module StoreProxy - class RedisCacheStoreProxy < SimpleDelegator + class RedisCacheStoreProxy < BaseProxy def self.handle?(store) store.class.name == "ActiveSupport::Cache::RedisCacheStore" end diff --git a/lib/rack/attack/store_proxy/redis_proxy.rb b/lib/rack/attack/store_proxy/redis_proxy.rb index e51b3e9..3127de6 100644 --- a/lib/rack/attack/store_proxy/redis_proxy.rb +++ b/lib/rack/attack/store_proxy/redis_proxy.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -require 'delegate' +require 'rack/attack/base_proxy' module Rack class Attack module StoreProxy - class RedisProxy < SimpleDelegator + class RedisProxy < BaseProxy def initialize(*args) if Gem::Version.new(Redis::VERSION) < Gem::Version.new("3") warn 'RackAttack requires Redis gem >= 3.0.0.' @@ -15,7 +15,7 @@ module Rack end def self.handle?(store) - defined?(::Redis) && store.is_a?(::Redis) + defined?(::Redis) && store.class == ::Redis end def read(key) diff --git a/lib/rack/attack/store_proxy/redis_store_proxy.rb b/lib/rack/attack/store_proxy/redis_store_proxy.rb index 6be5412..28557bc 100644 --- a/lib/rack/attack/store_proxy/redis_store_proxy.rb +++ b/lib/rack/attack/store_proxy/redis_store_proxy.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'delegate' +require 'rack/attack/store_proxy/redis_proxy' module Rack class Attack From 1e5fb868f685dca552d2fefe84863b273728bbae Mon Sep 17 00:00:00 2001 From: fatkodima Date: Thu, 31 Oct 2019 14:35:29 +0200 Subject: [PATCH 3/7] Auto include middleware for older railses --- README.md | 7 +------ lib/rack/attack/railtie.rb | 4 +--- spec/acceptance/rails_middleware_spec.rb | 21 +++------------------ 3 files changed, 5 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 86b92c4..738cb16 100644 --- a/README.md +++ b/README.md @@ -71,12 +71,7 @@ Or install it yourself as: Then tell your ruby web application to use rack-attack as a middleware. -a) For __rails__ applications with versions >= 5.1 it is used by default. For older rails versions you should enable it explicitly: -```ruby -# In config/application.rb - -config.middleware.use Rack::Attack -``` +a) For __rails__ applications it is used by default. You can disable it permanently (like for specific environment) or temporarily (can be useful for specific test cases) by writing: diff --git a/lib/rack/attack/railtie.rb b/lib/rack/attack/railtie.rb index 398ac6c..234e126 100644 --- a/lib/rack/attack/railtie.rb +++ b/lib/rack/attack/railtie.rb @@ -4,9 +4,7 @@ module Rack class Attack class Railtie < ::Rails::Railtie initializer "rack-attack.middleware" do |app| - if Gem::Version.new(::Rails::VERSION::STRING) >= Gem::Version.new("5.1") - app.middleware.use(Rack::Attack) - end + app.middleware.use(Rack::Attack) end end end diff --git a/spec/acceptance/rails_middleware_spec.rb b/spec/acceptance/rails_middleware_spec.rb index 8e7b014..0e14e89 100644 --- a/spec/acceptance/rails_middleware_spec.rb +++ b/spec/acceptance/rails_middleware_spec.rb @@ -12,24 +12,9 @@ if defined?(Rails) end end - if Gem::Version.new(Rails::VERSION::STRING) >= Gem::Version.new("5.1") - it "is used by default" do - @app.initialize! - assert_equal 1, @app.middleware.count(Rack::Attack) - end - - it "is not added when it was explicitly deleted" do - @app.config.middleware.delete(Rack::Attack) - @app.initialize! - refute @app.middleware.include?(Rack::Attack) - end - end - - if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new("5.1") - it "is not used by default" do - @app.initialize! - assert_equal 0, @app.middleware.count(Rack::Attack) - end + it "is used by default" do + @app.initialize! + assert @app.middleware.include?(Rack::Attack) end end end From d1b01f0b4ae669bbea862aa778c42a62d31265e6 Mon Sep 17 00:00:00 2001 From: Gonzalo Date: Fri, 25 Dec 2020 23:55:58 -0300 Subject: [PATCH 4/7] test: update ruby and rails versions --- .travis.yml | 8 -------- Appraisals | 8 ++------ gemfiles/active_support_redis_cache_store.gemfile | 2 +- gemfiles/active_support_redis_cache_store_pooled.gemfile | 2 +- gemfiles/rails_5_1.gemfile | 7 ------- 5 files changed, 4 insertions(+), 23 deletions(-) delete mode 100644 gemfiles/rails_5_1.gemfile diff --git a/.travis.yml b/.travis.yml index b2c79be..2275029 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,6 @@ rvm: - 2.7.2 - 2.6.6 - 2.5.8 - - 2.4.10 before_install: - yes | gem update --system @@ -19,7 +18,6 @@ gemfile: - gemfiles/rails_6_1.gemfile - gemfiles/rails_6_0.gemfile - gemfiles/rails_5_2.gemfile - - gemfiles/rails_5_1.gemfile - gemfiles/rails_4_2.gemfile - gemfiles/dalli2.gemfile - gemfiles/redis_4.gemfile @@ -36,8 +34,6 @@ matrix: rvm: 3.0.0 - gemfile: gemfiles/rails_5_2.gemfile rvm: 3.0.0 - - gemfile: gemfiles/rails_5_1.gemfile - rvm: 3.0.0 - gemfile: gemfiles/rails_4_2.gemfile rvm: 3.0.0 - gemfile: gemfiles/dalli2.gemfile @@ -48,10 +44,6 @@ matrix: rvm: 2.7.2 - gemfile: gemfiles/rails_4_2.gemfile rvm: 2.7.2 - - gemfile: gemfiles/rails_6_1.gemfile - rvm: 2.4.10 - - gemfile: gemfiles/rails_6_0.gemfile - rvm: 2.4.10 fast_finish: true services: diff --git a/Appraisals b/Appraisals index d4ee0a3..03c6a70 100644 --- a/Appraisals +++ b/Appraisals @@ -29,10 +29,6 @@ appraise 'rails_5-2' do gem 'railties', '~> 5.2.0' end -appraise 'rails_5-1' do - gem 'railties', '~> 5.1.0' -end - appraise 'rails_4-2' do gem 'railties', '~> 4.2.0' @@ -59,12 +55,12 @@ appraise "connection_pool_dalli" do end appraise "active_support_redis_cache_store" do - gem "activesupport", ">= 5.2", "< 6.2" + gem "activesupport", "~> 6.1.0" gem "redis", "~> 4.0" end appraise "active_support_redis_cache_store_pooled" do - gem "activesupport", ">= 5.2", "< 6.2" + gem "activesupport", "~> 6.1.0" gem "connection_pool", "~> 2.2" gem "redis", "~> 4.0" end diff --git a/gemfiles/active_support_redis_cache_store.gemfile b/gemfiles/active_support_redis_cache_store.gemfile index ac227aa..8acbbe1 100644 --- a/gemfiles/active_support_redis_cache_store.gemfile +++ b/gemfiles/active_support_redis_cache_store.gemfile @@ -2,7 +2,7 @@ source "https://rubygems.org" -gem "activesupport", ">= 5.2", "< 6.2" +gem "activesupport", "~> 6.1.0" gem "redis", "~> 4.0" gemspec path: "../" diff --git a/gemfiles/active_support_redis_cache_store_pooled.gemfile b/gemfiles/active_support_redis_cache_store_pooled.gemfile index 4e3af69..cf1e92e 100644 --- a/gemfiles/active_support_redis_cache_store_pooled.gemfile +++ b/gemfiles/active_support_redis_cache_store_pooled.gemfile @@ -2,7 +2,7 @@ source "https://rubygems.org" -gem "activesupport", ">= 5.2", "< 6.2" +gem "activesupport", "~> 6.1.0" gem "connection_pool", "~> 2.2" gem "redis", "~> 4.0" diff --git a/gemfiles/rails_5_1.gemfile b/gemfiles/rails_5_1.gemfile deleted file mode 100644 index 66a5a0b..0000000 --- a/gemfiles/rails_5_1.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "railties", "~> 5.1.0" - -gemspec path: "../" From 0f1a72a4d4f1056f89d60dd1d8e6f345be600b57 Mon Sep 17 00:00:00 2001 From: brchristian Date: Sat, 16 Jan 2021 10:19:33 -0800 Subject: [PATCH 5/7] Use single quotes in example configuration --- docs/example_configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/example_configuration.md b/docs/example_configuration.md index e1aaa38..b30a4ab 100644 --- a/docs/example_configuration.md +++ b/docs/example_configuration.md @@ -59,7 +59,7 @@ class Rack::Attack # throttle logins for another user and force their login requests to be # denied, but that's not very common and shouldn't happen to you. (Knock # on wood!) - throttle("logins/email", limit: 5, period: 20.seconds) do |req| + throttle('logins/email', limit: 5, period: 20.seconds) do |req| if req.path == '/login' && req.post? # Normalize the email, using the same logic as your authentication process, to # protect against rate limit bypasses. Return the normalized email if present, nil otherwise. From f3f0df3fc0c3438ac5be7e94583a6b8cb905f861 Mon Sep 17 00:00:00 2001 From: Gonzalo Date: Sun, 7 Feb 2021 13:34:26 -0300 Subject: [PATCH 6/7] refactor: attempt to avoid user confusion by clarifying method is used by throttle --- lib/rack/attack.rb | 4 ++-- lib/rack/attack/throttle.rb | 4 ++-- spec/rack_attack_throttle_spec.rb | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/rack/attack.rb b/lib/rack/attack.rb index afb5b08..7aa29c7 100644 --- a/lib/rack/attack.rb +++ b/lib/rack/attack.rb @@ -31,7 +31,7 @@ module Rack autoload :Allow2Ban, 'rack/attack/allow2ban' class << self - attr_accessor :enabled, :notifier, :discriminator_normalizer + attr_accessor :enabled, :notifier, :throttle_discriminator_normalizer attr_reader :configuration def instrument(request) @@ -83,7 +83,7 @@ module Rack # Set defaults @enabled = true @notifier = ActiveSupport::Notifications if defined?(ActiveSupport::Notifications) - @discriminator_normalizer = lambda do |discriminator| + @throttle_discriminator_normalizer = lambda do |discriminator| discriminator.to_s.strip.downcase end @configuration = Configuration.new diff --git a/lib/rack/attack/throttle.rb b/lib/rack/attack/throttle.rb index 1cc50f4..6992339 100644 --- a/lib/rack/attack/throttle.rb +++ b/lib/rack/attack/throttle.rb @@ -51,8 +51,8 @@ module Rack def discriminator_for(request) discriminator = block.call(request) - if discriminator && Rack::Attack.discriminator_normalizer - discriminator = Rack::Attack.discriminator_normalizer.call(discriminator) + if discriminator && Rack::Attack.throttle_discriminator_normalizer + discriminator = Rack::Attack.throttle_discriminator_normalizer.call(discriminator) end discriminator end diff --git a/spec/rack_attack_throttle_spec.rb b/spec/rack_attack_throttle_spec.rb index feb599c..0b0d68a 100644 --- a/spec/rack_attack_throttle_spec.rb +++ b/spec/rack_attack_throttle_spec.rb @@ -145,7 +145,7 @@ describe 'Rack::Attack.throttle with block retuning nil' do end end -describe 'Rack::Attack.throttle with discriminator_normalizer' do +describe 'Rack::Attack.throttle with throttle_discriminator_normalizer' do before do @period = 60 @emails = [ @@ -161,16 +161,16 @@ describe 'Rack::Attack.throttle with discriminator_normalizer' do end end - it 'should not differentiate requests when discriminator_normalizer is enabled' do + it 'should not differentiate requests when throttle_discriminator_normalizer is enabled' do post_logins key = "rack::attack:#{Time.now.to_i / @period}:logins/email:person@example.com" _(Rack::Attack.cache.store.read(key)).must_equal 3 end - it 'should differentiate requests when discriminator_normalizer is disabled' do + it 'should differentiate requests when throttle_discriminator_normalizer is disabled' do begin - prev = Rack::Attack.discriminator_normalizer - Rack::Attack.discriminator_normalizer = nil + prev = Rack::Attack.throttle_discriminator_normalizer + Rack::Attack.throttle_discriminator_normalizer = nil post_logins @emails.each do |email| @@ -178,7 +178,7 @@ describe 'Rack::Attack.throttle with discriminator_normalizer' do _(Rack::Attack.cache.store.read(key)).must_equal 1 end ensure - Rack::Attack.discriminator_normalizer = prev + Rack::Attack.throttle_discriminator_normalizer = prev end end From 12a8390d2dc0160f2966f0793a12ac2ce76bfe35 Mon Sep 17 00:00:00 2001 From: Gonzalo Date: Sun, 7 Feb 2021 13:34:46 -0300 Subject: [PATCH 7/7] Bump gem version to v6.5 --- CHANGELOG.md | 20 ++++++++++++++++++++ lib/rack/attack/version.rb | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 71008c9..e7fbfbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,25 @@ All notable changes to this project will be documented in this file. +## [6.5.0] - 2021-02-07 + +### Added + +- Added ability to normalize throttle discriminator by setting `Rack::Attack.throttle_discriminator_normalizer` (@fatkodima) + + Example: + + Rack::Attack.throttle_discriminator_normalizer = ->(discriminator) { ... } + + or disable default normalization with: + + Rack::Attack.throttle_discriminator_normalizer = nil + +### Removed + +- Dropped support for ruby v2.4 +- Dropped support for rails v5.1 + ## [6.4.0] - 2021-01-23 ### Added @@ -232,6 +251,7 @@ so your custom code is less prone to race conditions ([#282](https://github.com/ - Remove unused variable - Extract mandatory options to constants +[6.5.0]: https://github.com/rack/rack-attack/compare/v6.4.0...v6.5.0/ [6.4.0]: https://github.com/rack/rack-attack/compare/v6.3.1...v6.4.0/ [6.3.1]: https://github.com/rack/rack-attack/compare/v6.3.0...v6.3.1/ [6.3.0]: https://github.com/rack/rack-attack/compare/v6.2.2...v6.3.0/ diff --git a/lib/rack/attack/version.rb b/lib/rack/attack/version.rb index fb11922..0c28e15 100644 --- a/lib/rack/attack/version.rb +++ b/lib/rack/attack/version.rb @@ -2,6 +2,6 @@ module Rack class Attack - VERSION = '6.4.0' + VERSION = '6.5.0' end end