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 +4 -4
- data/README.md +4 -4
- data/Rakefile +1 -0
- data/lib/rack/attack/cache.rb +18 -4
- data/lib/rack/attack/fail2ban.rb +11 -4
- data/lib/rack/attack/store_proxy/redis_store_proxy.rb +7 -3
- data/lib/rack/attack/version.rb +1 -1
- data/spec/fail2ban_spec.rb +20 -0
- data/spec/integration/rack_attack_cache_spec.rb +33 -0
- data/spec/rack_attack_spec.rb +3 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da0016c3e3d7fee696a96f8f1e3a493b0b197518
|
4
|
+
data.tar.gz: 6b337c7d2ed9c48dbfd4cfc031ab6157fbceda3d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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/
|
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://
|
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
data/lib/rack/attack/cache.rb
CHANGED
@@ -15,10 +15,7 @@ module Rack
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def count(unprefixed_key, period)
|
18
|
-
|
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
|
|
data/lib/rack/attack/fail2ban.rb
CHANGED
@@ -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
|
data/lib/rack/attack/version.rb
CHANGED
data/spec/fail2ban_spec.rb
CHANGED
@@ -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
|
data/spec/rack_attack_spec.rb
CHANGED
@@ -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') {
|
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.
|
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:
|
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.
|
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:
|