rack-attack 5.4.2 → 6.0.0

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