From 9923012fe81fe4a31f0f1e0f6100d268911a1c87 Mon Sep 17 00:00:00 2001 From: fatkodima Date: Thu, 10 Oct 2019 13:32:04 +0300 Subject: [PATCH 1/8] Allow to reset state between tests --- lib/rack/attack.rb | 5 +++++ lib/rack/attack/cache.rb | 11 +++++++++++ lib/rack/attack/store_proxy/redis_proxy.rb | 13 +++++++++++++ spec/rack_attack_spec.rb | 22 ++++++++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/lib/rack/attack.rb b/lib/rack/attack.rb index de5f745..f209d59 100644 --- a/lib/rack/attack.rb +++ b/lib/rack/attack.rb @@ -14,6 +14,7 @@ module Rack class Error < StandardError; end class MisconfiguredStoreError < Error; end class MissingStoreError < Error; end + class IncompatibleStoreError < Error; end autoload :Check, 'rack/attack/check' autoload :Throttle, 'rack/attack/throttle' @@ -53,6 +54,10 @@ module Rack @configuration.clear_configuration end + def reset! + cache.reset! + end + extend Forwardable def_delegators( :@configuration, diff --git a/lib/rack/attack/cache.rb b/lib/rack/attack/cache.rb index cfa2efa..0defa64 100644 --- a/lib/rack/attack/cache.rb +++ b/lib/rack/attack/cache.rb @@ -41,6 +41,17 @@ module Rack store.delete("#{prefix}:#{unprefixed_key}") end + def reset! + if store.respond_to?(:delete_matched) + store.delete_matched("#{prefix}*") + else + raise( + Rack::Attack::IncompatibleStoreError, + "Configured store #{store.class.name} doesn't respond to #delete_matched method" + ) + end + end + private def key_and_expiry(unprefixed_key, period) diff --git a/lib/rack/attack/store_proxy/redis_proxy.rb b/lib/rack/attack/store_proxy/redis_proxy.rb index d4e6f3a..e51b3e9 100644 --- a/lib/rack/attack/store_proxy/redis_proxy.rb +++ b/lib/rack/attack/store_proxy/redis_proxy.rb @@ -43,6 +43,19 @@ module Rack rescuing { del(key) } end + def delete_matched(matcher, _options = nil) + cursor = "0" + + rescuing do + # Fetch keys in batches using SCAN to avoid blocking the Redis server. + loop do + cursor, keys = scan(cursor, match: matcher, count: 1000) + del(*keys) unless keys.empty? + break if cursor == "0" + end + end + end + private def rescuing diff --git a/spec/rack_attack_spec.rb b/spec/rack_attack_spec.rb index 647a08d..d9bab4d 100644 --- a/spec/rack_attack_spec.rb +++ b/spec/rack_attack_spec.rb @@ -99,4 +99,26 @@ describe 'Rack::Attack' do end end end + + describe 'reset!' do + it 'raises an error when is not supported by cache store' do + Rack::Attack.cache.store = Class.new + assert_raises(Rack::Attack::IncompatibleStoreError) do + Rack::Attack.reset! + end + end + + if defined?(Redis) + it 'should delete rack attack keys' do + redis = Redis.new + redis.set('key', 'value') + redis.set("#{Rack::Attack.cache.prefix}::key", 'value') + Rack::Attack.cache.store = redis + Rack::Attack.reset! + + _(redis.get('key')).must_equal 'value' + _(redis.get("#{Rack::Attack.cache.prefix}::key")).must_be_nil + end + end + end end From 8bbd0ab702bced82d15b8d5f52b28242ef66a05d Mon Sep 17 00:00:00 2001 From: Gonzalo Date: Wed, 18 Dec 2019 13:35:08 -0300 Subject: [PATCH 2/8] ci: test against ruby 2.7.0 - don't test ruby 2.7.0 with incompatible rails versions --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0506907..c310aac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ cache: bundler rvm: - ruby-head + - 2.7.0-preview3 - 2.6.5 - 2.5.7 - 2.4.9 @@ -33,6 +34,10 @@ matrix: allow_failures: - rvm: ruby-head exclude: + - gemfile: gemfiles/rack_1_6.gemfile + rvm: 2.7.0-preview3 + - gemfile: gemfiles/rails_4_2.gemfile + rvm: 2.7.0-preview3 - gemfile: gemfiles/rails_6_0.gemfile rvm: 2.4.9 - gemfile: gemfiles/rails_6_0.gemfile From fadb98f25c45d25ea840c3bce2ec0f5149ac7ce8 Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Tue, 22 Oct 2019 14:28:34 -0300 Subject: [PATCH 3/8] ci: update Travis dist to bionic --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index c310aac..129cf5b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,4 @@ -dist: xenial +dist: bionic language: ruby cache: bundler From aeac2d488707438ebbca2ecbb63295a59d3d2800 Mon Sep 17 00:00:00 2001 From: Gonzalo Date: Mon, 6 Jan 2020 13:09:04 -0300 Subject: [PATCH 4/8] ci: update to final ruby 2.7 --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 129cf5b..4033113 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ cache: bundler rvm: - ruby-head - - 2.7.0-preview3 + - 2.7.0 - 2.6.5 - 2.5.7 - 2.4.9 @@ -35,9 +35,9 @@ matrix: - rvm: ruby-head exclude: - gemfile: gemfiles/rack_1_6.gemfile - rvm: 2.7.0-preview3 + rvm: 2.7.0 - gemfile: gemfiles/rails_4_2.gemfile - rvm: 2.7.0-preview3 + rvm: 2.7.0 - gemfile: gemfiles/rails_6_0.gemfile rvm: 2.4.9 - gemfile: gemfiles/rails_6_0.gemfile From 8787f7db5a7fb359923d6fd0f8a7802d18aec306 Mon Sep 17 00:00:00 2001 From: Gonzalo Date: Tue, 4 Feb 2020 14:15:07 -0300 Subject: [PATCH 5/8] ci: test against latest rack minor versions --- .travis.yml | 6 +++--- Appraisals | 8 ++++---- gemfiles/{rack_1_6.gemfile => rack_1.gemfile} | 2 +- gemfiles/{rack_2_0.gemfile => rack_2.gemfile} | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) rename gemfiles/{rack_1_6.gemfile => rack_1.gemfile} (88%) rename gemfiles/{rack_2_0.gemfile => rack_2.gemfile} (80%) diff --git a/.travis.yml b/.travis.yml index 4033113..ece47e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,8 @@ before_install: - gem install bundler -v "~> 2.0" gemfile: - - gemfiles/rack_2_0.gemfile - - gemfiles/rack_1_6.gemfile + - gemfiles/rack_2.gemfile + - gemfiles/rack_1.gemfile - gemfiles/rails_6_0.gemfile - gemfiles/rails_5_2.gemfile - gemfiles/rails_5_1.gemfile @@ -34,7 +34,7 @@ matrix: allow_failures: - rvm: ruby-head exclude: - - gemfile: gemfiles/rack_1_6.gemfile + - gemfile: gemfiles/rack_1.gemfile rvm: 2.7.0 - gemfile: gemfiles/rails_4_2.gemfile rvm: 2.7.0 diff --git a/Appraisals b/Appraisals index 834d201..ef44d14 100644 --- a/Appraisals +++ b/Appraisals @@ -1,16 +1,16 @@ # frozen_string_literal: true -appraise "rack_2_0" do - gem "rack", "~> 2.0.4" +appraise "rack_2" do + gem "rack", "~> 2.0" end -appraise "rack_1_6" do +appraise "rack_1" do # Override activesupport and actionpack version constraints by making # it more loose so it's compatible with rack 1.6.x gem "actionpack", ">= 4.2" gem "activesupport", ">= 4.2" - gem "rack", "~> 1.6.9" + gem "rack", "~> 1.6" # Override rack-test version constraint by making it more loose # so it's compatible with actionpack 4.2.x diff --git a/gemfiles/rack_1_6.gemfile b/gemfiles/rack_1.gemfile similarity index 88% rename from gemfiles/rack_1_6.gemfile rename to gemfiles/rack_1.gemfile index 0cc0050..2390b85 100644 --- a/gemfiles/rack_1_6.gemfile +++ b/gemfiles/rack_1.gemfile @@ -4,7 +4,7 @@ source "https://rubygems.org" gem "actionpack", ">= 4.2" gem "activesupport", ">= 4.2" -gem "rack", "~> 1.6.9" +gem "rack", "~> 1.6" gem "rack-test", ">= 0.6" gemspec path: "../" diff --git a/gemfiles/rack_2_0.gemfile b/gemfiles/rack_2.gemfile similarity index 80% rename from gemfiles/rack_2_0.gemfile rename to gemfiles/rack_2.gemfile index 9915a10..964e087 100644 --- a/gemfiles/rack_2_0.gemfile +++ b/gemfiles/rack_2.gemfile @@ -2,6 +2,6 @@ source "https://rubygems.org" -gem "rack", "~> 2.0.4" +gem "rack", "~> 2.0" gemspec path: "../" From 4c33737ed337c0a14c1b362ae7a5697cdad49441 Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Wed, 25 Dec 2019 18:10:42 -0300 Subject: [PATCH 6/8] build: update rubocop to v0.78 --- .rubocop.yml | 12 ++++++------ rack-attack.gemspec | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 28f8502..7fe2ca6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -21,6 +21,9 @@ Gemspec: Layout: Enabled: true +Layout/LineLength: + Max: 120 + Lint: Enabled: true @@ -29,9 +32,6 @@ Naming: Exclude: - "lib/rack/attack/path_normalizer.rb" -Metrics/LineLength: - Max: 120 - Performance: Enabled: true @@ -83,6 +83,9 @@ Style/RedundantBegin: Style/RedundantFreeze: Enabled: true +Style/RedundantPercentQ: + Enabled: true + Style/RedundantSelf: Enabled: true @@ -94,6 +97,3 @@ Style/SingleLineMethods: Style/SpecialGlobalVars: Enabled: true - -Style/UnneededPercentQ: - Enabled: true diff --git a/rack-attack.gemspec b/rack-attack.gemspec index 0bebfa3..99deeb7 100644 --- a/rack-attack.gemspec +++ b/rack-attack.gemspec @@ -37,7 +37,7 @@ Gem::Specification.new do |s| s.add_development_dependency "minitest-stub-const", "~> 0.6" s.add_development_dependency 'rack-test', "~> 1.0" s.add_development_dependency 'rake', "~> 13.0" - s.add_development_dependency "rubocop", "0.75.0" + s.add_development_dependency "rubocop", "0.78.0" s.add_development_dependency "rubocop-performance", "~> 1.5.0" s.add_development_dependency "timecop", "~> 0.9.1" From 76bbada48fcd9ed2d0b02bc7e8f6f36ce35bab9e Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Sat, 25 Apr 2020 15:30:42 -0300 Subject: [PATCH 7/8] ci: update rubies --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index ece47e2..98432ae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,10 @@ cache: bundler rvm: - ruby-head - - 2.7.0 - - 2.6.5 - - 2.5.7 - - 2.4.9 + - 2.7.1 + - 2.6.6 + - 2.5.8 + - 2.4.10 - 2.3.8 before_install: @@ -35,11 +35,11 @@ matrix: - rvm: ruby-head exclude: - gemfile: gemfiles/rack_1.gemfile - rvm: 2.7.0 + rvm: 2.7.1 - gemfile: gemfiles/rails_4_2.gemfile - rvm: 2.7.0 + rvm: 2.7.1 - gemfile: gemfiles/rails_6_0.gemfile - rvm: 2.4.9 + rvm: 2.4.10 - gemfile: gemfiles/rails_6_0.gemfile rvm: 2.3.8 fast_finish: true From aa071aa5df4289dd3d7029b187320afa62974685 Mon Sep 17 00:00:00 2001 From: Gonzalo Rodriguez Date: Sat, 25 Apr 2020 16:41:28 -0300 Subject: [PATCH 8/8] Bump gem version to v6.3.0 --- CHANGELOG.md | 18 ++++++++++++++++++ lib/rack/attack/version.rb | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7f382d..fb5506a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. +## [6.3.0] - 2020-04-26 + +### Added + +- `Rack::Attack.reset!` to reset state (#436) (@fatkodima) +- `Rack::Attack.throttled_response_retry_after_header=` setting that enables a `Retry-After` response header when client is throttled (#440) (@fatkodima) + +### Changed + +- No longer swallow Redis non-connection errors if Redis is configured as cache store (#450) (@fatkodima) + +### Fixed + +- `Rack::Attack.clear_configuration` also clears `blocklisted_response` and `throttled_response` back to defaults + ## [6.2.2] - 2019-12-18 ### Fixed @@ -201,6 +216,7 @@ so your custom code is less prone to race conditions ([#282](https://github.com/ - Remove unused variable - Extract mandatory options to constants +[6.3.0]: https://github.com/kickstarter/rack-attack/compare/v6.2.2...v6.3.0/ [6.2.2]: https://github.com/kickstarter/rack-attack/compare/v6.2.1...v6.2.2/ [6.2.1]: https://github.com/kickstarter/rack-attack/compare/v6.2.0...v6.2.1/ [6.2.0]: https://github.com/kickstarter/rack-attack/compare/v6.1.0...v6.2.0/ @@ -229,3 +245,5 @@ so your custom code is less prone to race conditions ([#282](https://github.com/ [2.3.0]: https://github.com/kickstarter/rack-attack/compare/v2.2.1...v2.3.0/ [2.2.1]: https://github.com/kickstarter/rack-attack/compare/v2.2.0...v2.2.1/ [2.2.0]: https://github.com/kickstarter/rack-attack/compare/v2.1.1...v2.2.0/ + +[@fatkodima]: https://github.com/fatkodima diff --git a/lib/rack/attack/version.rb b/lib/rack/attack/version.rb index a4b448c..67b60a5 100644 --- a/lib/rack/attack/version.rb +++ b/lib/rack/attack/version.rb @@ -2,6 +2,6 @@ module Rack class Attack - VERSION = '6.2.2' + VERSION = '6.3.0' end end