rack-attack 5.3.1 → 5.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f06d0fae1f4dc5d960274ca06a4da7be66a1180a3df051595c98813296e80e46
4
- data.tar.gz: 32fa128bb61140836c8fcce73d1cd972c3987405e581a43dea2334d6ba05cfa7
3
+ metadata.gz: 30b1caccf538327c289b6e4962e2deadc4d7c5fc8509eb1adbf4383c950bd4ad
4
+ data.tar.gz: 4b8af97dca4e04414712cce9ba21cc7940f46e2072d3cc9e288b5bf54d066bba
5
5
  SHA512:
6
- metadata.gz: 7d7be10e1ddb908f07fb10aec414f47fcb9d23289eacd98a1a91e1f87ffa0212d63f424fff44bcfa0b0154263518d807e535bcd8791200c8dc290ea31bd4395e
7
- data.tar.gz: c99bfe7df1e11591e80526fd17b414494ddaa797906a4cced2beca884fe51db9fe9ce9d4dd99ee92ac98921a35f87361944ca4d8895b83a86ccc442b6d5cae31
6
+ metadata.gz: f439d0196c505e73f10671f30d1b9cf919fb1b185468f38915817782cfecdc59d6405bd4d1a895e956de2f788c33524f232bd5c4eadee36dffe1883b0954efdb
7
+ data.tar.gz: a736973564ec15f143fbb6b5067441eea50cbc33385a557b1d6d13180b5237982cc676de6ee97989e06fa97185666811945b85d6a8263c19c0a16446407afa22
@@ -81,40 +81,40 @@ class Rack::Attack
81
81
  blocklists
82
82
  end
83
83
 
84
- def safelisted?(req)
85
- ip_safelists.any? { |safelist| safelist.match?(req) } ||
86
- safelists.any? { |_name, safelist| safelist.match?(req) }
84
+ def safelisted?(request)
85
+ ip_safelists.any? { |safelist| safelist.matched_by?(request) } ||
86
+ safelists.any? { |_name, safelist| safelist.matched_by?(request) }
87
87
  end
88
88
 
89
- def whitelisted?(req)
89
+ def whitelisted?(request)
90
90
  warn "[DEPRECATION] 'Rack::Attack.whitelisted?' is deprecated. Please use 'safelisted?' instead."
91
- safelisted?(req)
91
+ safelisted?(request)
92
92
  end
93
93
 
94
- def blocklisted?(req)
95
- ip_blocklists.any? { |blocklist| blocklist.match?(req) } ||
96
- blocklists.any? { |_name, blocklist| blocklist.match?(req) }
94
+ def blocklisted?(request)
95
+ ip_blocklists.any? { |blocklist| blocklist.matched_by?(request) } ||
96
+ blocklists.any? { |_name, blocklist| blocklist.matched_by?(request) }
97
97
  end
98
98
 
99
- def blacklisted?(req)
99
+ def blacklisted?(request)
100
100
  warn "[DEPRECATION] 'Rack::Attack.blacklisted?' is deprecated. Please use 'blocklisted?' instead."
101
- blocklisted?(req)
101
+ blocklisted?(request)
102
102
  end
103
103
 
104
- def throttled?(req)
104
+ def throttled?(request)
105
105
  throttles.any? do |_name, throttle|
106
- throttle[req]
106
+ throttle.matched_by?(request)
107
107
  end
108
108
  end
109
109
 
110
- def tracked?(req)
111
- tracks.each_value do |tracker|
112
- tracker[req]
110
+ def tracked?(request)
111
+ tracks.each_value do |track|
112
+ track.matched_by?(request)
113
113
  end
114
114
  end
115
115
 
116
- def instrument(req)
117
- notifier.instrument('rack.attack', req) if notifier
116
+ def instrument(request)
117
+ notifier.instrument('rack.attack', request) if notifier
118
118
  end
119
119
 
120
120
  def cache
@@ -167,16 +167,16 @@ class Rack::Attack
167
167
 
168
168
  def call(env)
169
169
  env['PATH_INFO'] = PathNormalizer.normalize_path(env['PATH_INFO'])
170
- req = Rack::Attack::Request.new(env)
170
+ request = Rack::Attack::Request.new(env)
171
171
 
172
- if safelisted?(req)
172
+ if safelisted?(request)
173
173
  @app.call(env)
174
- elsif blocklisted?(req)
174
+ elsif blocklisted?(request)
175
175
  self.class.blocklisted_response.call(env)
176
- elsif throttled?(req)
176
+ elsif throttled?(request)
177
177
  self.class.throttled_response.call(env)
178
178
  else
179
- tracked?(req)
179
+ tracked?(request)
180
180
  @app.call(env)
181
181
  end
182
182
  end
@@ -7,17 +7,15 @@ module Rack
7
7
  @type = options.fetch(:type, nil)
8
8
  end
9
9
 
10
- def [](req)
11
- block[req].tap { |match|
10
+ def matched_by?(request)
11
+ block.call(request).tap do |match|
12
12
  if match
13
- req.env["rack.attack.matched"] = name
14
- req.env["rack.attack.match_type"] = type
15
- Rack::Attack.instrument(req)
13
+ request.env["rack.attack.matched"] = name
14
+ request.env["rack.attack.match_type"] = type
15
+ Rack::Attack.instrument(request)
16
16
  end
17
- }
17
+ end
18
18
  end
19
-
20
- alias_method :match?, :[]
21
19
  end
22
20
  end
23
21
  end
@@ -5,7 +5,7 @@ module Rack
5
5
  module StoreProxy
6
6
  class RedisCacheStoreProxy < SimpleDelegator
7
7
  def self.handle?(store)
8
- defined?(::ActiveSupport::Cache::RedisCacheStore) && store.is_a?(::ActiveSupport::Cache::RedisCacheStore)
8
+ defined?(::Redis) && defined?(::ActiveSupport::Cache::RedisCacheStore) && store.is_a?(::ActiveSupport::Cache::RedisCacheStore)
9
9
  end
10
10
 
11
11
  def increment(name, amount = 1, options = {})
@@ -16,7 +16,7 @@ module Rack
16
16
  if options[:expires_in] && !read(name)
17
17
  write(name, amount, options)
18
18
 
19
- 1
19
+ amount
20
20
  else
21
21
  super
22
22
  end
@@ -18,12 +18,12 @@ module Rack
18
18
  Rack::Attack.cache
19
19
  end
20
20
 
21
- def [](req)
22
- discriminator = block[req]
21
+ def matched_by?(request)
22
+ discriminator = block.call(request)
23
23
  return false unless discriminator
24
24
 
25
- current_period = period.respond_to?(:call) ? period.call(req) : period
26
- current_limit = limit.respond_to?(:call) ? limit.call(req) : limit
25
+ current_period = period.respond_to?(:call) ? period.call(request) : period
26
+ current_limit = limit.respond_to?(:call) ? limit.call(request) : limit
27
27
  key = "#{name}:#{discriminator}"
28
28
  count = cache.count(key, current_period)
29
29
 
@@ -32,15 +32,15 @@ module Rack
32
32
  :period => current_period,
33
33
  :limit => current_limit
34
34
  }
35
- (req.env['rack.attack.throttle_data'] ||= {})[name] = data
35
+ (request.env['rack.attack.throttle_data'] ||= {})[name] = data
36
36
 
37
37
  (count > current_limit).tap do |throttled|
38
38
  if throttled
39
- req.env['rack.attack.matched'] = name
40
- req.env['rack.attack.match_discriminator'] = discriminator
41
- req.env['rack.attack.match_type'] = type
42
- req.env['rack.attack.match_data'] = data
43
- Rack::Attack.instrument(req)
39
+ request.env['rack.attack.matched'] = name
40
+ request.env['rack.attack.match_discriminator'] = discriminator
41
+ request.env['rack.attack.match_type'] = type
42
+ request.env['rack.attack.match_data'] = data
43
+ Rack::Attack.instrument(request)
44
44
  end
45
45
  end
46
46
  end
@@ -1,8 +1,6 @@
1
1
  module Rack
2
2
  class Attack
3
3
  class Track
4
- extend Forwardable
5
-
6
4
  attr_reader :filter
7
5
 
8
6
  def initialize(name, options = {}, block)
@@ -15,7 +13,9 @@ module Rack
15
13
  end
16
14
  end
17
15
 
18
- def_delegator :@filter, :[]
16
+ def matched_by?(request)
17
+ filter.matched_by?(request)
18
+ end
19
19
  end
20
20
  end
21
21
  end
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class Attack
3
- VERSION = '5.3.1'
3
+ VERSION = '5.3.2'
4
4
  end
5
5
  end
@@ -0,0 +1,41 @@
1
+ require_relative "../../spec_helper"
2
+
3
+ if defined?(::Dalli)
4
+ require_relative "../../support/cache_store_helper"
5
+ require "active_support/cache/dalli_store"
6
+ require "timecop"
7
+
8
+ describe "ActiveSupport::Cache::DalliStore as a cache backend" do
9
+ before do
10
+ Rack::Attack.cache.store = ActiveSupport::Cache::DalliStore.new
11
+ end
12
+
13
+ after do
14
+ Rack::Attack.cache.store.clear
15
+ end
16
+
17
+ it_works_for_cache_backed_features
18
+
19
+ it "doesn't leak keys" do
20
+ Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
21
+ request.ip
22
+ end
23
+
24
+ key = nil
25
+
26
+ # Freeze time during these statement to be sure that the key used by rack attack is the same
27
+ # we pre-calculate in local variable `key`
28
+ Timecop.freeze do
29
+ key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
30
+
31
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
32
+ end
33
+
34
+ assert Rack::Attack.cache.store.fetch(key)
35
+
36
+ sleep 2.1
37
+
38
+ assert_nil Rack::Attack.cache.store.fetch(key)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,40 @@
1
+ require_relative "../../spec_helper"
2
+
3
+ if defined?(::Dalli)
4
+ require_relative "../../support/cache_store_helper"
5
+ require "timecop"
6
+
7
+ describe "ActiveSupport::Cache::MemCacheStore as a cache backend" do
8
+ before do
9
+ Rack::Attack.cache.store = ActiveSupport::Cache::MemCacheStore.new
10
+ end
11
+
12
+ after do
13
+ Rack::Attack.cache.store.flush_all
14
+ end
15
+
16
+ it_works_for_cache_backed_features
17
+
18
+ it "doesn't leak keys" do
19
+ Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
20
+ request.ip
21
+ end
22
+
23
+ key = nil
24
+
25
+ # Freeze time during these statement to be sure that the key used by rack attack is the same
26
+ # we pre-calculate in local variable `key`
27
+ Timecop.freeze do
28
+ key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
29
+
30
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
31
+ end
32
+
33
+ assert Rack::Attack.cache.store.get(key)
34
+
35
+ sleep 2.1
36
+
37
+ assert_nil Rack::Attack.cache.store.get(key)
38
+ end
39
+ end
40
+ end
@@ -3,13 +3,13 @@ require_relative "../../support/cache_store_helper"
3
3
 
4
4
  require "timecop"
5
5
 
6
- describe "MemCacheStore as a cache backend" do
6
+ describe "ActiveSupport::Cache::MemoryStore as a cache backend" do
7
7
  before do
8
- Rack::Attack.cache.store = ActiveSupport::Cache::MemCacheStore.new
8
+ Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
9
9
  end
10
10
 
11
11
  after do
12
- Rack::Attack.cache.store.flush_all
12
+ Rack::Attack.cache.store.clear
13
13
  end
14
14
 
15
15
  it_works_for_cache_backed_features
@@ -29,10 +29,10 @@ describe "MemCacheStore as a cache backend" do
29
29
  get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
30
30
  end
31
31
 
32
- assert Rack::Attack.cache.store.get(key)
32
+ assert Rack::Attack.cache.store.fetch(key)
33
33
 
34
34
  sleep 2.1
35
35
 
36
- assert_nil Rack::Attack.cache.store.get(key)
36
+ assert_nil Rack::Attack.cache.store.fetch(key)
37
37
  end
38
38
  end
@@ -1,10 +1,10 @@
1
1
  require_relative "../../spec_helper"
2
- require_relative "../../support/cache_store_helper"
3
2
 
4
- require "timecop"
3
+ if defined?(::ConnectionPool) && defined?(::Redis) && defined?(::ActiveSupport::Cache::RedisCacheStore)
4
+ require_relative "../../support/cache_store_helper"
5
+ require "timecop"
5
6
 
6
- if ActiveSupport.version >= Gem::Version.new("5.2.0")
7
- describe "RedisCacheStore (pooled) as a cache backend" do
7
+ describe "ActiveSupport::Cache::RedisCacheStore (pooled) as a cache backend" do
8
8
  before do
9
9
  Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new(pool_size: 2)
10
10
  end
@@ -1,10 +1,10 @@
1
1
  require_relative "../../spec_helper"
2
- require_relative "../../support/cache_store_helper"
3
2
 
4
- require "timecop"
3
+ if defined?(::Redis) && defined?(::ActiveSupport::Cache::RedisCacheStore)
4
+ require_relative "../../support/cache_store_helper"
5
+ require "timecop"
5
6
 
6
- if ActiveSupport.version >= Gem::Version.new("5.2.0")
7
- describe "RedisCacheStore as a cache backend" do
7
+ describe "ActiveSupport::Cache::RedisCacheStore as a cache backend" do
8
8
  before do
9
9
  Rack::Attack.cache.store = ActiveSupport::Cache::RedisCacheStore.new
10
10
  end
@@ -0,0 +1,40 @@
1
+ require_relative "../../spec_helper"
2
+
3
+ if defined?(::ActiveSupport::Cache::RedisStore)
4
+ require_relative "../../support/cache_store_helper"
5
+ require "timecop"
6
+
7
+ describe "ActiveSupport::Cache::RedisStore as a cache backend" do
8
+ before do
9
+ Rack::Attack.cache.store = ActiveSupport::Cache::RedisStore.new
10
+ end
11
+
12
+ after do
13
+ Rack::Attack.cache.store.flushdb
14
+ end
15
+
16
+ it_works_for_cache_backed_features
17
+
18
+ it "doesn't leak keys" do
19
+ Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
20
+ request.ip
21
+ end
22
+
23
+ key = nil
24
+
25
+ # Freeze time during these statement to be sure that the key used by rack attack is the same
26
+ # we pre-calculate in local variable `key`
27
+ Timecop.freeze do
28
+ key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
29
+
30
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
31
+ end
32
+
33
+ assert Rack::Attack.cache.store.read(key)
34
+
35
+ sleep 2.1
36
+
37
+ assert_nil Rack::Attack.cache.store.read(key)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,42 @@
1
+ require_relative "../../spec_helper"
2
+
3
+ if defined?(::Dalli) && defined?(::ConnectionPool)
4
+ require_relative "../../support/cache_store_helper"
5
+ require "connection_pool"
6
+ require "dalli"
7
+ require "timecop"
8
+
9
+ describe "ConnectionPool with Dalli::Client as a cache backend" do
10
+ before do
11
+ Rack::Attack.cache.store = ConnectionPool.new { Dalli::Client.new }
12
+ end
13
+
14
+ after do
15
+ Rack::Attack.cache.store.with { |client| client.flush_all }
16
+ end
17
+
18
+ it_works_for_cache_backed_features
19
+
20
+ it "doesn't leak keys" do
21
+ Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
22
+ request.ip
23
+ end
24
+
25
+ key = nil
26
+
27
+ # Freeze time during these statement to be sure that the key used by rack attack is the same
28
+ # we pre-calculate in local variable `key`
29
+ Timecop.freeze do
30
+ key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
31
+
32
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
33
+ end
34
+
35
+ assert(Rack::Attack.cache.store.with { |client| client.fetch(key) })
36
+
37
+ sleep 2.1
38
+
39
+ assert_nil(Rack::Attack.cache.store.with { |client| client.fetch(key) })
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,41 @@
1
+ require_relative "../../spec_helper"
2
+
3
+ if defined?(::Dalli)
4
+ require_relative "../../support/cache_store_helper"
5
+ require "dalli"
6
+ require "timecop"
7
+
8
+ describe "Dalli::Client as a cache backend" do
9
+ before do
10
+ Rack::Attack.cache.store = Dalli::Client.new
11
+ end
12
+
13
+ after do
14
+ Rack::Attack.cache.store.flush_all
15
+ end
16
+
17
+ it_works_for_cache_backed_features
18
+
19
+ it "doesn't leak keys" do
20
+ Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
21
+ request.ip
22
+ end
23
+
24
+ key = nil
25
+
26
+ # Freeze time during these statement to be sure that the key used by rack attack is the same
27
+ # we pre-calculate in local variable `key`
28
+ Timecop.freeze do
29
+ key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
30
+
31
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
32
+ end
33
+
34
+ assert Rack::Attack.cache.store.fetch(key)
35
+
36
+ sleep 2.1
37
+
38
+ assert_nil Rack::Attack.cache.store.fetch(key)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,40 @@
1
+ require_relative "../../spec_helper"
2
+ require_relative "../../support/cache_store_helper"
3
+
4
+ if defined?(::Redis::Store)
5
+ require "timecop"
6
+
7
+ describe "ActiveSupport::Cache::RedisStore as a cache backend" do
8
+ before do
9
+ Rack::Attack.cache.store = ::Redis::Store.new
10
+ end
11
+
12
+ after do
13
+ Rack::Attack.cache.store.flushdb
14
+ end
15
+
16
+ it_works_for_cache_backed_features
17
+
18
+ it "doesn't leak keys" do
19
+ Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
20
+ request.ip
21
+ end
22
+
23
+ key = nil
24
+
25
+ # Freeze time during these statement to be sure that the key used by rack attack is the same
26
+ # we pre-calculate in local variable `key`
27
+ Timecop.freeze do
28
+ key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
29
+
30
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
31
+ end
32
+
33
+ assert Rack::Attack.cache.store.read(key)
34
+
35
+ sleep 2.1
36
+
37
+ assert_nil Rack::Attack.cache.store.read(key)
38
+ end
39
+ end
40
+ end
@@ -1,6 +1,4 @@
1
1
  require 'active_support/cache'
2
- require 'redis-activesupport'
3
- require 'dalli'
4
2
  require_relative '../spec_helper'
5
3
 
6
4
  OfflineExamples = Minitest::SharedExamples.new do
@@ -17,27 +15,31 @@ OfflineExamples = Minitest::SharedExamples.new do
17
15
  end
18
16
  end
19
17
 
20
- describe 'when Redis is offline' do
21
- include OfflineExamples
18
+ if defined?(::ActiveSupport::Cache::RedisStore)
19
+ describe 'when Redis is offline' do
20
+ include OfflineExamples
22
21
 
23
- before {
24
- @cache = Rack::Attack::Cache.new
25
- # Use presumably unused port for Redis client
26
- @cache.store = ActiveSupport::Cache::RedisStore.new(:host => '127.0.0.1', :port => 3333)
27
- }
22
+ before do
23
+ @cache = Rack::Attack::Cache.new
24
+ # Use presumably unused port for Redis client
25
+ @cache.store = ActiveSupport::Cache::RedisStore.new(:host => '127.0.0.1', :port => 3333)
26
+ end
27
+ end
28
28
  end
29
29
 
30
- describe 'when Memcached is offline' do
31
- include OfflineExamples
30
+ if defined?(::Dalli)
31
+ describe 'when Memcached is offline' do
32
+ include OfflineExamples
32
33
 
33
- before {
34
- Dalli.logger.level = Logger::FATAL
34
+ before do
35
+ Dalli.logger.level = Logger::FATAL
35
36
 
36
- @cache = Rack::Attack::Cache.new
37
- @cache.store = Dalli::Client.new('127.0.0.1:22122')
38
- }
37
+ @cache = Rack::Attack::Cache.new
38
+ @cache.store = Dalli::Client.new('127.0.0.1:22122')
39
+ end
39
40
 
40
- after {
41
- Dalli.logger.level = Logger::INFO
42
- }
41
+ after do
42
+ Dalli.logger.level = Logger::INFO
43
+ end
44
+ end
43
45
  end
@@ -47,15 +47,15 @@ describe 'Rack::Attack.track' do
47
47
 
48
48
  describe "without limit and period options" do
49
49
  it "should assign the track filter to a Check instance" do
50
- tracker = Rack::Attack.track("homepage") { |req| req.path == "/" }
51
- tracker.filter.class.must_equal Rack::Attack::Check
50
+ track = Rack::Attack.track("homepage") { |req| req.path == "/" }
51
+ track.filter.class.must_equal Rack::Attack::Check
52
52
  end
53
53
  end
54
54
 
55
55
  describe "with limit and period options" do
56
56
  it "should assign the track filter to a Throttle instance" do
57
- tracker = Rack::Attack.track("homepage", :limit => 10, :period => 10) { |req| req.path == "/" }
58
- tracker.filter.class.must_equal Rack::Attack::Throttle
57
+ track = Rack::Attack.track("homepage", :limit => 10, :period => 10) { |req| req.path == "/" }
58
+ track.filter.class.must_equal Rack::Attack::Throttle
59
59
  end
60
60
  end
61
61
  end
@@ -9,16 +9,23 @@ require 'action_dispatch'
9
9
 
10
10
  require "rack/attack"
11
11
 
12
- begin
13
- require 'pry'
14
- rescue LoadError
15
- # nothing to do here
16
- end
17
-
18
12
  if RUBY_ENGINE == "ruby"
19
13
  require "byebug"
20
14
  end
21
15
 
16
+ def safe_require(name)
17
+ begin
18
+ require name
19
+ rescue LoadError
20
+ end
21
+ end
22
+
23
+ safe_require "connection_pool"
24
+ safe_require "dalli"
25
+ safe_require "redis"
26
+ safe_require "redis-activesupport"
27
+ safe_require "redis-store"
28
+
22
29
  class MiniTest::Spec
23
30
  include Rack::Test::Methods
24
31
 
@@ -36,14 +43,14 @@ class MiniTest::Spec
36
43
  end
37
44
 
38
45
  def app
39
- Rack::Builder.new {
46
+ Rack::Builder.new do
40
47
  # Use Rack::Lint to test that rack-attack is complying with the rack spec
41
48
  use Rack::Lint
42
49
  use Rack::Attack
43
50
  use Rack::Lint
44
51
 
45
52
  run lambda { |_env| [200, {}, ['Hello World']] }
46
- }.to_app
53
+ end.to_app
47
54
  end
48
55
 
49
56
  def self.it_allows_ok_requests
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-attack
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.1
4
+ version: 5.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Suggs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-06-20 00:00:00.000000000 Z
11
+ date: 2018-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -24,244 +24,146 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: actionpack
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 3.0.0
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 3.0.0
41
- - !ruby/object:Gem::Dependency
42
- name: activesupport
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: 3.0.0
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: 3.0.0
55
27
  - !ruby/object:Gem::Dependency
56
28
  name: appraisal
57
29
  requirement: !ruby/object:Gem::Requirement
58
30
  requirements:
59
- - - ">="
31
+ - - "~>"
60
32
  - !ruby/object:Gem::Version
61
- version: '0'
33
+ version: '2.2'
62
34
  type: :development
63
35
  prerelease: false
64
36
  version_requirements: !ruby/object:Gem::Requirement
65
37
  requirements:
66
- - - ">="
38
+ - - "~>"
67
39
  - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: connection_pool
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: dalli
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
- - !ruby/object:Gem::Dependency
98
- name: guard-minitest
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ">="
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
- - !ruby/object:Gem::Dependency
112
- name: memcache-client
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ">="
123
- - !ruby/object:Gem::Version
124
- version: '0'
40
+ version: '2.2'
125
41
  - !ruby/object:Gem::Dependency
126
42
  name: minitest
127
43
  requirement: !ruby/object:Gem::Requirement
128
44
  requirements:
129
- - - ">="
45
+ - - "~>"
130
46
  - !ruby/object:Gem::Version
131
- version: '0'
47
+ version: '5.11'
132
48
  type: :development
133
49
  prerelease: false
134
50
  version_requirements: !ruby/object:Gem::Requirement
135
51
  requirements:
136
- - - ">="
52
+ - - "~>"
137
53
  - !ruby/object:Gem::Version
138
- version: '0'
54
+ version: '5.11'
139
55
  - !ruby/object:Gem::Dependency
140
56
  name: minitest-stub-const
141
57
  requirement: !ruby/object:Gem::Requirement
142
58
  requirements:
143
- - - ">="
144
- - !ruby/object:Gem::Version
145
- version: '0'
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ">="
151
- - !ruby/object:Gem::Version
152
- version: '0'
153
- - !ruby/object:Gem::Dependency
154
- name: pry
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
59
+ - - "~>"
158
60
  - !ruby/object:Gem::Version
159
- version: '0'
61
+ version: '0.6'
160
62
  type: :development
161
63
  prerelease: false
162
64
  version_requirements: !ruby/object:Gem::Requirement
163
65
  requirements:
164
- - - ">="
66
+ - - "~>"
165
67
  - !ruby/object:Gem::Version
166
- version: '0'
68
+ version: '0.6'
167
69
  - !ruby/object:Gem::Dependency
168
70
  name: rack-test
169
71
  requirement: !ruby/object:Gem::Requirement
170
72
  requirements:
171
- - - ">="
73
+ - - "~>"
172
74
  - !ruby/object:Gem::Version
173
- version: '0'
75
+ version: '1.0'
174
76
  type: :development
175
77
  prerelease: false
176
78
  version_requirements: !ruby/object:Gem::Requirement
177
79
  requirements:
178
- - - ">="
80
+ - - "~>"
179
81
  - !ruby/object:Gem::Version
180
- version: '0'
82
+ version: '1.0'
181
83
  - !ruby/object:Gem::Dependency
182
84
  name: rake
183
85
  requirement: !ruby/object:Gem::Requirement
184
86
  requirements:
185
- - - ">="
87
+ - - "~>"
186
88
  - !ruby/object:Gem::Version
187
- version: '0'
89
+ version: '12.3'
188
90
  type: :development
189
91
  prerelease: false
190
92
  version_requirements: !ruby/object:Gem::Requirement
191
93
  requirements:
192
- - - ">="
94
+ - - "~>"
193
95
  - !ruby/object:Gem::Version
194
- version: '0'
96
+ version: '12.3'
195
97
  - !ruby/object:Gem::Dependency
196
- name: redis-activesupport
98
+ name: rubocop
197
99
  requirement: !ruby/object:Gem::Requirement
198
100
  requirements:
199
- - - ">="
101
+ - - '='
200
102
  - !ruby/object:Gem::Version
201
- version: '0'
103
+ version: 0.57.2
202
104
  type: :development
203
105
  prerelease: false
204
106
  version_requirements: !ruby/object:Gem::Requirement
205
107
  requirements:
206
- - - ">="
108
+ - - '='
207
109
  - !ruby/object:Gem::Version
208
- version: '0'
110
+ version: 0.57.2
209
111
  - !ruby/object:Gem::Dependency
210
- name: rubocop
112
+ name: timecop
211
113
  requirement: !ruby/object:Gem::Requirement
212
114
  requirements:
213
- - - '='
115
+ - - "~>"
214
116
  - !ruby/object:Gem::Version
215
- version: 0.57.2
117
+ version: 0.9.1
216
118
  type: :development
217
119
  prerelease: false
218
120
  version_requirements: !ruby/object:Gem::Requirement
219
121
  requirements:
220
- - - '='
122
+ - - "~>"
221
123
  - !ruby/object:Gem::Version
222
- version: 0.57.2
124
+ version: 0.9.1
223
125
  - !ruby/object:Gem::Dependency
224
- name: timecop
126
+ name: byebug
225
127
  requirement: !ruby/object:Gem::Requirement
226
128
  requirements:
227
- - - ">="
129
+ - - "~>"
228
130
  - !ruby/object:Gem::Version
229
- version: '0'
131
+ version: '10.0'
230
132
  type: :development
231
133
  prerelease: false
232
134
  version_requirements: !ruby/object:Gem::Requirement
233
135
  requirements:
234
- - - ">="
136
+ - - "~>"
235
137
  - !ruby/object:Gem::Version
236
- version: '0'
138
+ version: '10.0'
237
139
  - !ruby/object:Gem::Dependency
238
- name: guard
140
+ name: actionpack
239
141
  requirement: !ruby/object:Gem::Requirement
240
142
  requirements:
241
143
  - - ">="
242
144
  - !ruby/object:Gem::Version
243
- version: '0'
145
+ version: 3.0.0
244
146
  type: :development
245
147
  prerelease: false
246
148
  version_requirements: !ruby/object:Gem::Requirement
247
149
  requirements:
248
150
  - - ">="
249
151
  - !ruby/object:Gem::Version
250
- version: '0'
152
+ version: 3.0.0
251
153
  - !ruby/object:Gem::Dependency
252
- name: byebug
154
+ name: activesupport
253
155
  requirement: !ruby/object:Gem::Requirement
254
156
  requirements:
255
157
  - - ">="
256
158
  - !ruby/object:Gem::Version
257
- version: '0'
159
+ version: 3.0.0
258
160
  type: :development
259
161
  prerelease: false
260
162
  version_requirements: !ruby/object:Gem::Requirement
261
163
  requirements:
262
164
  - - ">="
263
165
  - !ruby/object:Gem::Version
264
- version: '0'
166
+ version: 3.0.0
265
167
  description: A rack middleware for throttling and blocking abusive requests
266
168
  email: aaron@ktheory.com
267
169
  executables: []
@@ -302,16 +204,21 @@ files:
302
204
  - spec/acceptance/safelisting_ip_spec.rb
303
205
  - spec/acceptance/safelisting_spec.rb
304
206
  - spec/acceptance/safelisting_subnet_spec.rb
305
- - spec/acceptance/stores/mem_cache_store_spec.rb
306
- - spec/acceptance/stores/redis_cache_store_pooled_spec.rb
307
- - spec/acceptance/stores/redis_cache_store_spec.rb
207
+ - spec/acceptance/stores/active_support_dalli_store_spec.rb
208
+ - spec/acceptance/stores/active_support_mem_cache_store_spec.rb
209
+ - spec/acceptance/stores/active_support_memory_store_spec.rb
210
+ - spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb
211
+ - spec/acceptance/stores/active_support_redis_cache_store_spec.rb
212
+ - spec/acceptance/stores/active_support_redis_store_spec.rb
213
+ - spec/acceptance/stores/connection_pool_dalli_client_spec.rb
214
+ - spec/acceptance/stores/dalli_client_spec.rb
215
+ - spec/acceptance/stores/redis_store_spec.rb
308
216
  - spec/acceptance/throttling_spec.rb
309
217
  - spec/acceptance/track_spec.rb
310
218
  - spec/acceptance/track_throttle_spec.rb
311
219
  - spec/allow2ban_spec.rb
312
220
  - spec/fail2ban_spec.rb
313
221
  - spec/integration/offline_spec.rb
314
- - spec/integration/rack_attack_cache_spec.rb
315
222
  - spec/rack_attack_dalli_proxy_spec.rb
316
223
  - spec/rack_attack_path_normalizer_spec.rb
317
224
  - spec/rack_attack_request_spec.rb
@@ -323,7 +230,10 @@ files:
323
230
  homepage: https://github.com/kickstarter/rack-attack
324
231
  licenses:
325
232
  - MIT
326
- metadata: {}
233
+ metadata:
234
+ bug_tracker_uri: https://github.com/kickstarter/rack-attack/issues
235
+ changelog_uri: https://github.com/kickstarter/rack-attack/blob/master/CHANGELOG.md
236
+ source_code_uri: https://github.com/kickstarter/rack-attack
327
237
  post_install_message:
328
238
  rdoc_options:
329
239
  - "--charset=UTF-8"
@@ -347,7 +257,6 @@ specification_version: 4
347
257
  summary: Block & throttle abusive requests
348
258
  test_files:
349
259
  - spec/integration/offline_spec.rb
350
- - spec/integration/rack_attack_cache_spec.rb
351
260
  - spec/rack_attack_path_normalizer_spec.rb
352
261
  - spec/acceptance/safelisting_subnet_spec.rb
353
262
  - spec/acceptance/track_throttle_spec.rb
@@ -366,9 +275,15 @@ test_files:
366
275
  - spec/acceptance/safelisting_spec.rb
367
276
  - spec/acceptance/cache_store_config_for_throttle_spec.rb
368
277
  - spec/acceptance/fail2ban_spec.rb
369
- - spec/acceptance/stores/mem_cache_store_spec.rb
370
- - spec/acceptance/stores/redis_cache_store_spec.rb
371
- - spec/acceptance/stores/redis_cache_store_pooled_spec.rb
278
+ - spec/acceptance/stores/active_support_redis_cache_store_spec.rb
279
+ - spec/acceptance/stores/active_support_memory_store_spec.rb
280
+ - spec/acceptance/stores/active_support_redis_store_spec.rb
281
+ - spec/acceptance/stores/active_support_mem_cache_store_spec.rb
282
+ - spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb
283
+ - spec/acceptance/stores/connection_pool_dalli_client_spec.rb
284
+ - spec/acceptance/stores/active_support_dalli_store_spec.rb
285
+ - spec/acceptance/stores/redis_store_spec.rb
286
+ - spec/acceptance/stores/dalli_client_spec.rb
372
287
  - spec/acceptance/customizing_blocked_response_spec.rb
373
288
  - spec/spec_helper.rb
374
289
  - spec/allow2ban_spec.rb
@@ -1,124 +0,0 @@
1
- require_relative '../spec_helper'
2
-
3
- describe Rack::Attack::Cache do
4
- # A convenience method for deleting a key from cache.
5
- # Slightly different than @cache.delete, which adds a prefix.
6
- def delete(key)
7
- if @cache.store.respond_to?(:delete)
8
- @cache.store.delete(key)
9
- else
10
- @cache.store.del(key)
11
- end
12
- end
13
-
14
- def sleep_until_expired
15
- sleep(@expires_in * 1.1) # Add 10% to reduce errors
16
- end
17
-
18
- require 'active_support/cache/dalli_store'
19
- require 'active_support/cache/mem_cache_store'
20
- require 'active_support/cache/redis_store'
21
- require 'active_support/cache/redis_cache_store' if ActiveSupport.version.to_s.to_f >= 5.2
22
- require 'connection_pool'
23
-
24
- cache_stores = [
25
- ActiveSupport::Cache::MemoryStore.new,
26
- ActiveSupport::Cache::DalliStore.new("127.0.0.1"),
27
- ActiveSupport::Cache::RedisStore.new("127.0.0.1"),
28
- ActiveSupport::Cache::MemCacheStore.new("127.0.0.1"),
29
- Dalli::Client.new,
30
- ConnectionPool.new { Dalli::Client.new },
31
- Redis::Store.new
32
- ]
33
-
34
- cache_stores << ActiveSupport::Cache::RedisCacheStore.new if defined?(ActiveSupport::Cache::RedisCacheStore)
35
-
36
- cache_stores.each do |store|
37
- store = Rack::Attack::StoreProxy.build(store)
38
-
39
- describe "with #{store.class}" do
40
- before {
41
- @cache = Rack::Attack::Cache.new
42
- @key = "rack::attack:cache-test-key"
43
- @expires_in = 1
44
- @cache.store = store
45
- delete(@key)
46
- }
47
-
48
- after { delete(@key) }
49
-
50
- describe "do_count once" do
51
- it "should be 1" do
52
- @cache.send(:do_count, @key, @expires_in).must_equal 1
53
- end
54
- end
55
-
56
- describe "do_count twice" do
57
- it "must be 2" do
58
- @cache.send(:do_count, @key, @expires_in)
59
- @cache.send(:do_count, @key, @expires_in).must_equal 2
60
- end
61
- end
62
-
63
- describe "do_count after expires_in" do
64
- it "must be 1" do
65
- @cache.send(:do_count, @key, @expires_in)
66
- sleep_until_expired
67
- @cache.send(:do_count, @key, @expires_in).must_equal 1
68
- end
69
- end
70
-
71
- describe "write" do
72
- it "should write a value to the store with prefix" do
73
- @cache.write("cache-test-key", "foobar", 1)
74
- store.read(@key).must_equal "foobar"
75
- end
76
- end
77
-
78
- describe "write after expiry" do
79
- it "must not have a value" do
80
- @cache.write("cache-test-key", "foobar", @expires_in)
81
- sleep_until_expired
82
- store.read(@key).must_be :nil?
83
- end
84
- end
85
-
86
- describe "read" do
87
- it "must read the value with a prefix" do
88
- store.write(@key, "foobar", :expires_in => @expires_in)
89
- @cache.read("cache-test-key").must_equal "foobar"
90
- end
91
- end
92
-
93
- describe "delete" do
94
- it "must delete the value" do
95
- store.write(@key, "foobar", :expires_in => @expires_in)
96
- @cache.read('cache-test-key').must_equal "foobar"
97
- store.delete(@key)
98
- assert_nil @cache.read('cache-test-key')
99
- end
100
- end
101
-
102
- describe "cache#delete" do
103
- it "must delete the value" do
104
- @cache.write("cache-test-key", "foobar", 1)
105
- store.read(@key).must_equal "foobar"
106
- @cache.delete('cache-test-key')
107
- store.read(@key).must_be :nil?
108
- end
109
- end
110
-
111
- describe "reset_count" do
112
- it "must delete the value" do
113
- period = 1.minute
114
- unprefixed_key = 'cache-test-key'
115
- @cache.count(unprefixed_key, period)
116
- period_key, _ = @cache.send(:key_and_expiry, 'cache-test-key', period)
117
- store.read(period_key).to_i.must_equal 1
118
- @cache.reset_count(unprefixed_key, period)
119
- assert_nil store.read(period_key)
120
- end
121
- end
122
- end
123
- end
124
- end