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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e666812691cc414692f7125979f0b152a9111ccee075e65b811fa4a6d8770daa
4
- data.tar.gz: 3e8caba79f7ad09d4999cce6358de9cc29b815dee3c9f9c5adbf12763c764656
3
+ metadata.gz: f85825803ce676e10466175d4bb99cc151d649130d6f4008bdffdc1381b4650a
4
+ data.tar.gz: 2bcd9d6a9d75491df5a9ddf2f7a5128eae152245fce8f27a069f36037ebc8ddb
5
5
  SHA512:
6
- metadata.gz: f630c0cd1a34bd588e616653a2e6795e2ec6baafc0e0df8b489e6aa451cf47fb64065447fb3ceb2b029a51d87a0393d6d44cea02e58423626ea46165531f7da3
7
- data.tar.gz: 22efc414db06b0a1bbbf8e6d34a3e0d0ead64f1832f48dc30af7ec0a374ef215d53cacf0a8e95c842bff0af84df0939f27820e4668c739eb8db3c51ebba4088e
6
+ metadata.gz: 5c9b03bbb0e55105ebe4d2ea9a0f13a025ea7ab4903f86e07956ecbd7f7ddfcacfecbbc8239bc9ac427fcc4bd5445fa85e20732bd4d90b51f6dafeb7194bc063
7
+ data.tar.gz: a31dad7fb5c9220d4a44b303103ffb12cb23843bc150b14cec38a9d0151bc73791a66a80e8a543fa09f58d36a7b0627f0b5fda4fb93953d525747840d7e1d97f
data/README.md CHANGED
@@ -10,9 +10,42 @@ See the [Backing & Hacking blog post](https://www.kickstarter.com/backing-and-ha
10
10
  [![Build Status](https://travis-ci.org/kickstarter/rack-attack.svg?branch=master)](https://travis-ci.org/kickstarter/rack-attack)
11
11
  [![Code Climate](https://codeclimate.com/github/kickstarter/rack-attack.svg)](https://codeclimate.com/github/kickstarter/rack-attack)
12
12
 
13
+ ## Table of contents
14
+
15
+ - [Getting started](#getting-started)
16
+ - [Installing](#installing)
17
+ - [Plugging into the application](#plugging-into-the-application)
18
+ - [Usage](#usage)
19
+ - [Safelisting](#safelisting)
20
+ - [`safelist_ip(ip_address_string)`](#safelist_ipip_address_string)
21
+ - [`safelist_ip(ip_subnet_string)`](#safelist_ipip_subnet_string)
22
+ - [`safelist(name, &block)`](#safelistname-block)
23
+ - [Blocking](#blocking)
24
+ - [`blocklist_ip(ip_address_string)`](#blocklist_ipip_address_string)
25
+ - [`blocklist_ip(ip_subnet_string)`](#blocklist_ipip_subnet_string)
26
+ - [`blocklist(name, &block)`](#blocklistname-block)
27
+ - [Fail2Ban](#fail2ban)
28
+ - [Allow2Ban](#allow2ban)
29
+ - [Throttling](#throttling)
30
+ - [`throttle(name, options, &block)`](#throttlename-options-block)
31
+ - [Tracks](#tracks)
32
+ - [Cache store configuration](#cache-store-configuration)
33
+ - [Customizing responses](#customizing-responses)
34
+ - [RateLimit headers for well-behaved clients](#ratelimit-headers-for-well-behaved-clients)
35
+ - [Logging & Instrumentation](#logging--instrumentation)
36
+ - [How it works](#how-it-works)
37
+ - [About Tracks](#about-tracks)
38
+ - [Testing](#testing)
39
+ - [Performance](#performance)
40
+ - [Motivation](#motivation)
41
+ - [Contributing](#contributing)
42
+ - [Code of Conduct](#code-of-conduct)
43
+ - [Development setup](#development-setup)
44
+ - [License](#license)
45
+
13
46
  ## Getting started
14
47
 
15
- ### 1. Installing
48
+ ### Installing
16
49
 
17
50
  Add this line to your application's Gemfile:
18
51
 
@@ -30,7 +63,7 @@ Or install it yourself as:
30
63
 
31
64
  $ gem install rack-attack
32
65
 
33
- ### 2. Plugging into the application
66
+ ### Plugging into the application
34
67
 
35
68
  Then tell your ruby web application to use rack-attack as a middleware.
36
69
 
@@ -55,8 +88,8 @@ __IMPORTANT__: By default, rack-attack won't perform any blocking or throttling,
55
88
 
56
89
  ## Usage
57
90
 
58
- *Tip:* The example in the wiki is a great way to get started:
59
- [Example Configuration](https://github.com/kickstarter/rack-attack/wiki/Example-Configuration)
91
+ *Tip:* If you just want to get going asap, then you can take our [example configuration](docs/example_configuration.md)
92
+ and tailor it to your needs, or check out the [advanced configuration](docs/advanced_configuration.md) examples.
60
93
 
61
94
  Define rules by calling `Rack::Attack` public methods, in any file that runs when your application is being initialized. For rails applications this means creating a new file named `config/initializers/rack_attack.rb` and writing your rules there.
62
95
 
@@ -86,7 +119,7 @@ Rack::Attack.safelist_ip("5.6.7.0/24")
86
119
 
87
120
  #### `safelist(name, &block)`
88
121
 
89
- Name your custom safelist and make your ruby-block argument return a truthy value if you want the request to be blocked, and falsy otherwise.
122
+ Name your custom safelist and make your ruby-block argument return a truthy value if you want the request to be allowed, and falsy otherwise.
90
123
 
91
124
  The request object is a [Rack::Request](http://www.rubydoc.info/gems/rack/Rack/Request).
92
125
 
@@ -252,7 +285,8 @@ Rack::Attack.track("special_agent", limit: 6, period: 60) do |req|
252
285
  end
253
286
 
254
287
  # Track it using ActiveSupport::Notification
255
- ActiveSupport::Notifications.subscribe("rack.attack") do |name, start, finish, request_id, req|
288
+ ActiveSupport::Notifications.subscribe("rack.attack") do |name, start, finish, request_id, payload|
289
+ req = payload[:request]
256
290
  if req.env['rack.attack.matched'] == "special_agent" && req.env['rack.attack.match_type'] == :track
257
291
  Rails.logger.info "special_agent: #{req.path}"
258
292
  STATSD.increment("special_agent")
@@ -294,12 +328,12 @@ Rack::Attack.throttled_response = lambda do |env|
294
328
  end
295
329
  ```
296
330
 
297
- ### X-RateLimit headers for well-behaved clients
331
+ ### RateLimit headers for well-behaved clients
298
332
 
299
333
  While Rack::Attack's primary focus is minimizing harm from abusive clients, it
300
334
  can also be used to return rate limit data that's helpful for well-behaved clients.
301
335
 
302
- Here's an example response that includes conventional `X-RateLimit-*` headers:
336
+ Here's an example response that includes conventional `RateLimit-*` headers:
303
337
 
304
338
  ```ruby
305
339
  Rack::Attack.throttled_response = lambda do |env|
@@ -307,9 +341,9 @@ Rack::Attack.throttled_response = lambda do |env|
307
341
  now = match_data[:epoch_time]
308
342
 
309
343
  headers = {
310
- 'X-RateLimit-Limit' => match_data[:limit].to_s,
311
- 'X-RateLimit-Remaining' => '0',
312
- 'X-RateLimit-Reset' => (now + (match_data[:period] - now % match_data[:period])).to_s
344
+ 'RateLimit-Limit' => match_data[:limit].to_s,
345
+ 'RateLimit-Remaining' => '0',
346
+ 'RateLimit-Reset' => (now + (match_data[:period] - now % match_data[:period])).to_s
313
347
  }
314
348
 
315
349
  [ 429, headers, ["Throttled\n"]]
@@ -327,11 +361,26 @@ request.env['rack.attack.throttle_data'][name] # => { :count => n, :period => p,
327
361
 
328
362
  Rack::Attack uses the [ActiveSupport::Notifications](http://api.rubyonrails.org/classes/ActiveSupport/Notifications.html) API if available.
329
363
 
330
- You can subscribe to 'rack.attack' events and log it, graph it, etc:
364
+ You can subscribe to `rack_attack` events and log it, graph it, etc.
365
+
366
+ To get notified about specific type of events, subscribe to the event name followed by the `rack_attack` namesapce.
367
+ E.g. for throttles use:
331
368
 
332
369
  ```ruby
333
- ActiveSupport::Notifications.subscribe('rack.attack') do |name, start, finish, request_id, req|
334
- puts req.inspect
370
+ ActiveSupport::Notifications.subscribe("throttle.rack_attack") do |name, start, finish, request_id, payload|
371
+ # request object available in payload[:request]
372
+
373
+ # Your code here
374
+ end
375
+ ```
376
+
377
+ If you want to subscribe to every `rack_attack` event, use:
378
+
379
+ ```ruby
380
+ ActiveSupport::Notifications.subscribe(/rack_attack/) do |name, start, finish, request_id, payload|
381
+ # request object available in payload[:request]
382
+
383
+ # Your code here
335
384
  end
336
385
  ```
337
386
 
@@ -344,7 +393,7 @@ The Rack::Attack middleware compares each request against *safelists*, *blocklis
344
393
  * Otherwise, if the request matches any **throttle**, a counter is incremented in the Rack::Attack.cache. If any throttle's limit is exceeded, the request is blocked.
345
394
  * Otherwise, all **tracks** are checked, and the request is allowed.
346
395
 
347
- The algorithm is actually more concise in code: See [Rack::Attack.call](https://github.com/kickstarter/rack-attack/blob/master/lib/rack/attack.rb):
396
+ The algorithm is actually more concise in code: See [Rack::Attack.call](lib/rack/attack.rb):
348
397
 
349
398
  ```ruby
350
399
  def call(env)
@@ -365,7 +414,7 @@ end
365
414
 
366
415
  Note: `Rack::Attack::Request` is just a subclass of `Rack::Request` so that you
367
416
  can cleanly monkey patch helper methods onto the
368
- [request object](https://github.com/kickstarter/rack-attack/blob/master/lib/rack/attack/request.rb).
417
+ [request object](lib/rack/attack/request.rb).
369
418
 
370
419
  ### About Tracks
371
420
 
@@ -412,13 +461,6 @@ This project is intended to be a safe, welcoming space for collaboration, and co
412
461
 
413
462
  Check out the [Development guide](docs/development.md).
414
463
 
415
- ## Mailing list
416
-
417
- New releases of Rack::Attack are announced on
418
- <rack.attack.announce@librelist.com>. To subscribe, just send an email to
419
- <rack.attack.announce@librelist.com>. See the
420
- [archives](http://librelist.com/browser/rack.attack.announce/).
421
-
422
464
  ## License
423
465
 
424
466
  Copyright Kickstarter, PBC.
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rubygems"
2
4
  require "bundler/setup"
3
5
  require 'bundler/gem_tasks'
@@ -24,4 +26,4 @@ Rake::TestTask.new(:test) do |t|
24
26
  t.pattern = "spec/**/*_spec.rb"
25
27
  end
26
28
 
27
- task :default => [:rubocop, :test]
29
+ task default: [:rubocop, :test]
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rack'
2
4
  require 'forwardable'
3
5
  require 'rack/attack/path_normalizer'
@@ -16,93 +18,79 @@ class Rack::Attack
16
18
  autoload :Track, 'rack/attack/track'
17
19
  autoload :StoreProxy, 'rack/attack/store_proxy'
18
20
  autoload :DalliProxy, 'rack/attack/store_proxy/dalli_proxy'
19
- autoload :MemCacheProxy, 'rack/attack/store_proxy/mem_cache_proxy'
20
21
  autoload :MemCacheStoreProxy, 'rack/attack/store_proxy/mem_cache_store_proxy'
21
22
  autoload :RedisProxy, 'rack/attack/store_proxy/redis_proxy'
22
23
  autoload :RedisStoreProxy, 'rack/attack/store_proxy/redis_store_proxy'
23
24
  autoload :RedisCacheStoreProxy, 'rack/attack/store_proxy/redis_cache_store_proxy'
25
+ autoload :ActiveSupportRedisStoreProxy, 'rack/attack/store_proxy/active_support_redis_store_proxy'
24
26
  autoload :Fail2Ban, 'rack/attack/fail2ban'
25
27
  autoload :Allow2Ban, 'rack/attack/allow2ban'
26
28
 
27
29
  class << self
28
- attr_accessor :notifier, :blocklisted_response, :throttled_response
30
+ attr_accessor :notifier, :blocklisted_response, :throttled_response, :anonymous_blocklists, :anonymous_safelists
29
31
 
30
- def safelist(name, &block)
31
- self.safelists[name] = Safelist.new(name, block)
32
- end
32
+ def safelist(name = nil, &block)
33
+ safelist = Safelist.new(name, &block)
33
34
 
34
- def whitelist(name, &block)
35
- warn "[DEPRECATION] 'Rack::Attack.whitelist' is deprecated. Please use 'safelist' instead."
36
- safelist(name, &block)
35
+ if name
36
+ safelists[name] = safelist
37
+ else
38
+ anonymous_safelists << safelist
39
+ end
37
40
  end
38
41
 
39
- def blocklist(name, &block)
40
- self.blocklists[name] = Blocklist.new(name, block)
42
+ def blocklist(name = nil, &block)
43
+ blocklist = Blocklist.new(name, &block)
44
+
45
+ if name
46
+ blocklists[name] = blocklist
47
+ else
48
+ anonymous_blocklists << blocklist
49
+ end
41
50
  end
42
51
 
43
52
  def blocklist_ip(ip_address)
44
- @ip_blocklists ||= []
45
- ip_blocklist_proc = lambda { |request| IPAddr.new(ip_address).include?(IPAddr.new(request.ip)) }
46
- @ip_blocklists << Blocklist.new(nil, ip_blocklist_proc)
53
+ anonymous_blocklists << Blocklist.new { |request| IPAddr.new(ip_address).include?(IPAddr.new(request.ip)) }
47
54
  end
48
55
 
49
56
  def safelist_ip(ip_address)
50
- @ip_safelists ||= []
51
- ip_safelist_proc = lambda { |request| IPAddr.new(ip_address).include?(IPAddr.new(request.ip)) }
52
- @ip_safelists << Safelist.new(nil, ip_safelist_proc)
53
- end
54
-
55
- def blacklist(name, &block)
56
- warn "[DEPRECATION] 'Rack::Attack.blacklist' is deprecated. Please use 'blocklist' instead."
57
- blocklist(name, &block)
57
+ anonymous_safelists << Safelist.new { |request| IPAddr.new(ip_address).include?(IPAddr.new(request.ip)) }
58
58
  end
59
59
 
60
60
  def throttle(name, options, &block)
61
- self.throttles[name] = Throttle.new(name, options, block)
61
+ throttles[name] = Throttle.new(name, options, &block)
62
62
  end
63
63
 
64
64
  def track(name, options = {}, &block)
65
- self.tracks[name] = Track.new(name, options, block)
65
+ tracks[name] = Track.new(name, options, &block)
66
66
  end
67
67
 
68
- def safelists; @safelists ||= {}; end
69
-
70
- def blocklists; @blocklists ||= {}; end
71
-
72
- def throttles; @throttles ||= {}; end
68
+ def safelists
69
+ @safelists ||= {}
70
+ end
73
71
 
74
- def tracks; @tracks ||= {}; end
72
+ def blocklists
73
+ @blocklists ||= {}
74
+ end
75
75
 
76
- def whitelists
77
- warn "[DEPRECATION] 'Rack::Attack.whitelists' is deprecated. Please use 'safelists' instead."
78
- safelists
76
+ def throttles
77
+ @throttles ||= {}
79
78
  end
80
79
 
81
- def blacklists
82
- warn "[DEPRECATION] 'Rack::Attack.blacklists' is deprecated. Please use 'blocklists' instead."
83
- blocklists
80
+ def tracks
81
+ @tracks ||= {}
84
82
  end
85
83
 
86
84
  def safelisted?(request)
87
- ip_safelists.any? { |safelist| safelist.matched_by?(request) } ||
85
+ anonymous_safelists.any? { |safelist| safelist.matched_by?(request) } ||
88
86
  safelists.any? { |_name, safelist| safelist.matched_by?(request) }
89
87
  end
90
88
 
91
- def whitelisted?(request)
92
- warn "[DEPRECATION] 'Rack::Attack.whitelisted?' is deprecated. Please use 'safelisted?' instead."
93
- safelisted?(request)
94
- end
95
-
96
89
  def blocklisted?(request)
97
- ip_blocklists.any? { |blocklist| blocklist.matched_by?(request) } ||
90
+ anonymous_blocklists.any? { |blocklist| blocklist.matched_by?(request) } ||
98
91
  blocklists.any? { |_name, blocklist| blocklist.matched_by?(request) }
99
92
  end
100
93
 
101
- def blacklisted?(request)
102
- warn "[DEPRECATION] 'Rack::Attack.blacklisted?' is deprecated. Please use 'blocklisted?' instead."
103
- blocklisted?(request)
104
- end
105
-
106
94
  def throttled?(request)
107
95
  throttles.any? do |_name, throttle|
108
96
  throttle.matched_by?(request)
@@ -116,7 +104,13 @@ class Rack::Attack
116
104
  end
117
105
 
118
106
  def instrument(request)
119
- notifier.instrument('rack.attack', request) if notifier
107
+ if notifier
108
+ event_type = request.env["rack.attack.match_type"]
109
+ notifier.instrument("#{event_type}.rack_attack", request: request)
110
+
111
+ # Deprecated: Keeping just for backwards compatibility
112
+ notifier.instrument("rack.attack", request: request)
113
+ end
120
114
  end
121
115
 
122
116
  def cache
@@ -125,37 +119,19 @@ class Rack::Attack
125
119
 
126
120
  def clear_configuration
127
121
  @safelists, @blocklists, @throttles, @tracks = {}, {}, {}, {}
128
- @ip_blocklists = []
129
- @ip_safelists = []
122
+ self.anonymous_blocklists = []
123
+ self.anonymous_safelists = []
130
124
  end
131
125
 
132
126
  def clear!
133
127
  warn "[DEPRECATION] Rack::Attack.clear! is deprecated. Please use Rack::Attack.clear_configuration instead"
134
128
  clear_configuration
135
129
  end
136
-
137
- def blacklisted_response=(res)
138
- warn "[DEPRECATION] 'Rack::Attack.blacklisted_response=' is deprecated. Please use 'blocklisted_response=' instead."
139
- self.blocklisted_response = res
140
- end
141
-
142
- def blacklisted_response
143
- warn "[DEPRECATION] 'Rack::Attack.blacklisted_response' is deprecated. Please use 'blocklisted_response' instead."
144
- blocklisted_response
145
- end
146
-
147
- private
148
-
149
- def ip_blocklists
150
- @ip_blocklists ||= []
151
- end
152
-
153
- def ip_safelists
154
- @ip_safelists ||= []
155
- end
156
130
  end
157
131
 
158
132
  # Set defaults
133
+ @anonymous_blocklists = []
134
+ @anonymous_safelists = []
159
135
  @notifier = ActiveSupport::Notifications if defined?(ActiveSupport::Notifications)
160
136
  @blocklisted_response = lambda { |_env| [403, { 'Content-Type' => 'text/plain' }, ["Forbidden\n"]] }
161
137
  @throttled_response = lambda { |env|
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  class Attack
3
5
  class Allow2Ban < Fail2Ban
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  class Attack
3
5
  class Blocklist < Check
4
- def initialize(name, block)
6
+ def initialize(name = nil, &block)
5
7
  super
6
8
  @type = :blocklist
7
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  class Attack
3
5
  class Cache
@@ -27,7 +29,7 @@ module Rack
27
29
  end
28
30
 
29
31
  def write(unprefixed_key, value, expires_in)
30
- store.write("#{prefix}:#{unprefixed_key}", value, :expires_in => expires_in)
32
+ store.write("#{prefix}:#{unprefixed_key}", value, expires_in: expires_in)
31
33
  end
32
34
 
33
35
  def reset_count(unprefixed_key, period)
@@ -52,13 +54,13 @@ module Rack
52
54
  enforce_store_presence!
53
55
  enforce_store_method_presence!(:increment)
54
56
 
55
- result = store.increment(key, 1, :expires_in => expires_in)
57
+ result = store.increment(key, 1, expires_in: expires_in)
56
58
 
57
59
  # NB: Some stores return nil when incrementing uninitialized values
58
60
  if result.nil?
59
61
  enforce_store_method_presence!(:write)
60
62
 
61
- store.write(key, 1, :expires_in => expires_in)
63
+ store.write(key, 1, expires_in: expires_in)
62
64
  end
63
65
  result || 1
64
66
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  class Attack
3
5
  class Check
4
6
  attr_reader :name, :block, :type
5
- def initialize(name, options = {}, block)
7
+ def initialize(name, options = {}, &block)
6
8
  @name, @block = name, block
7
9
  @type = options.fetch(:type, nil)
8
10
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  class Attack
3
5
  class Fail2Ban