rack-attack 4.2.0 → 4.3.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.

Potentially problematic release.


This version of rack-attack might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e99e6a7757d11626b6b7d078abe43e9fe123cc36
4
- data.tar.gz: 77b5a17a9de1acd9692805e2e634d165d66f1506
3
+ metadata.gz: da0016c3e3d7fee696a96f8f1e3a493b0b197518
4
+ data.tar.gz: 6b337c7d2ed9c48dbfd4cfc031ab6157fbceda3d
5
5
  SHA512:
6
- metadata.gz: 75e2f1b7c760cc33323618edf03dd6fb3f661b73d2ed2d2ce67e80f632942c369d4e4336c479ae68e99805c2c2910a51b54dc4fab545b54d295536c28811ca20
7
- data.tar.gz: 5da774caa95cfe83eaeb1c42d759ac0761fc76c5c6137681101f658680b3bba9edde35862f9a84cd0a1f530ae294142663a619c3940fedc761345b0be5cd3542
6
+ metadata.gz: 1f84ef0262ee5f64ed98d745bedf49f7e8ef38693a3bc8e0eddb643dc7165e881ee11642944cf75d52769e13f6da934be69bf3156c6945e938caa139bf886252
7
+ data.tar.gz: b952d3bd6061eaf8c7b5172c0b6620d4e3797d383c7a00d9d6d80eef78d470ba3ce8dbb1c57f801f3685164f7076a587236fc5bc3550b433c3771bddbfe589ef
data/README.md CHANGED
@@ -15,7 +15,7 @@ See the [Backing & Hacking blog post](http://www.kickstarter.com/backing-and-hac
15
15
 
16
16
  ## Getting started
17
17
 
18
- Install the [rack-attack](http://rubygems.org/gems/rack-attack) gem; or add it to you Gemfile with bundler:
18
+ Install the [rack-attack](http://rubygems.org/gems/rack-attack) gem; or add it to your Gemfile with bundler:
19
19
 
20
20
  ```ruby
21
21
  # In your Gemfile
@@ -36,7 +36,7 @@ Or for Rackup files:
36
36
  use Rack::Attack
37
37
  ```
38
38
 
39
- Add a `rack-attack.rb` file to `config/initalizers/`:
39
+ Add a `rack-attack.rb` file to `config/initializers/`:
40
40
  ```ruby
41
41
  # In config/initializers/rack-attack.rb
42
42
  class Rack::Attack
@@ -95,7 +95,7 @@ can cleanly monkey patch helper methods onto the
95
95
 
96
96
  Define whitelists, blacklists, throttles, and tracks as blocks that return truthy values if matched, falsy otherwise. In a Rails app
97
97
  these go in an initializer in `config/initializers/`.
98
- A [Rack::Request](http://rack.rubyforge.org/doc/classes/Rack/Request.html) object is passed to the block (named 'req' in the examples).
98
+ A [Rack::Request](http://www.rubydoc.info/gems/rack/Rack/Request) object is passed to the block (named 'req' in the examples).
99
99
 
100
100
  ### Whitelists
101
101
 
@@ -199,7 +199,7 @@ Rack::Attack.track("special_agent") do |req|
199
199
  end
200
200
 
201
201
  # Supports optional limit and period, triggers the notification only when the limit is reached.
202
- Rack::Attack.track("special_agent", :limit 6, :period => 60.seconds) do |req|
202
+ Rack::Attack.track("special_agent", :limit => 6, :period => 60.seconds) do |req|
203
203
  req.user_agent == "SpecialAgent"
204
204
  end
205
205
 
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require "rubygems"
2
2
  require "bundler/setup"
3
+ require 'bundler/gem_tasks'
3
4
  require 'rake/testtask'
4
5
 
5
6
  namespace :test do
@@ -15,10 +15,7 @@ module Rack
15
15
  end
16
16
 
17
17
  def count(unprefixed_key, period)
18
- epoch_time = Time.now.to_i
19
- # Add 1 to expires_in to avoid timing error: http://git.io/i1PHXA
20
- expires_in = period - (epoch_time % period) + 1
21
- key = "#{prefix}:#{(epoch_time/period).to_i}:#{unprefixed_key}"
18
+ key, expires_in = key_and_expiry(unprefixed_key, period)
22
19
  do_count(key, expires_in)
23
20
  end
24
21
 
@@ -30,7 +27,24 @@ module Rack
30
27
  store.write("#{prefix}:#{unprefixed_key}", value, :expires_in => expires_in)
31
28
  end
32
29
 
30
+ def reset_count(unprefixed_key, period)
31
+ key, _ = key_and_expiry(unprefixed_key, period)
32
+ store.delete(key)
33
+ end
34
+
35
+ def delete(unprefixed_key)
36
+ store.delete("#{prefix}:#{unprefixed_key}")
37
+ end
38
+
33
39
  private
40
+
41
+ def key_and_expiry(unprefixed_key, period)
42
+ epoch_time = Time.now.to_i
43
+ # Add 1 to expires_in to avoid timing error: http://git.io/i1PHXA
44
+ expires_in = (period - (epoch_time % period) + 1).to_i
45
+ ["#{prefix}:#{(epoch_time / period).to_i}:#{unprefixed_key}", expires_in]
46
+ end
47
+
34
48
  def do_count(key, expires_in)
35
49
  result = store.increment(key, 1, :expires_in => expires_in)
36
50
 
@@ -15,6 +15,17 @@ module Rack
15
15
  end
16
16
  end
17
17
 
18
+ def reset(discriminator, options)
19
+ findtime = options[:findtime] or raise ArgumentError, "Must pass findtime option"
20
+ cache.reset_count("#{key_prefix}:count:#{discriminator}", findtime)
21
+ # Clear ban flag just in case it's there
22
+ cache.delete("#{key_prefix}:ban:#{discriminator}")
23
+ end
24
+
25
+ def banned?(discriminator)
26
+ cache.read("#{key_prefix}:ban:#{discriminator}") ? true : false
27
+ end
28
+
18
29
  protected
19
30
  def key_prefix
20
31
  'fail2ban'
@@ -35,10 +46,6 @@ module Rack
35
46
  cache.write("#{key_prefix}:ban:#{discriminator}", 1, bantime)
36
47
  end
37
48
 
38
- def banned?(discriminator)
39
- cache.read("#{key_prefix}:ban:#{discriminator}")
40
- end
41
-
42
49
  def cache
43
50
  Rack::Attack.cache
44
51
  end
@@ -13,15 +13,15 @@ module Rack
13
13
  end
14
14
 
15
15
  def read(key)
16
- self.get(key)
16
+ self.get(key, raw: true)
17
17
  rescue Redis::BaseError
18
18
  end
19
19
 
20
20
  def write(key, value, options={})
21
21
  if (expires_in = options[:expires_in])
22
- self.setex(key, expires_in, value)
22
+ self.setex(key, expires_in, value, raw: true)
23
23
  else
24
- self.set(key, value)
24
+ self.set(key, value, raw: true)
25
25
  end
26
26
  rescue Redis::BaseError
27
27
  end
@@ -36,6 +36,10 @@ module Rack
36
36
  rescue Redis::BaseError
37
37
  end
38
38
 
39
+ def delete(key, options={})
40
+ self.del(key)
41
+ rescue Redis::BaseError
42
+ end
39
43
  end
40
44
  end
41
45
  end
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class Attack
3
- VERSION = '4.2.0'
3
+ VERSION = '4.3.0'
4
4
  end
5
5
  end
@@ -58,7 +58,27 @@ describe 'Rack::Attack.Fail2Ban' do
58
58
  key = "rack::attack:fail2ban:ban:1.2.3.4"
59
59
  @cache.store.read(key).must_equal 1
60
60
  end
61
+ end
62
+
63
+ describe 'reset after success' do
64
+ before do
65
+ get '/?test=OMGHAX', {}, 'REMOTE_ADDR' => '1.2.3.4'
66
+ Rack::Attack::Fail2Ban.reset('1.2.3.4', @f2b_options)
67
+ get '/', {}, 'REMOTE_ADDR' => '1.2.3.4'
68
+ end
61
69
 
70
+ it 'succeeds' do
71
+ last_response.status.must_equal 200
72
+ end
73
+
74
+ 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
77
+ end
78
+
79
+ it 'IP is not banned' do
80
+ Rack::Attack::Fail2Ban.banned?('1.2.3.4').must_equal false
81
+ end
62
82
  end
63
83
  end
64
84
  end
@@ -1,6 +1,9 @@
1
1
  require_relative '../spec_helper'
2
2
 
3
3
  describe Rack::Attack::Cache do
4
+
5
+ # A convenience method for deleting a key from cache.
6
+ # Slightly differnet than @cache.delete, which adds a prefix.
4
7
  def delete(key)
5
8
  if @cache.store.respond_to?(:delete)
6
9
  @cache.store.delete(key)
@@ -80,6 +83,36 @@ describe Rack::Attack::Cache do
80
83
  @cache.read("cache-test-key").must_equal "foobar"
81
84
  end
82
85
  end
86
+
87
+ describe "delete" do
88
+ it "must delete the value" do
89
+ store.write(@key, "foobar", :expires_in => @expires_in)
90
+ @cache.read('cache-test-key').must_equal "foobar"
91
+ store.delete(@key)
92
+ @cache.read('cache-test-key').must_equal nil
93
+ end
94
+ end
95
+
96
+ describe "cache#delete" do
97
+ it "must delete the value" do
98
+ @cache.write("cache-test-key", "foobar", 1)
99
+ store.read(@key).must_equal "foobar"
100
+ @cache.delete('cache-test-key')
101
+ store.read(@key).must_be :nil?
102
+ end
103
+ end
104
+
105
+ describe "reset_count" do
106
+ it "must delete the value" do
107
+ period = 1.minute
108
+ unprefixed_key = 'cache-test-key'
109
+ @cache.count(unprefixed_key, period)
110
+ period_key, _ = @cache.send(:key_and_expiry, 'cache-test-key', period)
111
+ store.read(period_key).to_i.must_equal 1
112
+ @cache.reset_count(unprefixed_key, period)
113
+ store.read(period_key).must_equal nil
114
+ end
115
+ end
83
116
  end
84
117
 
85
118
  end
@@ -9,7 +9,9 @@ describe 'Rack::Attack' do
9
9
  Rack::Attack.blacklist("ip #{@bad_ip}") {|req| req.ip == @bad_ip }
10
10
  end
11
11
 
12
- it('has a blacklist') { Rack::Attack.blacklists.key?("ip #{@bad_ip}") }
12
+ it('has a blacklist') {
13
+ Rack::Attack.blacklists.key?("ip #{@bad_ip}").must_equal true
14
+ }
13
15
 
14
16
  describe "a bad request" do
15
17
  before { get '/', {}, 'REMOTE_ADDR' => @bad_ip }
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: 4.2.0
4
+ version: 4.3.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: 2014-10-26 00:00:00.000000000 Z
11
+ date: 2015-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -189,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
189
189
  version: '0'
190
190
  requirements: []
191
191
  rubyforge_project:
192
- rubygems_version: 2.2.2
192
+ rubygems_version: 2.4.5
193
193
  signing_key:
194
194
  specification_version: 4
195
195
  summary: Block & throttle abusive requests
@@ -204,4 +204,3 @@ test_files:
204
204
  - spec/rack_attack_throttle_spec.rb
205
205
  - spec/rack_attack_track_spec.rb
206
206
  - spec/spec_helper.rb
207
- has_rdoc: