rack-attack 5.4.0 → 5.4.1

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: 123608043cbaa1604ab2d7b06c056010decd274dd4a5b1fe8f2175cec766fa4d
4
- data.tar.gz: 2bd3ca91293545b76221608f144c1a43a458fbd9e6f2e8ea2647bf561d8ea9a9
3
+ metadata.gz: 21f1ecf9854b74958cacdb31211735c29b9a2f98f1ee848e0f60a3f409651cc6
4
+ data.tar.gz: 934f2ac2af420277f6d31052b56af24d2cbe93412a272aa753c25ce26228d7b1
5
5
  SHA512:
6
- metadata.gz: '06388ad68edc65019740c9ee77347f817b0769e782d0f8564ac5ac6b9c7fa819fe2157a10d89b570c78c14ef5a86fe080fac30aba8ebdfed281f2073785f5685'
7
- data.tar.gz: a15cc2cef9eebda52d662fe3eeee3f187d5b575c089a1fa2cf5e0179012499f6440889349a47108c4017f8b73dd18985655dc933baf8c031e08d73ea23d1dbba
6
+ metadata.gz: 32f63613544602a11c8af12a5ac764adf44ba22beda1dc8840bfc5431a32edd8ea1075eab6933f423405e71959ed0c5b5f8668d72262c5fb4787f89105259f5a
7
+ data.tar.gz: aad3b2d1ace4369f2605d863df03c86d0e008c934c5f9c6741b71d2a3e363bcf37c93685e436ff48c917a512d39b8fd059fb3db09f38250c609f5fa22244cda4
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -17,6 +17,7 @@ class Rack::Attack
17
17
  autoload :StoreProxy, 'rack/attack/store_proxy'
18
18
  autoload :DalliProxy, 'rack/attack/store_proxy/dalli_proxy'
19
19
  autoload :MemCacheProxy, 'rack/attack/store_proxy/mem_cache_proxy'
20
+ autoload :MemCacheStoreProxy, 'rack/attack/store_proxy/mem_cache_store_proxy'
20
21
  autoload :RedisProxy, 'rack/attack/store_proxy/redis_proxy'
21
22
  autoload :RedisStoreProxy, 'rack/attack/store_proxy/redis_store_proxy'
22
23
  autoload :RedisCacheStoreProxy, 'rack/attack/store_proxy/redis_cache_store_proxy'
@@ -1,10 +1,7 @@
1
1
  module Rack
2
2
  class Attack
3
3
  module StoreProxy
4
- PROXIES = [DalliProxy, MemCacheProxy, RedisStoreProxy, RedisProxy, RedisCacheStoreProxy].freeze
5
-
6
- ACTIVE_SUPPORT_WRAPPER_CLASSES = Set.new(['ActiveSupport::Cache::MemCacheStore', 'ActiveSupport::Cache::RedisStore', 'ActiveSupport::Cache::RedisCacheStore']).freeze
7
- ACTIVE_SUPPORT_CLIENTS = Set.new(['Redis::Store', 'Dalli::Client', 'MemCache']).freeze
4
+ PROXIES = [DalliProxy, MemCacheStoreProxy, MemCacheProxy, RedisStoreProxy, RedisProxy, RedisCacheStoreProxy].freeze
8
5
 
9
6
  def self.build(store)
10
7
  client = unwrap_active_support_stores(store)
@@ -15,15 +12,8 @@ module Rack
15
12
  def self.unwrap_active_support_stores(store)
16
13
  # ActiveSupport::Cache::RedisStore doesn't expose any way to set an expiry,
17
14
  # so use the raw Redis::Store instead.
18
- # We also want to use the underlying Dalli client instead of ::ActiveSupport::Cache::MemCacheStore,
19
- # and the MemCache client if using Rails 3.x
20
-
21
- if store.instance_variable_defined?(:@data)
22
- client = store.instance_variable_get(:@data)
23
- end
24
-
25
- if ACTIVE_SUPPORT_WRAPPER_CLASSES.include?(store.class.to_s) && ACTIVE_SUPPORT_CLIENTS.include?(client.class.to_s)
26
- client
15
+ if store.class.name == 'ActiveSupport::Cache::RedisStore'
16
+ store.instance_variable_get(:@data)
27
17
  else
28
18
  store
29
19
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'delegate'
4
+
5
+ module Rack
6
+ class Attack
7
+ module StoreProxy
8
+ class MemCacheStoreProxy < SimpleDelegator
9
+ def self.handle?(store)
10
+ defined?(::Dalli) && defined?(::ActiveSupport::Cache::MemCacheStore) && store.is_a?(::ActiveSupport::Cache::MemCacheStore)
11
+ end
12
+
13
+ def write(name, value, options = {})
14
+ super(name, value, options.merge!(raw: true))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class Attack
3
- VERSION = '5.4.0'
3
+ VERSION = '5.4.1'
4
4
  end
5
5
  end
@@ -14,28 +14,6 @@ if defined?(::Dalli)
14
14
  Rack::Attack.cache.store.clear
15
15
  end
16
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
17
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.fetch(key) })
40
18
  end
41
19
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../spec_helper"
4
+
5
+ if defined?(::ConnectionPool) && defined?(::Dalli)
6
+ require_relative "../../support/cache_store_helper"
7
+ require "timecop"
8
+
9
+ describe "ActiveSupport::Cache::MemCacheStore (pooled) as a cache backend" do
10
+ before do
11
+ Rack::Attack.cache.store = ActiveSupport::Cache::MemCacheStore.new(pool_size: 2)
12
+ end
13
+
14
+ after do
15
+ Rack::Attack.cache.store.clear
16
+ end
17
+
18
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) {
19
+ Rack::Attack.cache.store.read(key)
20
+ })
21
+ end
22
+ end
@@ -10,31 +10,9 @@ if defined?(::Dalli)
10
10
  end
11
11
 
12
12
  after do
13
- Rack::Attack.cache.store.flush_all
13
+ Rack::Attack.cache.store.clear
14
14
  end
15
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
16
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.read(key) })
39
17
  end
40
18
  end
@@ -12,27 +12,5 @@ describe "ActiveSupport::Cache::MemoryStore as a cache backend" do
12
12
  Rack::Attack.cache.store.clear
13
13
  end
14
14
 
15
- it_works_for_cache_backed_features
16
-
17
- it "doesn't leak keys" do
18
- Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
19
- request.ip
20
- end
21
-
22
- key = nil
23
-
24
- # Freeze time during these statement to be sure that the key used by rack attack is the same
25
- # we pre-calculate in local variable `key`
26
- Timecop.freeze do
27
- key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
28
-
29
- get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
30
- end
31
-
32
- assert Rack::Attack.cache.store.fetch(key)
33
-
34
- sleep 2.1
35
-
36
- assert_nil Rack::Attack.cache.store.fetch(key)
37
- end
15
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.fetch(key) })
38
16
  end
@@ -13,28 +13,6 @@ if defined?(::ConnectionPool) && defined?(::Redis) && defined?(::ActiveSupport::
13
13
  Rack::Attack.cache.store.clear
14
14
  end
15
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.fetch(key)
34
-
35
- sleep 2.1
36
-
37
- assert_nil Rack::Attack.cache.store.fetch(key)
38
- end
16
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.fetch(key) })
39
17
  end
40
18
  end
@@ -13,29 +13,6 @@ if defined?(::Redis) && defined?(::ActiveSupport::Cache::RedisCacheStore)
13
13
  Rack::Attack.cache.store.clear
14
14
  end
15
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
- # puts key
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
16
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.fetch(key) })
40
17
  end
41
18
  end
@@ -13,28 +13,6 @@ if defined?(::ActiveSupport::Cache::RedisStore)
13
13
  Rack::Attack.cache.store.flushdb
14
14
  end
15
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
16
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.read(key) })
39
17
  end
40
18
  end
@@ -15,28 +15,8 @@ if defined?(::Dalli) && defined?(::ConnectionPool)
15
15
  Rack::Attack.cache.store.with { |client| client.flush_all }
16
16
  end
17
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
18
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) {
19
+ Rack::Attack.cache.store.with { |client| client.fetch(key) }
20
+ })
41
21
  end
42
22
  end
@@ -14,28 +14,6 @@ if defined?(::Dalli)
14
14
  Rack::Attack.cache.store.flush_all
15
15
  end
16
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
17
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.fetch(key) })
40
18
  end
41
19
  end
@@ -15,28 +15,6 @@ if defined?(::Redis)
15
15
  Rack::Attack.cache.store.flushdb
16
16
  end
17
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.get(key)
36
-
37
- sleep 2.1
38
-
39
- assert_nil Rack::Attack.cache.store.get(key)
40
- end
18
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.get(key) })
41
19
  end
42
20
  end
@@ -13,28 +13,6 @@ if defined?(::Redis::Store)
13
13
  Rack::Attack.cache.store.flushdb
14
14
  end
15
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
16
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.read(key) })
39
17
  end
40
18
  end
@@ -1,5 +1,7 @@
1
1
  class Minitest::Spec
2
- def self.it_works_for_cache_backed_features
2
+ def self.it_works_for_cache_backed_features(options)
3
+ fetch_from_store = options.fetch(:fetch_from_store)
4
+
3
5
  it "works for throttle" do
4
6
  Rack::Attack.throttle("by ip", limit: 1, period: 60) do |request|
5
7
  request.ip
@@ -54,5 +56,27 @@ class Minitest::Spec
54
56
  get "/"
55
57
  assert_equal 403, last_response.status
56
58
  end
59
+
60
+ it "doesn't leak keys" do
61
+ Rack::Attack.throttle("by ip", limit: 1, period: 1) do |request|
62
+ request.ip
63
+ end
64
+
65
+ key = nil
66
+
67
+ # Freeze time during these statement to be sure that the key used by rack attack is the same
68
+ # we pre-calculate in local variable `key`
69
+ Timecop.freeze do
70
+ key = "rack::attack:#{Time.now.to_i}:by ip:1.2.3.4"
71
+
72
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
73
+ end
74
+
75
+ assert fetch_from_store.call(key)
76
+
77
+ sleep 2.1
78
+
79
+ assert_nil fetch_from_store.call(key)
80
+ end
57
81
  end
58
82
  end
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.4.0
4
+ version: 5.4.1
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-07-02 00:00:00.000000000 Z
11
+ date: 2018-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -120,14 +120,14 @@ dependencies:
120
120
  requirements:
121
121
  - - '='
122
122
  - !ruby/object:Gem::Version
123
- version: 0.57.2
123
+ version: 0.58.2
124
124
  type: :development
125
125
  prerelease: false
126
126
  version_requirements: !ruby/object:Gem::Requirement
127
127
  requirements:
128
128
  - - '='
129
129
  - !ruby/object:Gem::Version
130
- version: 0.57.2
130
+ version: 0.58.2
131
131
  - !ruby/object:Gem::Dependency
132
132
  name: timecop
133
133
  requirement: !ruby/object:Gem::Requirement
@@ -192,6 +192,7 @@ extra_rdoc_files: []
192
192
  files:
193
193
  - README.md
194
194
  - Rakefile
195
+ - bin/setup
195
196
  - lib/rack/attack.rb
196
197
  - lib/rack/attack/allow2ban.rb
197
198
  - lib/rack/attack/blocklist.rb
@@ -204,6 +205,7 @@ files:
204
205
  - lib/rack/attack/store_proxy.rb
205
206
  - lib/rack/attack/store_proxy/dalli_proxy.rb
206
207
  - lib/rack/attack/store_proxy/mem_cache_proxy.rb
208
+ - lib/rack/attack/store_proxy/mem_cache_store_proxy.rb
207
209
  - lib/rack/attack/store_proxy/redis_cache_store_proxy.rb
208
210
  - lib/rack/attack/store_proxy/redis_proxy.rb
209
211
  - lib/rack/attack/store_proxy/redis_store_proxy.rb
@@ -226,6 +228,7 @@ files:
226
228
  - spec/acceptance/safelisting_spec.rb
227
229
  - spec/acceptance/safelisting_subnet_spec.rb
228
230
  - spec/acceptance/stores/active_support_dalli_store_spec.rb
231
+ - spec/acceptance/stores/active_support_mem_cache_store_pooled_spec.rb
229
232
  - spec/acceptance/stores/active_support_mem_cache_store_spec.rb
230
233
  - spec/acceptance/stores/active_support_memory_store_spec.rb
231
234
  - spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb
@@ -297,6 +300,7 @@ test_files:
297
300
  - spec/acceptance/safelisting_spec.rb
298
301
  - spec/acceptance/cache_store_config_for_throttle_spec.rb
299
302
  - spec/acceptance/fail2ban_spec.rb
303
+ - spec/acceptance/stores/active_support_mem_cache_store_pooled_spec.rb
300
304
  - spec/acceptance/stores/active_support_redis_cache_store_spec.rb
301
305
  - spec/acceptance/stores/active_support_memory_store_spec.rb
302
306
  - spec/acceptance/stores/active_support_redis_store_spec.rb