rack-attack 5.4.1 → 6.2.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 +4 -4
- data/README.md +78 -27
- data/Rakefile +3 -1
- data/lib/rack/attack.rb +138 -149
- data/lib/rack/attack/allow2ban.rb +2 -0
- data/lib/rack/attack/blocklist.rb +3 -1
- data/lib/rack/attack/cache.rb +9 -4
- data/lib/rack/attack/check.rb +5 -2
- data/lib/rack/attack/fail2ban.rb +2 -0
- data/lib/rack/attack/path_normalizer.rb +22 -18
- data/lib/rack/attack/railtie.rb +13 -0
- data/lib/rack/attack/request.rb +2 -0
- data/lib/rack/attack/safelist.rb +3 -1
- data/lib/rack/attack/store_proxy.rb +12 -14
- data/lib/rack/attack/store_proxy/active_support_redis_store_proxy.rb +39 -0
- data/lib/rack/attack/store_proxy/dalli_proxy.rb +27 -13
- data/lib/rack/attack/store_proxy/mem_cache_store_proxy.rb +3 -1
- data/lib/rack/attack/store_proxy/redis_cache_store_proxy.rb +23 -9
- data/lib/rack/attack/store_proxy/redis_proxy.rb +16 -10
- data/lib/rack/attack/store_proxy/redis_store_proxy.rb +5 -5
- data/lib/rack/attack/throttle.rb +12 -8
- data/lib/rack/attack/track.rb +9 -6
- data/lib/rack/attack/version.rb +3 -1
- data/spec/acceptance/allow2ban_spec.rb +2 -0
- data/spec/acceptance/blocking_ip_spec.rb +4 -2
- data/spec/acceptance/blocking_spec.rb +45 -3
- data/spec/acceptance/blocking_subnet_spec.rb +4 -2
- data/spec/acceptance/cache_store_config_for_allow2ban_spec.rb +50 -39
- data/spec/acceptance/cache_store_config_for_fail2ban_spec.rb +38 -29
- data/spec/acceptance/cache_store_config_for_throttle_spec.rb +2 -0
- data/spec/acceptance/cache_store_config_with_rails_spec.rb +2 -0
- data/spec/acceptance/customizing_blocked_response_spec.rb +2 -0
- data/spec/acceptance/customizing_throttled_response_spec.rb +2 -0
- data/spec/acceptance/extending_request_object_spec.rb +2 -0
- data/spec/acceptance/fail2ban_spec.rb +2 -0
- data/spec/acceptance/rails_middleware_spec.rb +35 -0
- data/spec/acceptance/safelisting_ip_spec.rb +4 -2
- data/spec/acceptance/safelisting_spec.rb +57 -3
- data/spec/acceptance/safelisting_subnet_spec.rb +4 -2
- data/spec/acceptance/stores/active_support_dalli_store_spec.rb +2 -0
- data/spec/acceptance/stores/active_support_mem_cache_store_pooled_spec.rb +1 -3
- data/spec/acceptance/stores/active_support_mem_cache_store_spec.rb +2 -0
- data/spec/acceptance/stores/active_support_memory_store_spec.rb +2 -0
- data/spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb +9 -1
- data/spec/acceptance/stores/active_support_redis_cache_store_spec.rb +8 -1
- data/spec/acceptance/stores/active_support_redis_store_spec.rb +3 -1
- data/spec/acceptance/stores/connection_pool_dalli_client_spec.rb +5 -3
- data/spec/acceptance/stores/dalli_client_spec.rb +2 -0
- data/spec/acceptance/stores/redis_store_spec.rb +2 -0
- data/spec/acceptance/throttling_spec.rb +7 -5
- data/spec/acceptance/track_spec.rb +5 -3
- data/spec/acceptance/track_throttle_spec.rb +5 -3
- data/spec/allow2ban_spec.rb +20 -15
- data/spec/fail2ban_spec.rb +20 -17
- data/spec/integration/offline_spec.rb +3 -1
- data/spec/rack_attack_dalli_proxy_spec.rb +2 -0
- data/spec/rack_attack_instrumentation_spec.rb +42 -0
- data/spec/rack_attack_path_normalizer_spec.rb +4 -2
- data/spec/rack_attack_request_spec.rb +2 -0
- data/spec/rack_attack_spec.rb +38 -34
- data/spec/rack_attack_throttle_spec.rb +50 -19
- data/spec/rack_attack_track_spec.rb +12 -7
- data/spec/spec_helper.rb +12 -8
- data/spec/support/cache_store_helper.rb +2 -0
- metadata +44 -28
- data/lib/rack/attack/store_proxy/mem_cache_proxy.rb +0 -50
data/spec/fail2ban_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'spec_helper'
|
2
4
|
|
3
5
|
describe 'Rack::Attack.Fail2Ban' do
|
@@ -7,7 +9,7 @@ describe 'Rack::Attack.Fail2Ban' do
|
|
7
9
|
@findtime = 60
|
8
10
|
@bantime = 60
|
9
11
|
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
10
|
-
@f2b_options = { :
|
12
|
+
@f2b_options = { bantime: @bantime, findtime: @findtime, maxretry: 2 }
|
11
13
|
|
12
14
|
Rack::Attack.blocklist('pentest') do |req|
|
13
15
|
Rack::Attack::Fail2Ban.filter(req.ip, @f2b_options) { req.query_string =~ /OMGHAX/ }
|
@@ -18,7 +20,7 @@ describe 'Rack::Attack.Fail2Ban' do
|
|
18
20
|
describe 'making ok request' do
|
19
21
|
it 'succeeds' do
|
20
22
|
get '/', {}, 'REMOTE_ADDR' => '1.2.3.4'
|
21
|
-
last_response.status.must_equal 200
|
23
|
+
_(last_response.status).must_equal 200
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
@@ -27,17 +29,17 @@ describe 'Rack::Attack.Fail2Ban' do
|
|
27
29
|
before { get '/?foo=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4' }
|
28
30
|
|
29
31
|
it 'fails' do
|
30
|
-
last_response.status.must_equal 403
|
32
|
+
_(last_response.status).must_equal 403
|
31
33
|
end
|
32
34
|
|
33
35
|
it 'increases fail count' do
|
34
36
|
key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
|
35
|
-
@cache.store.read(key).must_equal 1
|
37
|
+
_(@cache.store.read(key)).must_equal 1
|
36
38
|
end
|
37
39
|
|
38
40
|
it 'is not banned' do
|
39
41
|
key = "rack::attack:fail2ban:1.2.3.4"
|
40
|
-
@cache.store.read(key).must_be_nil
|
42
|
+
_(@cache.store.read(key)).must_be_nil
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
@@ -49,17 +51,17 @@ describe 'Rack::Attack.Fail2Ban' do
|
|
49
51
|
end
|
50
52
|
|
51
53
|
it 'fails' do
|
52
|
-
last_response.status.must_equal 403
|
54
|
+
_(last_response.status).must_equal 403
|
53
55
|
end
|
54
56
|
|
55
57
|
it 'increases fail count' do
|
56
58
|
key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
|
57
|
-
@cache.store.read(key).must_equal 2
|
59
|
+
_(@cache.store.read(key)).must_equal 2
|
58
60
|
end
|
59
61
|
|
60
62
|
it 'is banned' do
|
61
63
|
key = "rack::attack:fail2ban:ban:1.2.3.4"
|
62
|
-
@cache.store.read(key).must_equal 1
|
64
|
+
_(@cache.store.read(key)).must_equal 1
|
63
65
|
end
|
64
66
|
end
|
65
67
|
|
@@ -71,7 +73,7 @@ describe 'Rack::Attack.Fail2Ban' do
|
|
71
73
|
end
|
72
74
|
|
73
75
|
it 'succeeds' do
|
74
|
-
last_response.status.must_equal 200
|
76
|
+
_(last_response.status).must_equal 200
|
75
77
|
end
|
76
78
|
|
77
79
|
it 'resets fail count' do
|
@@ -80,7 +82,7 @@ describe 'Rack::Attack.Fail2Ban' do
|
|
80
82
|
end
|
81
83
|
|
82
84
|
it 'IP is not banned' do
|
83
|
-
Rack::Attack::Fail2Ban.banned?('1.2.3.4').must_equal false
|
85
|
+
_(Rack::Attack::Fail2Ban.banned?('1.2.3.4')).must_equal false
|
84
86
|
end
|
85
87
|
end
|
86
88
|
end
|
@@ -96,7 +98,8 @@ describe 'Rack::Attack.Fail2Ban' do
|
|
96
98
|
describe 'making request for other discriminator' do
|
97
99
|
it 'succeeds' do
|
98
100
|
get '/', {}, 'REMOTE_ADDR' => '2.2.3.4'
|
99
|
-
|
101
|
+
|
102
|
+
_(last_response.status).must_equal 200
|
100
103
|
end
|
101
104
|
end
|
102
105
|
|
@@ -106,17 +109,17 @@ describe 'Rack::Attack.Fail2Ban' do
|
|
106
109
|
end
|
107
110
|
|
108
111
|
it 'fails' do
|
109
|
-
last_response.status.must_equal 403
|
112
|
+
_(last_response.status).must_equal 403
|
110
113
|
end
|
111
114
|
|
112
115
|
it 'does not increase fail count' do
|
113
116
|
key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
|
114
|
-
@cache.store.read(key).must_equal 2
|
117
|
+
_(@cache.store.read(key)).must_equal 2
|
115
118
|
end
|
116
119
|
|
117
120
|
it 'is still banned' do
|
118
121
|
key = "rack::attack:fail2ban:ban:1.2.3.4"
|
119
|
-
@cache.store.read(key).must_equal 1
|
122
|
+
_(@cache.store.read(key)).must_equal 1
|
120
123
|
end
|
121
124
|
end
|
122
125
|
|
@@ -126,17 +129,17 @@ describe 'Rack::Attack.Fail2Ban' do
|
|
126
129
|
end
|
127
130
|
|
128
131
|
it 'fails' do
|
129
|
-
last_response.status.must_equal 403
|
132
|
+
_(last_response.status).must_equal 403
|
130
133
|
end
|
131
134
|
|
132
135
|
it 'does not increase fail count' do
|
133
136
|
key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
|
134
|
-
@cache.store.read(key).must_equal 2
|
137
|
+
_(@cache.store.read(key)).must_equal 2
|
135
138
|
end
|
136
139
|
|
137
140
|
it 'is still banned' do
|
138
141
|
key = "rack::attack:fail2ban:ban:1.2.3.4"
|
139
|
-
@cache.store.read(key).must_equal 1
|
142
|
+
_(@cache.store.read(key)).must_equal 1
|
140
143
|
end
|
141
144
|
end
|
142
145
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support/cache'
|
2
4
|
require_relative '../spec_helper'
|
3
5
|
|
@@ -22,7 +24,7 @@ if defined?(::ActiveSupport::Cache::RedisStore)
|
|
22
24
|
before do
|
23
25
|
@cache = Rack::Attack::Cache.new
|
24
26
|
# Use presumably unused port for Redis client
|
25
|
-
@cache.store = ActiveSupport::Cache::RedisStore.new(:
|
27
|
+
@cache.store = ActiveSupport::Cache::RedisStore.new(host: '127.0.0.1', port: 3333)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "spec_helper"
|
4
|
+
|
5
|
+
# ActiveSupport::Subscribers added in ~> 4.0.2.0
|
6
|
+
if ActiveSupport::VERSION::MAJOR > 3
|
7
|
+
require_relative 'spec_helper'
|
8
|
+
require 'active_support/subscriber'
|
9
|
+
class CustomSubscriber < ActiveSupport::Subscriber
|
10
|
+
@notification_count = 0
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :notification_count
|
14
|
+
end
|
15
|
+
|
16
|
+
def throttle(_event)
|
17
|
+
self.class.notification_count += 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'Rack::Attack.instrument' do
|
22
|
+
before do
|
23
|
+
@period = 60 # Use a long period; failures due to cache key rotation less likely
|
24
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
25
|
+
Rack::Attack.throttle('ip/sec', limit: 1, period: @period) { |req| req.ip }
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "with throttling" do
|
29
|
+
before do
|
30
|
+
ActiveSupport::Notifications.stub(:notifier, ActiveSupport::Notifications::Fanout.new) do
|
31
|
+
CustomSubscriber.attach_to("rack_attack")
|
32
|
+
2.times { get '/', {}, 'REMOTE_ADDR' => '1.2.3.4' }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should instrument without error' do
|
37
|
+
_(last_response.status).must_equal 429
|
38
|
+
assert_equal 1, CustomSubscriber.notification_count
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,17 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'spec_helper'
|
2
4
|
|
3
5
|
describe Rack::Attack::PathNormalizer do
|
4
6
|
subject { Rack::Attack::PathNormalizer }
|
5
7
|
|
6
8
|
it 'should have a normalize_path method' do
|
7
|
-
subject.normalize_path('/foo').must_equal '/foo'
|
9
|
+
_(subject.normalize_path('/foo')).must_equal '/foo'
|
8
10
|
end
|
9
11
|
|
10
12
|
describe 'FallbackNormalizer' do
|
11
13
|
subject { Rack::Attack::FallbackPathNormalizer }
|
12
14
|
|
13
15
|
it '#normalize_path does not change the path' do
|
14
|
-
subject.normalize_path('').must_equal ''
|
16
|
+
_(subject.normalize_path('')).must_equal ''
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
data/spec/rack_attack_spec.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'spec_helper'
|
2
4
|
|
3
5
|
describe 'Rack::Attack' do
|
@@ -10,7 +12,7 @@ describe 'Rack::Attack' do
|
|
10
12
|
|
11
13
|
it 'blocks requests with trailing slash' do
|
12
14
|
get '/foo/'
|
13
|
-
last_response.status.must_equal 403
|
15
|
+
_(last_response.status).must_equal 403
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
@@ -20,28 +22,21 @@ describe 'Rack::Attack' do
|
|
20
22
|
Rack::Attack.blocklist("ip #{@bad_ip}") { |req| req.ip == @bad_ip }
|
21
23
|
end
|
22
24
|
|
23
|
-
it
|
24
|
-
Rack::Attack.blocklists.key?("ip #{@bad_ip}").must_equal true
|
25
|
-
|
26
|
-
|
27
|
-
it('has a blacklist with a deprication warning') {
|
28
|
-
_, stderror = capture_io do
|
29
|
-
Rack::Attack.blacklists.key?("ip #{@bad_ip}").must_equal true
|
30
|
-
end
|
31
|
-
assert_match "[DEPRECATION] 'Rack::Attack.blacklists' is deprecated. Please use 'blocklists' instead.", stderror
|
32
|
-
}
|
25
|
+
it 'has a blocklist' do
|
26
|
+
_(Rack::Attack.blocklists.key?("ip #{@bad_ip}")).must_equal true
|
27
|
+
end
|
33
28
|
|
34
29
|
describe "a bad request" do
|
35
30
|
before { get '/', {}, 'REMOTE_ADDR' => @bad_ip }
|
36
31
|
|
37
32
|
it "should return a blocklist response" do
|
38
|
-
last_response.status.must_equal 403
|
39
|
-
last_response.body.must_equal "Forbidden\n"
|
33
|
+
_(last_response.status).must_equal 403
|
34
|
+
_(last_response.body).must_equal "Forbidden\n"
|
40
35
|
end
|
41
36
|
|
42
37
|
it "should tag the env" do
|
43
|
-
last_request.env['rack.attack.matched'].must_equal "ip #{@bad_ip}"
|
44
|
-
last_request.env['rack.attack.match_type'].must_equal :blocklist
|
38
|
+
_(last_request.env['rack.attack.matched']).must_equal "ip #{@bad_ip}"
|
39
|
+
_(last_request.env['rack.attack.match_type']).must_equal :blocklist
|
45
40
|
end
|
46
41
|
|
47
42
|
it_allows_ok_requests
|
@@ -55,43 +50,52 @@ describe 'Rack::Attack' do
|
|
55
50
|
|
56
51
|
it('has a safelist') { Rack::Attack.safelists.key?("good ua") }
|
57
52
|
|
58
|
-
it('has a whitelist with a deprication warning') {
|
59
|
-
_, stderror = capture_io do
|
60
|
-
Rack::Attack.whitelists.key?("good ua")
|
61
|
-
end
|
62
|
-
assert_match "[DEPRECATION] 'Rack::Attack.whitelists' is deprecated. Please use 'safelists' instead.", stderror
|
63
|
-
}
|
64
|
-
|
65
53
|
describe "with a request match both safelist & blocklist" do
|
66
54
|
before { get '/', {}, 'REMOTE_ADDR' => @bad_ip, 'HTTP_USER_AGENT' => @good_ua }
|
67
55
|
|
68
56
|
it "should allow safelists before blocklists" do
|
69
|
-
last_response.status.must_equal 200
|
57
|
+
_(last_response.status).must_equal 200
|
70
58
|
end
|
71
59
|
|
72
60
|
it "should tag the env" do
|
73
|
-
last_request.env['rack.attack.matched'].must_equal 'good ua'
|
74
|
-
last_request.env['rack.attack.match_type'].must_equal :safelist
|
61
|
+
_(last_request.env['rack.attack.matched']).must_equal 'good ua'
|
62
|
+
_(last_request.env['rack.attack.match_type']).must_equal :safelist
|
75
63
|
end
|
76
64
|
end
|
77
65
|
end
|
78
66
|
|
79
67
|
describe '#blocklisted_response' do
|
80
68
|
it 'should exist' do
|
81
|
-
Rack::Attack.blocklisted_response.must_respond_to :call
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'should give a deprication warning for blacklisted_response' do
|
85
|
-
_, stderror = capture_io do
|
86
|
-
Rack::Attack.blacklisted_response
|
87
|
-
end
|
88
|
-
assert_match "[DEPRECATION] 'Rack::Attack.blacklisted_response' is deprecated. Please use 'blocklisted_response' instead.", stderror
|
69
|
+
_(Rack::Attack.blocklisted_response).must_respond_to :call
|
89
70
|
end
|
90
71
|
end
|
91
72
|
|
92
73
|
describe '#throttled_response' do
|
93
74
|
it 'should exist' do
|
94
|
-
Rack::Attack.throttled_response.must_respond_to :call
|
75
|
+
_(Rack::Attack.throttled_response).must_respond_to :call
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'enabled' do
|
81
|
+
it 'should be enabled by default' do
|
82
|
+
_(Rack::Attack.enabled).must_equal true
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should directly pass request when disabled' do
|
86
|
+
bad_ip = '1.2.3.4'
|
87
|
+
Rack::Attack.blocklist("ip #{bad_ip}") { |req| req.ip == bad_ip }
|
88
|
+
|
89
|
+
get '/', {}, 'REMOTE_ADDR' => bad_ip
|
90
|
+
_(last_response.status).must_equal 403
|
91
|
+
|
92
|
+
prev_enabled = Rack::Attack.enabled
|
93
|
+
begin
|
94
|
+
Rack::Attack.enabled = false
|
95
|
+
get '/', {}, 'REMOTE_ADDR' => bad_ip
|
96
|
+
_(last_response.status).must_equal 200
|
97
|
+
ensure
|
98
|
+
Rack::Attack.enabled = prev_enabled
|
95
99
|
end
|
96
100
|
end
|
97
101
|
end
|
@@ -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', :
|
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') }
|
@@ -16,12 +18,19 @@ describe 'Rack::Attack.throttle' do
|
|
16
18
|
|
17
19
|
it 'should set the counter for one request' do
|
18
20
|
key = "rack::attack:#{Time.now.to_i / @period}:ip/sec:1.2.3.4"
|
19
|
-
Rack::Attack.cache.store.read(key).must_equal 1
|
21
|
+
_(Rack::Attack.cache.store.read(key)).must_equal 1
|
20
22
|
end
|
21
23
|
|
22
24
|
it 'should populate throttle data' do
|
23
|
-
data = {
|
24
|
-
|
25
|
+
data = {
|
26
|
+
count: 1,
|
27
|
+
limit: 1,
|
28
|
+
period: @period,
|
29
|
+
epoch_time: Rack::Attack.cache.last_epoch_time.to_i,
|
30
|
+
discriminator: "1.2.3.4"
|
31
|
+
}
|
32
|
+
|
33
|
+
_(last_request.env['rack.attack.throttle_data']['ip/sec']).must_equal data
|
25
34
|
end
|
26
35
|
end
|
27
36
|
|
@@ -31,18 +40,26 @@ describe 'Rack::Attack.throttle' do
|
|
31
40
|
end
|
32
41
|
|
33
42
|
it 'should block the last request' do
|
34
|
-
last_response.status.must_equal 429
|
43
|
+
_(last_response.status).must_equal 429
|
35
44
|
end
|
36
45
|
|
37
46
|
it 'should tag the env' do
|
38
|
-
last_request.env['rack.attack.matched'].must_equal 'ip/sec'
|
39
|
-
last_request.env['rack.attack.match_type'].must_equal :throttle
|
40
|
-
|
41
|
-
last_request.env['rack.attack.
|
47
|
+
_(last_request.env['rack.attack.matched']).must_equal 'ip/sec'
|
48
|
+
_(last_request.env['rack.attack.match_type']).must_equal :throttle
|
49
|
+
|
50
|
+
_(last_request.env['rack.attack.match_data']).must_equal(
|
51
|
+
count: 2,
|
52
|
+
limit: 1,
|
53
|
+
period: @period,
|
54
|
+
epoch_time: Rack::Attack.cache.last_epoch_time.to_i,
|
55
|
+
discriminator: "1.2.3.4"
|
56
|
+
)
|
57
|
+
|
58
|
+
_(last_request.env['rack.attack.match_discriminator']).must_equal('1.2.3.4')
|
42
59
|
end
|
43
60
|
|
44
61
|
it 'should set a Retry-After header' do
|
45
|
-
last_response.headers['Retry-After'].must_equal @period.to_s
|
62
|
+
_(last_response.headers['Retry-After']).must_equal @period.to_s
|
46
63
|
end
|
47
64
|
end
|
48
65
|
end
|
@@ -51,7 +68,7 @@ describe 'Rack::Attack.throttle with limit as proc' do
|
|
51
68
|
before do
|
52
69
|
@period = 60 # Use a long period; failures due to cache key rotation less likely
|
53
70
|
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
54
|
-
Rack::Attack.throttle('ip/sec', :
|
71
|
+
Rack::Attack.throttle('ip/sec', limit: lambda { |_req| 1 }, period: @period) { |req| req.ip }
|
55
72
|
end
|
56
73
|
|
57
74
|
it_allows_ok_requests
|
@@ -61,12 +78,19 @@ describe 'Rack::Attack.throttle with limit as proc' do
|
|
61
78
|
|
62
79
|
it 'should set the counter for one request' do
|
63
80
|
key = "rack::attack:#{Time.now.to_i / @period}:ip/sec:1.2.3.4"
|
64
|
-
Rack::Attack.cache.store.read(key).must_equal 1
|
81
|
+
_(Rack::Attack.cache.store.read(key)).must_equal 1
|
65
82
|
end
|
66
83
|
|
67
84
|
it 'should populate throttle data' do
|
68
|
-
data = {
|
69
|
-
|
85
|
+
data = {
|
86
|
+
count: 1,
|
87
|
+
limit: 1,
|
88
|
+
period: @period,
|
89
|
+
epoch_time: Rack::Attack.cache.last_epoch_time.to_i,
|
90
|
+
discriminator: "1.2.3.4"
|
91
|
+
}
|
92
|
+
|
93
|
+
_(last_request.env['rack.attack.throttle_data']['ip/sec']).must_equal data
|
70
94
|
end
|
71
95
|
end
|
72
96
|
end
|
@@ -75,7 +99,7 @@ describe 'Rack::Attack.throttle with period as proc' do
|
|
75
99
|
before do
|
76
100
|
@period = 60 # Use a long period; failures due to cache key rotation less likely
|
77
101
|
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
78
|
-
Rack::Attack.throttle('ip/sec', :
|
102
|
+
Rack::Attack.throttle('ip/sec', limit: lambda { |_req| 1 }, period: lambda { |_req| @period }) { |req| req.ip }
|
79
103
|
end
|
80
104
|
|
81
105
|
it_allows_ok_requests
|
@@ -85,12 +109,19 @@ describe 'Rack::Attack.throttle with period as proc' do
|
|
85
109
|
|
86
110
|
it 'should set the counter for one request' do
|
87
111
|
key = "rack::attack:#{Time.now.to_i / @period}:ip/sec:1.2.3.4"
|
88
|
-
Rack::Attack.cache.store.read(key).must_equal 1
|
112
|
+
_(Rack::Attack.cache.store.read(key)).must_equal 1
|
89
113
|
end
|
90
114
|
|
91
115
|
it 'should populate throttle data' do
|
92
|
-
data = {
|
93
|
-
|
116
|
+
data = {
|
117
|
+
count: 1,
|
118
|
+
limit: 1,
|
119
|
+
period: @period,
|
120
|
+
epoch_time: Rack::Attack.cache.last_epoch_time.to_i,
|
121
|
+
discriminator: "1.2.3.4"
|
122
|
+
}
|
123
|
+
|
124
|
+
_(last_request.env['rack.attack.throttle_data']['ip/sec']).must_equal data
|
94
125
|
end
|
95
126
|
end
|
96
127
|
end
|
@@ -99,7 +130,7 @@ describe 'Rack::Attack.throttle with block retuning nil' do
|
|
99
130
|
before do
|
100
131
|
@period = 60
|
101
132
|
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
102
|
-
Rack::Attack.throttle('ip/sec', :
|
133
|
+
Rack::Attack.throttle('ip/sec', limit: 1, period: @period) { |_| nil }
|
103
134
|
end
|
104
135
|
|
105
136
|
it_allows_ok_requests
|