rack-attack 3.0.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rack-attack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +15 -4
- data/lib/rack/attack.rb +48 -39
- data/lib/rack/attack/allow2ban.rb +1 -1
- data/lib/rack/attack/blacklist.rb +1 -1
- data/lib/rack/attack/cache.rb +1 -1
- data/lib/rack/attack/check.rb +1 -1
- data/lib/rack/attack/fail2ban.rb +1 -1
- data/lib/rack/attack/request.rb +6 -0
- data/lib/rack/attack/store_proxy.rb +7 -42
- data/lib/rack/attack/store_proxy/dalli_proxy.rb +65 -0
- data/lib/rack/attack/store_proxy/redis_store_proxy.rb +42 -0
- data/lib/rack/attack/throttle.rb +1 -1
- data/lib/rack/attack/track.rb +1 -1
- data/lib/rack/attack/version.rb +2 -2
- data/lib/rack/attack/whitelist.rb +1 -1
- data/spec/integration/offline_spec.rb +47 -0
- data/spec/integration/rack_attack_cache_spec.rb +6 -31
- data/spec/rack_attack_dalli_proxy_spec.rb +10 -0
- data/spec/rack_attack_request_spec.rb +19 -0
- data/spec/spec_helper.rb +4 -0
- metadata +39 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff9b10f54b7093a546fea83332521abbd15b50fc
|
4
|
+
data.tar.gz: 766a4136c3895f45c09288e9fc97fe4a5e8e596c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5891f076087208013f1df9942977692aec45692ac6ec6fea1d143731033bebeed08d955a977ac7322aed8c9390383557214891ea61344351b1d1ec04c5f897e
|
7
|
+
data.tar.gz: d6e5098b06db042fb7e863b7d34668d4f5bff12812d7ee1d7493455ca8546606605431ebd403041442ee82f47509ad8c2365a2a2bcd130706c3a328a74dc94ed
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Rack::Attack!!!
|
2
|
-
*
|
2
|
+
*Rack middleware for blocking & throttling abusive requests*
|
3
3
|
|
4
4
|
Rack::Attack is a rack middleware to protect your web app from bad clients.
|
5
5
|
It allows *whitelisting*, *blacklisting*, *throttling*, and *tracking* based on arbitrary properties of the request.
|
@@ -13,7 +13,7 @@ See the [Backing & Hacking blog post](http://www.kickstarter.com/backing-and-hac
|
|
13
13
|
[![Code Climate](https://codeclimate.com/github/kickstarter/rack-attack.png)](https://codeclimate.com/github/kickstarter/rack-attack)
|
14
14
|
|
15
15
|
|
16
|
-
##
|
16
|
+
## Getting started
|
17
17
|
|
18
18
|
Install the [rack-attack](http://rubygems.org/gems/rack-attack) gem; or add it to you Gemfile with bundler:
|
19
19
|
|
@@ -36,6 +36,17 @@ Or for Rackup files:
|
|
36
36
|
use Rack::Attack
|
37
37
|
```
|
38
38
|
|
39
|
+
Add a `rack-attack.rb` file to `config/initalizers/`:
|
40
|
+
```ruby
|
41
|
+
# In config/initializers/rack-attack.rb
|
42
|
+
module Rack::Attack
|
43
|
+
# your custom configuration...
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
47
|
+
*Tip:* The example in the wiki is a great way to get started:
|
48
|
+
[Example Configuration](https://github.com/kickstarter/rack-attack/wiki/Example-Configuration)
|
49
|
+
|
39
50
|
Optionally configure the cache store for throttling:
|
40
51
|
|
41
52
|
```ruby
|
@@ -271,6 +282,6 @@ New releases of Rack::Attack are announced on
|
|
271
282
|
|
272
283
|
## License
|
273
284
|
|
274
|
-
Copyright
|
285
|
+
Copyright Kickstarter, Inc.
|
275
286
|
|
276
|
-
Released under an [MIT License](http://opensource.org/licenses/MIT)
|
287
|
+
Released under an [MIT License](http://opensource.org/licenses/MIT).
|
data/lib/rack/attack.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
require 'rack'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
autoload :
|
6
|
-
autoload :
|
7
|
-
autoload :
|
8
|
-
autoload :
|
9
|
-
autoload :
|
10
|
-
autoload :
|
11
|
-
autoload :
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
class Rack::Attack
|
5
|
+
autoload :Cache, 'rack/attack/cache'
|
6
|
+
autoload :Check, 'rack/attack/check'
|
7
|
+
autoload :Throttle, 'rack/attack/throttle'
|
8
|
+
autoload :Whitelist, 'rack/attack/whitelist'
|
9
|
+
autoload :Blacklist, 'rack/attack/blacklist'
|
10
|
+
autoload :Track, 'rack/attack/track'
|
11
|
+
autoload :StoreProxy, 'rack/attack/store_proxy'
|
12
|
+
autoload :DalliProxy, 'rack/attack/store_proxy/dalli_proxy'
|
13
|
+
autoload :RedisStoreProxy, 'rack/attack/store_proxy/redis_store_proxy'
|
14
|
+
autoload :Fail2Ban, 'rack/attack/fail2ban'
|
15
|
+
autoload :Allow2Ban, 'rack/attack/allow2ban'
|
16
|
+
autoload :Request, 'rack/attack/request'
|
12
17
|
|
13
18
|
class << self
|
14
19
|
|
@@ -35,35 +40,6 @@ module Rack::Attack
|
|
35
40
|
def throttles; @throttles ||= {}; end
|
36
41
|
def tracks; @tracks ||= {}; end
|
37
42
|
|
38
|
-
def new(app)
|
39
|
-
@app = app
|
40
|
-
|
41
|
-
# Set defaults
|
42
|
-
@notifier ||= ActiveSupport::Notifications if defined?(ActiveSupport::Notifications)
|
43
|
-
@blacklisted_response ||= lambda {|env| [403, {}, ["Forbidden\n"]] }
|
44
|
-
@throttled_response ||= lambda {|env|
|
45
|
-
retry_after = env['rack.attack.match_data'][:period] rescue nil
|
46
|
-
[429, {'Retry-After' => retry_after.to_s}, ["Retry later\n"]]
|
47
|
-
}
|
48
|
-
|
49
|
-
self
|
50
|
-
end
|
51
|
-
|
52
|
-
def call(env)
|
53
|
-
req = Rack::Request.new(env)
|
54
|
-
|
55
|
-
if whitelisted?(req)
|
56
|
-
@app.call(env)
|
57
|
-
elsif blacklisted?(req)
|
58
|
-
blacklisted_response[env]
|
59
|
-
elsif throttled?(req)
|
60
|
-
throttled_response[env]
|
61
|
-
else
|
62
|
-
tracked?(req)
|
63
|
-
@app.call(env)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
43
|
def whitelisted?(req)
|
68
44
|
whitelists.any? do |name, whitelist|
|
69
45
|
whitelist[req]
|
@@ -101,4 +77,37 @@ module Rack::Attack
|
|
101
77
|
end
|
102
78
|
|
103
79
|
end
|
80
|
+
|
81
|
+
# Set defaults
|
82
|
+
@notifier = ActiveSupport::Notifications if defined?(ActiveSupport::Notifications)
|
83
|
+
@blacklisted_response = lambda {|env| [403, {}, ["Forbidden\n"]] }
|
84
|
+
@throttled_response = lambda {|env|
|
85
|
+
retry_after = env['rack.attack.match_data'][:period] rescue nil
|
86
|
+
[429, {'Retry-After' => retry_after.to_s}, ["Retry later\n"]]
|
87
|
+
}
|
88
|
+
|
89
|
+
def initialize(app)
|
90
|
+
@app = app
|
91
|
+
end
|
92
|
+
|
93
|
+
def call(env)
|
94
|
+
req = Rack::Attack::Request.new(env)
|
95
|
+
|
96
|
+
if whitelisted?(req)
|
97
|
+
@app.call(env)
|
98
|
+
elsif blacklisted?(req)
|
99
|
+
self.class.blacklisted_response[env]
|
100
|
+
elsif throttled?(req)
|
101
|
+
self.class.throttled_response[env]
|
102
|
+
else
|
103
|
+
tracked?(req)
|
104
|
+
@app.call(env)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
extend Forwardable
|
109
|
+
def_delegators self, :whitelisted?,
|
110
|
+
:blacklisted?,
|
111
|
+
:throttled?,
|
112
|
+
:tracked?
|
104
113
|
end
|
data/lib/rack/attack/cache.rb
CHANGED
data/lib/rack/attack/check.rb
CHANGED
data/lib/rack/attack/fail2ban.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'delegate'
|
2
|
-
|
3
1
|
module Rack
|
4
|
-
|
5
|
-
|
2
|
+
class Attack
|
3
|
+
module StoreProxy
|
4
|
+
PROXIES = [DalliProxy, RedisStoreProxy]
|
5
|
+
|
6
6
|
def self.build(store)
|
7
7
|
# RedisStore#increment needs different behavior, so detect that
|
8
8
|
# (method has an arity of 2; must call #expire separately
|
@@ -12,46 +12,11 @@ module Rack
|
|
12
12
|
store = store.instance_variable_get(:@data)
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
RedisStoreProxy.new(store)
|
17
|
-
else
|
18
|
-
store
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class RedisStoreProxy < SimpleDelegator
|
23
|
-
def initialize(store)
|
24
|
-
super(store)
|
25
|
-
end
|
26
|
-
|
27
|
-
def read(key)
|
28
|
-
self.get(key)
|
29
|
-
rescue Redis::BaseError
|
30
|
-
nil
|
31
|
-
end
|
32
|
-
|
33
|
-
def write(key, value, options={})
|
34
|
-
if (expires_in = options[:expires_in])
|
35
|
-
self.setex(key, expires_in, value)
|
36
|
-
else
|
37
|
-
self.set(key, value)
|
38
|
-
end
|
39
|
-
rescue Redis::BaseError
|
40
|
-
nil
|
41
|
-
end
|
42
|
-
|
43
|
-
def increment(key, amount, options={})
|
44
|
-
count = nil
|
45
|
-
self.pipelined do
|
46
|
-
count = self.incrby(key, amount)
|
47
|
-
self.expire(key, options[:expires_in]) if options[:expires_in]
|
48
|
-
end
|
49
|
-
count.value if count
|
50
|
-
rescue Redis::BaseError
|
51
|
-
nil
|
52
|
-
end
|
15
|
+
klass = PROXIES.find { |proxy| proxy.handle?(store) }
|
53
16
|
|
17
|
+
klass ? klass.new(store) : store
|
54
18
|
end
|
19
|
+
|
55
20
|
end
|
56
21
|
end
|
57
22
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Attack
|
5
|
+
module StoreProxy
|
6
|
+
class DalliProxy < SimpleDelegator
|
7
|
+
def self.handle?(store)
|
8
|
+
return false unless defined?(::Dalli)
|
9
|
+
|
10
|
+
# Consider extracting to a separate Connection Pool proxy to reduce
|
11
|
+
# code here and handle clients other than Dalli.
|
12
|
+
if defined?(::ConnectionPool) && store.is_a?(::ConnectionPool)
|
13
|
+
store.with { |conn| conn.is_a?(::Dalli::Client) }
|
14
|
+
else
|
15
|
+
store.is_a?(::Dalli::Client)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(client)
|
20
|
+
super(client)
|
21
|
+
stub_with_if_missing
|
22
|
+
end
|
23
|
+
|
24
|
+
def read(key)
|
25
|
+
with do |client|
|
26
|
+
client.get(key)
|
27
|
+
end
|
28
|
+
rescue Dalli::DalliError
|
29
|
+
end
|
30
|
+
|
31
|
+
def write(key, value, options={})
|
32
|
+
with do |client|
|
33
|
+
client.set(key, value, options.fetch(:expires_in, 0), raw: true)
|
34
|
+
end
|
35
|
+
rescue Dalli::DalliError
|
36
|
+
end
|
37
|
+
|
38
|
+
def increment(key, amount, options={})
|
39
|
+
with do |client|
|
40
|
+
client.incr(key, amount, options.fetch(:expires_in, 0), amount)
|
41
|
+
end
|
42
|
+
rescue Dalli::DalliError
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete(key)
|
46
|
+
with do |client|
|
47
|
+
client.delete(key)
|
48
|
+
end
|
49
|
+
rescue Dalli::DalliError
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def stub_with_if_missing
|
55
|
+
unless __getobj__.respond_to?(:with)
|
56
|
+
class << self
|
57
|
+
def with; yield __getobj__; end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Attack
|
5
|
+
module StoreProxy
|
6
|
+
class RedisStoreProxy < SimpleDelegator
|
7
|
+
def self.handle?(store)
|
8
|
+
defined?(::Redis::Store) && store.is_a?(::Redis::Store)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(store)
|
12
|
+
super(store)
|
13
|
+
end
|
14
|
+
|
15
|
+
def read(key)
|
16
|
+
self.get(key)
|
17
|
+
rescue Redis::BaseError
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(key, value, options={})
|
21
|
+
if (expires_in = options[:expires_in])
|
22
|
+
self.setex(key, expires_in, value)
|
23
|
+
else
|
24
|
+
self.set(key, value)
|
25
|
+
end
|
26
|
+
rescue Redis::BaseError
|
27
|
+
end
|
28
|
+
|
29
|
+
def increment(key, amount, options={})
|
30
|
+
count = nil
|
31
|
+
self.pipelined do
|
32
|
+
count = self.incrby(key, amount)
|
33
|
+
self.expire(key, options[:expires_in]) if options[:expires_in]
|
34
|
+
end
|
35
|
+
count.value if count
|
36
|
+
rescue Redis::BaseError
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/rack/attack/throttle.rb
CHANGED
data/lib/rack/attack/track.rb
CHANGED
data/lib/rack/attack/version.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'active_support/cache'
|
2
|
+
require 'active_support/cache/redis_store'
|
3
|
+
require 'dalli'
|
4
|
+
require_relative '../spec_helper'
|
5
|
+
|
6
|
+
OfflineExamples = Minitest::SharedExamples.new do
|
7
|
+
|
8
|
+
it 'should write' do
|
9
|
+
@cache.write('cache-test-key', 'foobar', 1)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should read' do
|
13
|
+
@cache.read('cache-test-key')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should count' do
|
17
|
+
@cache.send(:do_count, 'rack::attack::cache-test-key', 1)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
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
|
+
}
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'when Memcached is offline' do
|
34
|
+
include OfflineExamples
|
35
|
+
|
36
|
+
before {
|
37
|
+
Dalli.logger.level = Logger::FATAL
|
38
|
+
|
39
|
+
@cache = Rack::Attack::Cache.new
|
40
|
+
@cache.store = Dalli::Client.new('127.0.0.1:22122')
|
41
|
+
}
|
42
|
+
|
43
|
+
after {
|
44
|
+
Dalli.logger.level = Logger::INFO
|
45
|
+
}
|
46
|
+
|
47
|
+
end
|
@@ -15,10 +15,13 @@ describe Rack::Attack::Cache do
|
|
15
15
|
|
16
16
|
require 'active_support/cache/dalli_store'
|
17
17
|
require 'active_support/cache/redis_store'
|
18
|
+
require 'connection_pool'
|
18
19
|
cache_stores = [
|
19
20
|
ActiveSupport::Cache::MemoryStore.new,
|
20
|
-
ActiveSupport::Cache::DalliStore.new("
|
21
|
-
ActiveSupport::Cache::RedisStore.new("
|
21
|
+
ActiveSupport::Cache::DalliStore.new("127.0.0.1"),
|
22
|
+
ActiveSupport::Cache::RedisStore.new("127.0.0.1"),
|
23
|
+
Dalli::Client.new,
|
24
|
+
ConnectionPool.new { Dalli::Client.new },
|
22
25
|
Redis::Store.new
|
23
26
|
]
|
24
27
|
|
@@ -27,7 +30,7 @@ describe Rack::Attack::Cache do
|
|
27
30
|
describe "with #{store.class}" do
|
28
31
|
|
29
32
|
before {
|
30
|
-
@cache
|
33
|
+
@cache = Rack::Attack::Cache.new
|
31
34
|
@key = "rack::attack:cache-test-key"
|
32
35
|
@expires_in = 1
|
33
36
|
@cache.store = store
|
@@ -80,32 +83,4 @@ describe Rack::Attack::Cache do
|
|
80
83
|
end
|
81
84
|
|
82
85
|
end
|
83
|
-
|
84
|
-
describe "should not error if redis is not running" do
|
85
|
-
before {
|
86
|
-
@cache = Rack::Attack::Cache.new
|
87
|
-
@key = "rack::attack:cache-test-key"
|
88
|
-
@expires_in = 1
|
89
|
-
# Use presumably unused port for Redis client
|
90
|
-
@cache.store = ActiveSupport::Cache::RedisStore.new(:host => '127.0.0.1', :port => 3333)
|
91
|
-
}
|
92
|
-
describe "write" do
|
93
|
-
it "should not raise exception" do
|
94
|
-
@cache.write("cache-test-key", "foobar", 1)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
describe "read" do
|
99
|
-
it "should not raise exception" do
|
100
|
-
@cache.read("cache-test-key")
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
describe "do_count" do
|
105
|
-
it "should not raise exception" do
|
106
|
-
@cache.send(:do_count, @key, @expires_in)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
86
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Attack::StoreProxy::DalliProxy do
|
4
|
+
|
5
|
+
it 'should stub Dalli::Client#with on older clients' do
|
6
|
+
proxy = Rack::Attack::StoreProxy::DalliProxy.new(Class.new)
|
7
|
+
proxy.with {} # will not raise an error
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Rack::Attack' do
|
4
|
+
describe 'helpers' do
|
5
|
+
before do
|
6
|
+
class Rack::Attack::Request
|
7
|
+
def remote_ip
|
8
|
+
ip
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Rack::Attack.whitelist('valid IP') do |req|
|
13
|
+
req.remote_ip == "127.0.0.1"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
allow_ok_requests
|
18
|
+
end
|
19
|
+
end
|
data/spec/spec_helper.rb
CHANGED
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
|
+
version: 4.0.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-
|
11
|
+
date: 2014-04-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: appraisal
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: activesupport
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,20 @@ dependencies:
|
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: connection_pool
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
111
139
|
description: A rack middleware for throttling and blocking abusive requests
|
112
140
|
email: aaron@ktheory.com
|
113
141
|
executables: []
|
@@ -122,14 +150,20 @@ files:
|
|
122
150
|
- lib/rack/attack/cache.rb
|
123
151
|
- lib/rack/attack/check.rb
|
124
152
|
- lib/rack/attack/fail2ban.rb
|
153
|
+
- lib/rack/attack/request.rb
|
125
154
|
- lib/rack/attack/store_proxy.rb
|
155
|
+
- lib/rack/attack/store_proxy/dalli_proxy.rb
|
156
|
+
- lib/rack/attack/store_proxy/redis_store_proxy.rb
|
126
157
|
- lib/rack/attack/throttle.rb
|
127
158
|
- lib/rack/attack/track.rb
|
128
159
|
- lib/rack/attack/version.rb
|
129
160
|
- lib/rack/attack/whitelist.rb
|
130
161
|
- spec/allow2ban_spec.rb
|
131
162
|
- spec/fail2ban_spec.rb
|
163
|
+
- spec/integration/offline_spec.rb
|
132
164
|
- spec/integration/rack_attack_cache_spec.rb
|
165
|
+
- spec/rack_attack_dalli_proxy_spec.rb
|
166
|
+
- spec/rack_attack_request_spec.rb
|
133
167
|
- spec/rack_attack_spec.rb
|
134
168
|
- spec/rack_attack_throttle_spec.rb
|
135
169
|
- spec/rack_attack_track_spec.rb
|
@@ -162,7 +196,10 @@ summary: Block & throttle abusive requests
|
|
162
196
|
test_files:
|
163
197
|
- spec/allow2ban_spec.rb
|
164
198
|
- spec/fail2ban_spec.rb
|
199
|
+
- spec/integration/offline_spec.rb
|
165
200
|
- spec/integration/rack_attack_cache_spec.rb
|
201
|
+
- spec/rack_attack_dalli_proxy_spec.rb
|
202
|
+
- spec/rack_attack_request_spec.rb
|
166
203
|
- spec/rack_attack_spec.rb
|
167
204
|
- spec/rack_attack_throttle_spec.rb
|
168
205
|
- spec/rack_attack_track_spec.rb
|