rack-attack 5.4.0 → 5.4.1

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: 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