rack-attack 5.0.1 → 5.4.2

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 (63) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +190 -94
  3. data/Rakefile +11 -4
  4. data/bin/setup +8 -0
  5. data/lib/rack/attack.rb +83 -51
  6. data/lib/rack/attack/allow2ban.rb +2 -1
  7. data/lib/rack/attack/blocklist.rb +0 -1
  8. data/lib/rack/attack/cache.rb +24 -5
  9. data/lib/rack/attack/check.rb +6 -8
  10. data/lib/rack/attack/fail2ban.rb +2 -1
  11. data/lib/rack/attack/path_normalizer.rb +6 -11
  12. data/lib/rack/attack/safelist.rb +0 -1
  13. data/lib/rack/attack/store_proxy.rb +3 -12
  14. data/lib/rack/attack/store_proxy/dalli_proxy.rb +2 -3
  15. data/lib/rack/attack/store_proxy/mem_cache_proxy.rb +4 -5
  16. data/lib/rack/attack/store_proxy/mem_cache_store_proxy.rb +19 -0
  17. data/lib/rack/attack/store_proxy/redis_cache_store_proxy.rb +35 -0
  18. data/lib/rack/attack/store_proxy/redis_proxy.rb +54 -0
  19. data/lib/rack/attack/store_proxy/redis_store_proxy.rb +5 -24
  20. data/lib/rack/attack/throttle.rb +16 -12
  21. data/lib/rack/attack/track.rb +3 -3
  22. data/lib/rack/attack/version.rb +1 -1
  23. data/spec/acceptance/allow2ban_spec.rb +71 -0
  24. data/spec/acceptance/blocking_ip_spec.rb +38 -0
  25. data/spec/acceptance/blocking_spec.rb +41 -0
  26. data/spec/acceptance/blocking_subnet_spec.rb +44 -0
  27. data/spec/acceptance/cache_store_config_for_allow2ban_spec.rb +126 -0
  28. data/spec/acceptance/cache_store_config_for_fail2ban_spec.rb +121 -0
  29. data/spec/acceptance/cache_store_config_for_throttle_spec.rb +48 -0
  30. data/spec/acceptance/cache_store_config_with_rails_spec.rb +31 -0
  31. data/spec/acceptance/customizing_blocked_response_spec.rb +41 -0
  32. data/spec/acceptance/customizing_throttled_response_spec.rb +59 -0
  33. data/spec/acceptance/extending_request_object_spec.rb +34 -0
  34. data/spec/acceptance/fail2ban_spec.rb +76 -0
  35. data/spec/acceptance/safelisting_ip_spec.rb +48 -0
  36. data/spec/acceptance/safelisting_spec.rb +53 -0
  37. data/spec/acceptance/safelisting_subnet_spec.rb +48 -0
  38. data/spec/acceptance/stores/active_support_dalli_store_spec.rb +19 -0
  39. data/spec/acceptance/stores/active_support_mem_cache_store_pooled_spec.rb +22 -0
  40. data/spec/acceptance/stores/active_support_mem_cache_store_spec.rb +18 -0
  41. data/spec/acceptance/stores/active_support_memory_store_spec.rb +16 -0
  42. data/spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb +18 -0
  43. data/spec/acceptance/stores/active_support_redis_cache_store_spec.rb +18 -0
  44. data/spec/acceptance/stores/active_support_redis_store_spec.rb +18 -0
  45. data/spec/acceptance/stores/connection_pool_dalli_client_spec.rb +22 -0
  46. data/spec/acceptance/stores/dalli_client_spec.rb +19 -0
  47. data/spec/acceptance/stores/redis_spec.rb +20 -0
  48. data/spec/acceptance/stores/redis_store_spec.rb +18 -0
  49. data/spec/acceptance/throttling_spec.rb +159 -0
  50. data/spec/acceptance/track_spec.rb +27 -0
  51. data/spec/acceptance/track_throttle_spec.rb +53 -0
  52. data/spec/allow2ban_spec.rb +9 -8
  53. data/spec/fail2ban_spec.rb +11 -9
  54. data/spec/integration/offline_spec.rb +21 -23
  55. data/spec/rack_attack_dalli_proxy_spec.rb +0 -2
  56. data/spec/rack_attack_request_spec.rb +1 -1
  57. data/spec/rack_attack_spec.rb +13 -14
  58. data/spec/rack_attack_throttle_spec.rb +28 -18
  59. data/spec/rack_attack_track_spec.rb +11 -8
  60. data/spec/spec_helper.rb +35 -14
  61. data/spec/support/cache_store_helper.rb +82 -0
  62. metadata +150 -65
  63. data/spec/integration/rack_attack_cache_spec.rb +0 -122
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../spec_helper"
4
+
5
+ if defined?(::Redis)
6
+ require_relative "../../support/cache_store_helper"
7
+ require "timecop"
8
+
9
+ describe "Plain redis as a cache backend" do
10
+ before do
11
+ Rack::Attack.cache.store = Redis.new
12
+ end
13
+
14
+ after do
15
+ Rack::Attack.cache.store.flushdb
16
+ end
17
+
18
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.get(key) })
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ require_relative "../../spec_helper"
2
+ require_relative "../../support/cache_store_helper"
3
+
4
+ if defined?(::Redis::Store)
5
+ require "timecop"
6
+
7
+ describe "ActiveSupport::Cache::RedisStore as a cache backend" do
8
+ before do
9
+ Rack::Attack.cache.store = ::Redis::Store.new
10
+ end
11
+
12
+ after do
13
+ Rack::Attack.cache.store.flushdb
14
+ end
15
+
16
+ it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.read(key) })
17
+ end
18
+ end
@@ -0,0 +1,159 @@
1
+ require_relative "../spec_helper"
2
+ require "timecop"
3
+
4
+ describe "#throttle" do
5
+ before do
6
+ Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
7
+ end
8
+
9
+ it "allows one request per minute by IP" do
10
+ Rack::Attack.throttle("by ip", limit: 1, period: 60) do |request|
11
+ request.ip
12
+ end
13
+
14
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
15
+
16
+ assert_equal 200, last_response.status
17
+
18
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
19
+
20
+ assert_equal 429, last_response.status
21
+ assert_equal "60", last_response.headers["Retry-After"]
22
+ assert_equal "Retry later\n", last_response.body
23
+
24
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8"
25
+
26
+ assert_equal 200, last_response.status
27
+
28
+ Timecop.travel(60) do
29
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
30
+
31
+ assert_equal 200, last_response.status
32
+ end
33
+ end
34
+
35
+ it "supports limit to be dynamic" do
36
+ # Could be used to have different rate limits for authorized
37
+ # vs general requests
38
+ limit_proc = lambda do |request|
39
+ if request.env["X-APIKey"] == "private-secret"
40
+ 2
41
+ else
42
+ 1
43
+ end
44
+ end
45
+
46
+ Rack::Attack.throttle("by ip", limit: limit_proc, period: 60) do |request|
47
+ request.ip
48
+ end
49
+
50
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
51
+ assert_equal 200, last_response.status
52
+
53
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
54
+ assert_equal 429, last_response.status
55
+
56
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret"
57
+ assert_equal 200, last_response.status
58
+
59
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret"
60
+ assert_equal 200, last_response.status
61
+
62
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret"
63
+ assert_equal 429, last_response.status
64
+ end
65
+
66
+ it "supports period to be dynamic" do
67
+ # Could be used to have different rate limits for authorized
68
+ # vs general requests
69
+ period_proc = lambda do |request|
70
+ if request.env["X-APIKey"] == "private-secret"
71
+ 10
72
+ else
73
+ 30
74
+ end
75
+ end
76
+
77
+ Rack::Attack.throttle("by ip", limit: 1, period: period_proc) do |request|
78
+ request.ip
79
+ end
80
+
81
+ # Using Time#at to align to start/end of periods exactly
82
+ # to achieve consistenty in different test runs
83
+
84
+ Timecop.travel(Time.at(0)) do
85
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
86
+ assert_equal 200, last_response.status
87
+
88
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
89
+ assert_equal 429, last_response.status
90
+ end
91
+
92
+ Timecop.travel(Time.at(10)) do
93
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
94
+ assert_equal 429, last_response.status
95
+ end
96
+
97
+ Timecop.travel(Time.at(30)) do
98
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
99
+ assert_equal 200, last_response.status
100
+ end
101
+
102
+ Timecop.travel(Time.at(0)) do
103
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret"
104
+ assert_equal 200, last_response.status
105
+
106
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret"
107
+ assert_equal 429, last_response.status
108
+ end
109
+
110
+ Timecop.travel(Time.at(10)) do
111
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8", "X-APIKey" => "private-secret"
112
+ assert_equal 200, last_response.status
113
+ end
114
+ end
115
+
116
+ it "notifies when the request is throttled" do
117
+ Rack::Attack.throttle("by ip", limit: 1, period: 60) do |request|
118
+ request.ip
119
+ end
120
+
121
+ notification_matched = nil
122
+ notification_type = nil
123
+ notification_data = nil
124
+ notification_discriminator = nil
125
+
126
+ ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, request|
127
+ notification_matched = request.env["rack.attack.matched"]
128
+ notification_type = request.env["rack.attack.match_type"]
129
+ notification_data = request.env['rack.attack.match_data']
130
+ notification_discriminator = request.env['rack.attack.match_discriminator']
131
+ end
132
+
133
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8"
134
+
135
+ assert_equal 200, last_response.status
136
+ assert_nil notification_matched
137
+ assert_nil notification_type
138
+ assert_nil notification_data
139
+ assert_nil notification_discriminator
140
+
141
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
142
+
143
+ assert_equal 200, last_response.status
144
+ assert_nil notification_matched
145
+ assert_nil notification_type
146
+ assert_nil notification_data
147
+ assert_nil notification_discriminator
148
+
149
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
150
+
151
+ assert_equal 429, last_response.status
152
+ assert_equal "by ip", notification_matched
153
+ assert_equal :throttle, notification_type
154
+ assert_equal 60, notification_data[:period]
155
+ assert_equal 1, notification_data[:limit]
156
+ assert_equal 2, notification_data[:count]
157
+ assert_equal "1.2.3.4", notification_discriminator
158
+ end
159
+ end
@@ -0,0 +1,27 @@
1
+ require_relative "../spec_helper"
2
+
3
+ describe "#track" do
4
+ it "notifies when track block returns true" do
5
+ Rack::Attack.track("ip 1.2.3.4") do |request|
6
+ request.ip == "1.2.3.4"
7
+ end
8
+
9
+ notification_matched = nil
10
+ notification_type = nil
11
+
12
+ ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, request|
13
+ notification_matched = request.env["rack.attack.matched"]
14
+ notification_type = request.env["rack.attack.match_type"]
15
+ end
16
+
17
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8"
18
+
19
+ assert_nil notification_matched
20
+ assert_nil notification_type
21
+
22
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
23
+
24
+ assert_equal "ip 1.2.3.4", notification_matched
25
+ assert_equal :track, notification_type
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ require_relative "../spec_helper"
2
+ require "timecop"
3
+
4
+ describe "#track with throttle-ish options" do
5
+ it "notifies when throttle goes over the limit without actually throttling requests" do
6
+ Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
7
+
8
+ Rack::Attack.track("by ip", limit: 1, period: 60) do |request|
9
+ request.ip
10
+ end
11
+
12
+ notification_matched = nil
13
+ notification_type = nil
14
+
15
+ ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, request|
16
+ notification_matched = request.env["rack.attack.matched"]
17
+ notification_type = request.env["rack.attack.match_type"]
18
+ end
19
+
20
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
21
+
22
+ assert_nil notification_matched
23
+ assert_nil notification_type
24
+
25
+ assert_equal 200, last_response.status
26
+
27
+ get "/", {}, "REMOTE_ADDR" => "5.6.7.8"
28
+
29
+ assert_nil notification_matched
30
+ assert_nil notification_type
31
+
32
+ assert_equal 200, last_response.status
33
+
34
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
35
+
36
+ assert_equal "by ip", notification_matched
37
+ assert_equal :track, notification_type
38
+
39
+ assert_equal 200, last_response.status
40
+
41
+ Timecop.travel(60) do
42
+ notification_matched = nil
43
+ notification_type = nil
44
+
45
+ get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
46
+
47
+ assert_nil notification_matched
48
+ assert_nil notification_type
49
+
50
+ assert_equal 200, last_response.status
51
+ end
52
+ end
53
+ end
@@ -1,4 +1,5 @@
1
1
  require_relative 'spec_helper'
2
+
2
3
  describe 'Rack::Attack.Allow2Ban' do
3
4
  before do
4
5
  # Use a long findtime; failures due to cache key rotation less likely
@@ -6,9 +7,10 @@ describe 'Rack::Attack.Allow2Ban' do
6
7
  @findtime = 60
7
8
  @bantime = 60
8
9
  Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
9
- @f2b_options = {:bantime => @bantime, :findtime => @findtime, :maxretry => 2}
10
+ @f2b_options = { :bantime => @bantime, :findtime => @findtime, :maxretry => 2 }
11
+
10
12
  Rack::Attack.blocklist('pentest') do |req|
11
- Rack::Attack::Allow2Ban.filter(req.ip, @f2b_options){req.query_string =~ /OMGHAX/}
13
+ Rack::Attack::Allow2Ban.filter(req.ip, @f2b_options) { req.query_string =~ /OMGHAX/ }
12
14
  end
13
15
  end
14
16
 
@@ -23,12 +25,13 @@ describe 'Rack::Attack.Allow2Ban' do
23
25
  describe 'making qualifying request' do
24
26
  describe 'when not at maxretry' do
25
27
  before { get '/?foo=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4' }
28
+
26
29
  it 'succeeds' do
27
30
  last_response.status.must_equal 200
28
31
  end
29
32
 
30
33
  it 'increases fail count' do
31
- key = "rack::attack:#{Time.now.to_i/@findtime}:allow2ban:count:1.2.3.4"
34
+ key = "rack::attack:#{Time.now.to_i / @findtime}:allow2ban:count:1.2.3.4"
32
35
  @cache.store.read(key).must_equal 1
33
36
  end
34
37
 
@@ -50,7 +53,7 @@ describe 'Rack::Attack.Allow2Ban' do
50
53
  end
51
54
 
52
55
  it 'increases fail count' do
53
- key = "rack::attack:#{Time.now.to_i/@findtime}:allow2ban:count:1.2.3.4"
56
+ key = "rack::attack:#{Time.now.to_i / @findtime}:allow2ban:count:1.2.3.4"
54
57
  @cache.store.read(key).must_equal 2
55
58
  end
56
59
 
@@ -58,7 +61,6 @@ describe 'Rack::Attack.Allow2Ban' do
58
61
  key = "rack::attack:allow2ban:ban:1.2.3.4"
59
62
  @cache.store.read(key).must_equal 1
60
63
  end
61
-
62
64
  end
63
65
  end
64
66
  end
@@ -87,7 +89,7 @@ describe 'Rack::Attack.Allow2Ban' do
87
89
  end
88
90
 
89
91
  it 'does not increase fail count' do
90
- key = "rack::attack:#{Time.now.to_i/@findtime}:allow2ban:count:1.2.3.4"
92
+ key = "rack::attack:#{Time.now.to_i / @findtime}:allow2ban:count:1.2.3.4"
91
93
  @cache.store.read(key).must_equal 2
92
94
  end
93
95
 
@@ -107,7 +109,7 @@ describe 'Rack::Attack.Allow2Ban' do
107
109
  end
108
110
 
109
111
  it 'does not increase fail count' do
110
- key = "rack::attack:#{Time.now.to_i/@findtime}:allow2ban:count:1.2.3.4"
112
+ key = "rack::attack:#{Time.now.to_i / @findtime}:allow2ban:count:1.2.3.4"
111
113
  @cache.store.read(key).must_equal 2
112
114
  end
113
115
 
@@ -116,6 +118,5 @@ describe 'Rack::Attack.Allow2Ban' do
116
118
  @cache.store.read(key).must_equal 1
117
119
  end
118
120
  end
119
-
120
121
  end
121
122
  end
@@ -1,4 +1,5 @@
1
1
  require_relative 'spec_helper'
2
+
2
3
  describe 'Rack::Attack.Fail2Ban' do
3
4
  before do
4
5
  # Use a long findtime; failures due to cache key rotation less likely
@@ -6,9 +7,10 @@ describe 'Rack::Attack.Fail2Ban' do
6
7
  @findtime = 60
7
8
  @bantime = 60
8
9
  Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
9
- @f2b_options = {:bantime => @bantime, :findtime => @findtime, :maxretry => 2}
10
+ @f2b_options = { :bantime => @bantime, :findtime => @findtime, :maxretry => 2 }
11
+
10
12
  Rack::Attack.blocklist('pentest') do |req|
11
- Rack::Attack::Fail2Ban.filter(req.ip, @f2b_options){req.query_string =~ /OMGHAX/}
13
+ Rack::Attack::Fail2Ban.filter(req.ip, @f2b_options) { req.query_string =~ /OMGHAX/ }
12
14
  end
13
15
  end
14
16
 
@@ -23,12 +25,13 @@ describe 'Rack::Attack.Fail2Ban' do
23
25
  describe 'making failing request' do
24
26
  describe 'when not at maxretry' do
25
27
  before { get '/?foo=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4' }
28
+
26
29
  it 'fails' do
27
30
  last_response.status.must_equal 403
28
31
  end
29
32
 
30
33
  it 'increases fail count' do
31
- key = "rack::attack:#{Time.now.to_i/@findtime}:fail2ban:count:1.2.3.4"
34
+ key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
32
35
  @cache.store.read(key).must_equal 1
33
36
  end
34
37
 
@@ -50,7 +53,7 @@ describe 'Rack::Attack.Fail2Ban' do
50
53
  end
51
54
 
52
55
  it 'increases fail count' do
53
- key = "rack::attack:#{Time.now.to_i/@findtime}:fail2ban:count:1.2.3.4"
56
+ key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
54
57
  @cache.store.read(key).must_equal 2
55
58
  end
56
59
 
@@ -72,8 +75,8 @@ describe 'Rack::Attack.Fail2Ban' do
72
75
  end
73
76
 
74
77
  it 'resets fail count' do
75
- key = "rack::attack:#{Time.now.to_i/@findtime}:fail2ban:count:1.2.3.4"
76
- @cache.store.read(key).must_equal nil
78
+ key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
79
+ assert_nil @cache.store.read(key)
77
80
  end
78
81
 
79
82
  it 'IP is not banned' do
@@ -107,7 +110,7 @@ describe 'Rack::Attack.Fail2Ban' do
107
110
  end
108
111
 
109
112
  it 'does not increase fail count' do
110
- key = "rack::attack:#{Time.now.to_i/@findtime}:fail2ban:count:1.2.3.4"
113
+ key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
111
114
  @cache.store.read(key).must_equal 2
112
115
  end
113
116
 
@@ -127,7 +130,7 @@ describe 'Rack::Attack.Fail2Ban' do
127
130
  end
128
131
 
129
132
  it 'does not increase fail count' do
130
- key = "rack::attack:#{Time.now.to_i/@findtime}:fail2ban:count:1.2.3.4"
133
+ key = "rack::attack:#{Time.now.to_i / @findtime}:fail2ban:count:1.2.3.4"
131
134
  @cache.store.read(key).must_equal 2
132
135
  end
133
136
 
@@ -136,6 +139,5 @@ describe 'Rack::Attack.Fail2Ban' do
136
139
  @cache.store.read(key).must_equal 1
137
140
  end
138
141
  end
139
-
140
142
  end
141
143
  end
@@ -1,10 +1,7 @@
1
1
  require 'active_support/cache'
2
- require 'redis-activesupport'
3
- require 'dalli'
4
2
  require_relative '../spec_helper'
5
3
 
6
4
  OfflineExamples = Minitest::SharedExamples.new do
7
-
8
5
  it 'should write' do
9
6
  @cache.write('cache-test-key', 'foobar', 1)
10
7
  end
@@ -16,32 +13,33 @@ OfflineExamples = Minitest::SharedExamples.new do
16
13
  it 'should count' do
17
14
  @cache.send(:do_count, 'rack::attack::cache-test-key', 1)
18
15
  end
19
-
20
16
  end
21
17
 
22
- describe 'when Redis is offline' do
23
- include OfflineExamples
24
-
25
- before {
26
- @cache = Rack::Attack::Cache.new
27
- # Use presumably unused port for Redis client
28
- @cache.store = ActiveSupport::Cache::RedisStore.new(:host => '127.0.0.1', :port => 3333)
29
- }
18
+ if defined?(::ActiveSupport::Cache::RedisStore)
19
+ describe 'when Redis is offline' do
20
+ include OfflineExamples
30
21
 
22
+ before do
23
+ @cache = Rack::Attack::Cache.new
24
+ # Use presumably unused port for Redis client
25
+ @cache.store = ActiveSupport::Cache::RedisStore.new(:host => '127.0.0.1', :port => 3333)
26
+ end
27
+ end
31
28
  end
32
29
 
33
- describe 'when Memcached is offline' do
34
- include OfflineExamples
35
-
36
- before {
37
- Dalli.logger.level = Logger::FATAL
30
+ if defined?(::Dalli)
31
+ describe 'when Memcached is offline' do
32
+ include OfflineExamples
38
33
 
39
- @cache = Rack::Attack::Cache.new
40
- @cache.store = Dalli::Client.new('127.0.0.1:22122')
41
- }
34
+ before do
35
+ Dalli.logger.level = Logger::FATAL
42
36
 
43
- after {
44
- Dalli.logger.level = Logger::INFO
45
- }
37
+ @cache = Rack::Attack::Cache.new
38
+ @cache.store = Dalli::Client.new('127.0.0.1:22122')
39
+ end
46
40
 
41
+ after do
42
+ Dalli.logger.level = Logger::INFO
43
+ end
44
+ end
47
45
  end