rack-attack 5.3.1 → 5.3.2

Sign up to get free protection for your applications and to get access to all the features.
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