rack-attack 5.4.2 → 6.0.0

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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +65 -23
  3. data/Rakefile +3 -1
  4. data/lib/rack/attack.rb +46 -70
  5. data/lib/rack/attack/allow2ban.rb +2 -0
  6. data/lib/rack/attack/blocklist.rb +3 -1
  7. data/lib/rack/attack/cache.rb +5 -3
  8. data/lib/rack/attack/check.rb +3 -1
  9. data/lib/rack/attack/fail2ban.rb +2 -0
  10. data/lib/rack/attack/path_normalizer.rb +2 -0
  11. data/lib/rack/attack/request.rb +2 -0
  12. data/lib/rack/attack/safelist.rb +3 -1
  13. data/lib/rack/attack/store_proxy.rb +12 -14
  14. data/lib/rack/attack/store_proxy/active_support_redis_store_proxy.rb +37 -0
  15. data/lib/rack/attack/store_proxy/dalli_proxy.rb +27 -13
  16. data/lib/rack/attack/store_proxy/redis_cache_store_proxy.rb +2 -4
  17. data/lib/rack/attack/store_proxy/redis_proxy.rb +16 -10
  18. data/lib/rack/attack/store_proxy/redis_store_proxy.rb +5 -5
  19. data/lib/rack/attack/throttle.rb +8 -6
  20. data/lib/rack/attack/track.rb +5 -3
  21. data/lib/rack/attack/version.rb +3 -1
  22. data/spec/acceptance/allow2ban_spec.rb +2 -0
  23. data/spec/acceptance/blocking_ip_spec.rb +4 -2
  24. data/spec/acceptance/blocking_spec.rb +45 -3
  25. data/spec/acceptance/blocking_subnet_spec.rb +4 -2
  26. data/spec/acceptance/cache_store_config_for_allow2ban_spec.rb +8 -12
  27. data/spec/acceptance/cache_store_config_for_fail2ban_spec.rb +8 -12
  28. data/spec/acceptance/cache_store_config_for_throttle_spec.rb +2 -0
  29. data/spec/acceptance/cache_store_config_with_rails_spec.rb +2 -0
  30. data/spec/acceptance/customizing_blocked_response_spec.rb +2 -0
  31. data/spec/acceptance/customizing_throttled_response_spec.rb +2 -0
  32. data/spec/acceptance/extending_request_object_spec.rb +2 -0
  33. data/spec/acceptance/fail2ban_spec.rb +2 -0
  34. data/spec/acceptance/safelisting_ip_spec.rb +4 -2
  35. data/spec/acceptance/safelisting_spec.rb +57 -3
  36. data/spec/acceptance/safelisting_subnet_spec.rb +4 -2
  37. data/spec/acceptance/stores/active_support_dalli_store_spec.rb +2 -0
  38. data/spec/acceptance/stores/active_support_mem_cache_store_spec.rb +2 -0
  39. data/spec/acceptance/stores/active_support_memory_store_spec.rb +2 -0
  40. data/spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb +2 -0
  41. data/spec/acceptance/stores/active_support_redis_cache_store_spec.rb +2 -0
  42. data/spec/acceptance/stores/active_support_redis_store_spec.rb +3 -1
  43. data/spec/acceptance/stores/connection_pool_dalli_client_spec.rb +2 -0
  44. data/spec/acceptance/stores/dalli_client_spec.rb +2 -0
  45. data/spec/acceptance/stores/redis_store_spec.rb +2 -0
  46. data/spec/acceptance/throttling_spec.rb +7 -5
  47. data/spec/acceptance/track_spec.rb +5 -3
  48. data/spec/acceptance/track_throttle_spec.rb +5 -3
  49. data/spec/allow2ban_spec.rb +3 -1
  50. data/spec/fail2ban_spec.rb +3 -1
  51. data/spec/integration/offline_spec.rb +3 -1
  52. data/spec/rack_attack_dalli_proxy_spec.rb +2 -0
  53. data/spec/rack_attack_instrumentation_spec.rb +42 -0
  54. data/spec/rack_attack_path_normalizer_spec.rb +2 -0
  55. data/spec/rack_attack_request_spec.rb +2 -0
  56. data/spec/rack_attack_spec.rb +2 -21
  57. data/spec/rack_attack_throttle_spec.rb +10 -8
  58. data/spec/rack_attack_track_spec.rb +4 -2
  59. data/spec/spec_helper.rb +5 -4
  60. data/spec/support/cache_store_helper.rb +2 -0
  61. metadata +21 -14
  62. data/lib/rack/attack/store_proxy/mem_cache_proxy.rb +0 -50
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'spec_helper'
2
4
 
3
5
  describe 'Rack::Attack.throttle' do
4
6
  before do
5
7
  @period = 60 # Use a long period; failures due to cache key rotation less likely
6
8
  Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
7
- Rack::Attack.throttle('ip/sec', :limit => 1, :period => @period) { |req| req.ip }
9
+ Rack::Attack.throttle('ip/sec', limit: 1, period: @period) { |req| req.ip }
8
10
  end
9
11
 
10
12
  it('should have a throttle') { Rack::Attack.throttles.key?('ip/sec') }
@@ -20,7 +22,7 @@ describe 'Rack::Attack.throttle' do
20
22
  end
21
23
 
22
24
  it 'should populate throttle data' do
23
- data = { :count => 1, :limit => 1, :period => @period, epoch_time: Rack::Attack.cache.last_epoch_time.to_i }
25
+ data = { count: 1, limit: 1, period: @period, epoch_time: Rack::Attack.cache.last_epoch_time.to_i }
24
26
  last_request.env['rack.attack.throttle_data']['ip/sec'].must_equal data
25
27
  end
26
28
  end
@@ -37,7 +39,7 @@ describe 'Rack::Attack.throttle' do
37
39
  it 'should tag the env' do
38
40
  last_request.env['rack.attack.matched'].must_equal 'ip/sec'
39
41
  last_request.env['rack.attack.match_type'].must_equal :throttle
40
- last_request.env['rack.attack.match_data'].must_equal(:count => 2, :limit => 1, :period => @period, epoch_time: Rack::Attack.cache.last_epoch_time.to_i)
42
+ last_request.env['rack.attack.match_data'].must_equal(count: 2, limit: 1, period: @period, epoch_time: Rack::Attack.cache.last_epoch_time.to_i)
41
43
  last_request.env['rack.attack.match_discriminator'].must_equal('1.2.3.4')
42
44
  end
43
45
 
@@ -51,7 +53,7 @@ describe 'Rack::Attack.throttle with limit as proc' do
51
53
  before do
52
54
  @period = 60 # Use a long period; failures due to cache key rotation less likely
53
55
  Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
54
- Rack::Attack.throttle('ip/sec', :limit => lambda { |_req| 1 }, :period => @period) { |req| req.ip }
56
+ Rack::Attack.throttle('ip/sec', limit: lambda { |_req| 1 }, period: @period) { |req| req.ip }
55
57
  end
56
58
 
57
59
  it_allows_ok_requests
@@ -65,7 +67,7 @@ describe 'Rack::Attack.throttle with limit as proc' do
65
67
  end
66
68
 
67
69
  it 'should populate throttle data' do
68
- data = { :count => 1, :limit => 1, :period => @period, epoch_time: Rack::Attack.cache.last_epoch_time.to_i }
70
+ data = { count: 1, limit: 1, period: @period, epoch_time: Rack::Attack.cache.last_epoch_time.to_i }
69
71
  last_request.env['rack.attack.throttle_data']['ip/sec'].must_equal data
70
72
  end
71
73
  end
@@ -75,7 +77,7 @@ describe 'Rack::Attack.throttle with period as proc' do
75
77
  before do
76
78
  @period = 60 # Use a long period; failures due to cache key rotation less likely
77
79
  Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
78
- Rack::Attack.throttle('ip/sec', :limit => lambda { |_req| 1 }, :period => lambda { |_req| @period }) { |req| req.ip }
80
+ Rack::Attack.throttle('ip/sec', limit: lambda { |_req| 1 }, period: lambda { |_req| @period }) { |req| req.ip }
79
81
  end
80
82
 
81
83
  it_allows_ok_requests
@@ -89,7 +91,7 @@ describe 'Rack::Attack.throttle with period as proc' do
89
91
  end
90
92
 
91
93
  it 'should populate throttle data' do
92
- data = { :count => 1, :limit => 1, :period => @period, epoch_time: Rack::Attack.cache.last_epoch_time.to_i }
94
+ data = { count: 1, limit: 1, period: @period, epoch_time: Rack::Attack.cache.last_epoch_time.to_i }
93
95
  last_request.env['rack.attack.throttle_data']['ip/sec'].must_equal data
94
96
  end
95
97
  end
@@ -99,7 +101,7 @@ describe 'Rack::Attack.throttle with block retuning nil' do
99
101
  before do
100
102
  @period = 60
101
103
  Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
102
- Rack::Attack.throttle('ip/sec', :limit => 1, :period => @period) { |_| nil }
104
+ Rack::Attack.throttle('ip/sec', limit: 1, period: @period) { |_| nil }
103
105
  end
104
106
 
105
107
  it_allows_ok_requests
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'spec_helper'
2
4
 
3
5
  describe 'Rack::Attack.track' do
@@ -33,7 +35,7 @@ describe 'Rack::Attack.track' do
33
35
  # A second track
34
36
  Rack::Attack.track("homepage") { |req| req.path == "/" }
35
37
 
36
- ActiveSupport::Notifications.subscribe("rack.attack") do |*_args|
38
+ ActiveSupport::Notifications.subscribe("track.rack_attack") do |*_args|
37
39
  Counter.incr
38
40
  end
39
41
 
@@ -54,7 +56,7 @@ describe 'Rack::Attack.track' do
54
56
 
55
57
  describe "with limit and period options" do
56
58
  it "should assign the track filter to a Throttle instance" do
57
- track = Rack::Attack.track("homepage", :limit => 10, :period => 10) { |req| req.path == "/" }
59
+ track = Rack::Attack.track("homepage", limit: 10, period: 10) { |req| req.path == "/" }
58
60
  track.filter.class.must_equal Rack::Attack::Throttle
59
61
  end
60
62
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/setup"
2
4
 
3
5
  require "minitest/autorun"
@@ -13,10 +15,9 @@ if RUBY_ENGINE == "ruby"
13
15
  end
14
16
 
15
17
  def safe_require(name)
16
- begin
17
- require name
18
- rescue LoadError
19
- end
18
+ require name
19
+ rescue LoadError
20
+ nil
20
21
  end
21
22
 
22
23
  safe_require "connection_pool"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Minitest::Spec
2
4
  def self.it_works_for_cache_backed_features(options)
3
5
  fetch_from_store = options.fetch(:fetch_from_store)
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.2
4
+ version: 6.0.0
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-10-30 00:00:00.000000000 Z
11
+ date: 2019-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -48,16 +48,22 @@ dependencies:
48
48
  name: bundler
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - "~>"
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '1.17'
54
+ - - "<"
52
55
  - !ruby/object:Gem::Version
53
- version: '1.16'
56
+ version: '3.0'
54
57
  type: :development
55
58
  prerelease: false
56
59
  version_requirements: !ruby/object:Gem::Requirement
57
60
  requirements:
58
- - - "~>"
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '1.17'
64
+ - - "<"
59
65
  - !ruby/object:Gem::Version
60
- version: '1.16'
66
+ version: '3.0'
61
67
  - !ruby/object:Gem::Dependency
62
68
  name: minitest
63
69
  requirement: !ruby/object:Gem::Requirement
@@ -120,14 +126,14 @@ dependencies:
120
126
  requirements:
121
127
  - - '='
122
128
  - !ruby/object:Gem::Version
123
- version: 0.58.2
129
+ version: 0.67.2
124
130
  type: :development
125
131
  prerelease: false
126
132
  version_requirements: !ruby/object:Gem::Requirement
127
133
  requirements:
128
134
  - - '='
129
135
  - !ruby/object:Gem::Version
130
- version: 0.58.2
136
+ version: 0.67.2
131
137
  - !ruby/object:Gem::Dependency
132
138
  name: timecop
133
139
  requirement: !ruby/object:Gem::Requirement
@@ -148,14 +154,14 @@ dependencies:
148
154
  requirements:
149
155
  - - "~>"
150
156
  - !ruby/object:Gem::Version
151
- version: '10.0'
157
+ version: '11.0'
152
158
  type: :development
153
159
  prerelease: false
154
160
  version_requirements: !ruby/object:Gem::Requirement
155
161
  requirements:
156
162
  - - "~>"
157
163
  - !ruby/object:Gem::Version
158
- version: '10.0'
164
+ version: '11.0'
159
165
  - !ruby/object:Gem::Dependency
160
166
  name: actionpack
161
167
  requirement: !ruby/object:Gem::Requirement
@@ -203,8 +209,8 @@ files:
203
209
  - lib/rack/attack/request.rb
204
210
  - lib/rack/attack/safelist.rb
205
211
  - lib/rack/attack/store_proxy.rb
212
+ - lib/rack/attack/store_proxy/active_support_redis_store_proxy.rb
206
213
  - lib/rack/attack/store_proxy/dalli_proxy.rb
207
- - lib/rack/attack/store_proxy/mem_cache_proxy.rb
208
214
  - lib/rack/attack/store_proxy/mem_cache_store_proxy.rb
209
215
  - lib/rack/attack/store_proxy/redis_cache_store_proxy.rb
210
216
  - lib/rack/attack/store_proxy/redis_proxy.rb
@@ -245,6 +251,7 @@ files:
245
251
  - spec/fail2ban_spec.rb
246
252
  - spec/integration/offline_spec.rb
247
253
  - spec/rack_attack_dalli_proxy_spec.rb
254
+ - spec/rack_attack_instrumentation_spec.rb
248
255
  - spec/rack_attack_path_normalizer_spec.rb
249
256
  - spec/rack_attack_request_spec.rb
250
257
  - spec/rack_attack_spec.rb
@@ -268,15 +275,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
268
275
  requirements:
269
276
  - - ">="
270
277
  - !ruby/object:Gem::Version
271
- version: '2.2'
278
+ version: '2.3'
272
279
  required_rubygems_version: !ruby/object:Gem::Requirement
273
280
  requirements:
274
281
  - - ">="
275
282
  - !ruby/object:Gem::Version
276
283
  version: '0'
277
284
  requirements: []
278
- rubyforge_project:
279
- rubygems_version: 2.7.6
285
+ rubygems_version: 3.0.3
280
286
  signing_key:
281
287
  specification_version: 4
282
288
  summary: Block & throttle abusive requests
@@ -314,6 +320,7 @@ test_files:
314
320
  - spec/acceptance/customizing_blocked_response_spec.rb
315
321
  - spec/spec_helper.rb
316
322
  - spec/allow2ban_spec.rb
323
+ - spec/rack_attack_instrumentation_spec.rb
317
324
  - spec/rack_attack_dalli_proxy_spec.rb
318
325
  - spec/rack_attack_spec.rb
319
326
  - spec/rack_attack_throttle_spec.rb
@@ -1,50 +0,0 @@
1
- module Rack
2
- class Attack
3
- module StoreProxy
4
- class MemCacheProxy < SimpleDelegator
5
- def self.handle?(store)
6
- defined?(::MemCache) && store.is_a?(::MemCache)
7
- end
8
-
9
- def initialize(store)
10
- super(store)
11
- stub_with_if_missing
12
- end
13
-
14
- def read(key)
15
- # Second argument: reading raw value
16
- get(key, true)
17
- rescue MemCache::MemCacheError
18
- end
19
-
20
- def write(key, value, options = {})
21
- # Third argument: writing raw value
22
- set(key, value, options.fetch(:expires_in, 0), true)
23
- rescue MemCache::MemCacheError
24
- end
25
-
26
- def increment(key, amount, _options = {})
27
- incr(key, amount)
28
- rescue MemCache::MemCacheError
29
- end
30
-
31
- def delete(key, _options = {})
32
- with do |client|
33
- client.delete(key)
34
- end
35
- rescue MemCache::MemCacheError
36
- end
37
-
38
- private
39
-
40
- def stub_with_if_missing
41
- unless __getobj__.respond_to?(:with)
42
- class << self
43
- def with; yield __getobj__; end
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end
50
- end