rack-defense 0.1.0 → 0.1.1
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.
- checksums.yaml +4 -4
- data/README.md +13 -9
- data/lib/rack/defense.rb +5 -2
- data/lib/rack/defense/version.rb +1 -1
- data/spec/defense_config_spec.rb +32 -0
- metadata +8 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e47fe356fd72d70737af5ff0d64db8f823e1e93
|
4
|
+
data.tar.gz: 62972c5a9e0258ffccd3af644d9e191526686e2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e09969ed7c4615439aa3f4dd105b992925cf48e7da9b0549f44c3f7757cbf8e4c46cdc5380edf0a66a5d3bb7c1bb8c2505062393a6600003dce6531f8b4f2840
|
7
|
+
data.tar.gz: c7258b578750efd00ce4046c8f3f6fa6daf97a0390a80b1a10df887bc22edf91894f7c6f49b00bfeda59724288c22dfc4e8fe776041ac457425c57a96d3b36e0
|
data/README.md
CHANGED
@@ -3,8 +3,10 @@ Rack::Defense
|
|
3
3
|
|
4
4
|
A Rack middleware for throttling and filtering requests.
|
5
5
|
|
6
|
-
[](https://travis-ci.org/Sinbadsoft/rack-defense)
|
7
|
+
[](https://codeclimate.com/github/Sinbadsoft/rack-defense)
|
7
8
|
[](https://gemnasium.com/Sinbadsoft/rack-defense)
|
9
|
+
[](http://badge.fury.io/rb/rack-defense)
|
8
10
|
|
9
11
|
Rack::Defense is a Rack middleware that allows you to easily add request rate limiting and request filtering to your Rack based application (Ruby On Rails, Sinatra etc.).
|
10
12
|
|
@@ -14,6 +16,8 @@ Rack::Defense is a Rack middleware that allows you to easily add request rate li
|
|
14
16
|
|
15
17
|
Rack::Defense has a small footprint and only two dependencies: [rack](https://github.com/rack/rack) and [redis](https://github.com/redis/redis-rb).
|
16
18
|
|
19
|
+
Rack::Defense is inspired from the [Rack::Attack](https://github.com/kickstarter/rack-attack) project. The main difference is the throttling algorithm: Rack::Attack uses a counter reset at the end of each period, therefore allowing up to 2 times more requests than the maximum rate specified. We use a sliding window algorithm allowing a precise request rate limiting.
|
20
|
+
|
17
21
|
## Getting started
|
18
22
|
|
19
23
|
Install the rack-defense gem; or add it to you Gemfile with bundler:
|
@@ -43,7 +47,7 @@ end
|
|
43
47
|
```
|
44
48
|
|
45
49
|
## Throttling
|
46
|
-
The Rack::Defense middleware evaluates the throttling criterias (
|
50
|
+
The Rack::Defense middleware evaluates the throttling criterias (lambdas) against the incoming request. If the return value is falsy, the request is not throttled. Otherwise, the returned value is used as a key to throttle the request. The returned key could be the request IP, user name, API token or any discriminator to throttle the requests against.
|
47
51
|
|
48
52
|
### Examples
|
49
53
|
|
@@ -71,13 +75,13 @@ Rack::Defense uses Redis to track request rates. By default, the `REDIS_URL` env
|
|
71
75
|
The redis store can be setup with either a connection url:
|
72
76
|
```ruby
|
73
77
|
Rack::Defense.setup do |config|
|
74
|
-
store = "redis://:p4ssw0rd@10.0.1.1:6380/15"
|
78
|
+
config.store = "redis://:p4ssw0rd@10.0.1.1:6380/15"
|
75
79
|
end
|
76
80
|
```
|
77
81
|
or directly with a connection object:
|
78
82
|
```ruby
|
79
83
|
Rack::Defense.setup do |config|
|
80
|
-
store = Redis.new(host: "10.0.1.1", port: 6380, db: 15)
|
84
|
+
config.store = Redis.new(host: "10.0.1.1", port: 6380, db: 15)
|
81
85
|
end
|
82
86
|
```
|
83
87
|
|
@@ -98,7 +102,7 @@ end
|
|
98
102
|
Allow only requests with a known API authorization token:
|
99
103
|
```ruby
|
100
104
|
Rack::Defense.setup do |config|
|
101
|
-
config.ban('
|
105
|
+
config.ban('validate_api_token') do |req|
|
102
106
|
%r{^/api/} =~ req.path && Redis.current.sismember('apitokens', req.env['HTTP_AUTHORIZATION'])
|
103
107
|
end
|
104
108
|
end
|
@@ -111,19 +115,19 @@ By default, Rack::Defense returns `429 Too Many Requests` and `403 Forbidden` re
|
|
111
115
|
```ruby
|
112
116
|
Rack::Defense.setup do |config|
|
113
117
|
config.banned_response =
|
114
|
-
->(env) { [404, {'Content-Type' => 'text/plain'}, ["Not Found"]] }
|
118
|
+
->(env) { [404, {'Content-Type' => 'text/plain'}, ["Not Found\n"]] }
|
115
119
|
|
116
120
|
config.throttled_response =
|
117
|
-
->(env) { [503, {'Content-Type' => 'text/plain'}, ["Service Unavailable"]] }
|
121
|
+
->(env) { [503, {'Content-Type' => 'text/plain'}, ["Service Unavailable\n"]] }
|
118
122
|
end
|
119
123
|
end
|
120
124
|
```
|
121
125
|
|
122
126
|
## License
|
123
127
|
|
124
|
-
Copyright [Sinbadsoft](http://www.sinbadsoft.com).
|
125
|
-
|
126
128
|
Licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
127
129
|
|
130
|
+
Copyright Sinbadsoft.
|
131
|
+
|
128
132
|
|
129
133
|
|
data/lib/rack/defense.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rack'
|
2
2
|
require 'redis'
|
3
|
+
require 'delegate'
|
3
4
|
|
4
5
|
class Rack::Defense
|
5
6
|
autoload :ThrottleCounter, 'rack/defense/throttle_counter'
|
@@ -29,13 +30,15 @@ class Rack::Defense
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def store=(value)
|
32
|
-
|
33
|
+
value = Redis.new(url: value) if value.is_a?(String)
|
34
|
+
@store = SimpleDelegator::new(value) unless @store
|
35
|
+
@store.__setobj__(value)
|
33
36
|
end
|
34
37
|
|
35
38
|
def store
|
36
39
|
# Redis.new uses REDIS_URL environment variable by default as URL.
|
37
40
|
# See https://github.com/redis/redis-rb
|
38
|
-
@store ||= Redis.new
|
41
|
+
@store ||= SimpleDelegator.new(Redis.new)
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
data/lib/rack/defense/version.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Defense::Config do
|
4
|
+
before do
|
5
|
+
@config = Rack::Defense::Config.new
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'store' do
|
9
|
+
it 'creates store instance from connection string' do
|
10
|
+
url = 'redis://localhost:4444'
|
11
|
+
@config.store = url
|
12
|
+
assert url, conn_url(@config.store)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'update proxied store instance when store config changes' do
|
16
|
+
obj1, obj2 = Redis.new(url: 'redis://localhost:3333'), Redis.new(url: 'redis://localhost:4444')
|
17
|
+
|
18
|
+
@config.store = obj1
|
19
|
+
assert conn_url(obj1), conn_url(@config.store)
|
20
|
+
|
21
|
+
cached_store = @config.store
|
22
|
+
|
23
|
+
@config.store = obj2
|
24
|
+
assert conn_url(obj2), conn_url(@config.store)
|
25
|
+
assert conn_url(obj2), conn_url(cached_store)
|
26
|
+
end
|
27
|
+
|
28
|
+
def conn_url(conn)
|
29
|
+
conn.client.options[:url]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-defense
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chaker Nakhli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -16,40 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 1.5.2
|
19
|
+
version: '1.3'
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: '1.
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 1.5.2
|
26
|
+
version: '1.3'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: redis
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
31
|
- - "~>"
|
38
32
|
- !ruby/object:Gem::Version
|
39
|
-
version: '3
|
40
|
-
- - ">="
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: 3.1.0
|
33
|
+
version: '3'
|
43
34
|
type: :runtime
|
44
35
|
prerelease: false
|
45
36
|
version_requirements: !ruby/object:Gem::Requirement
|
46
37
|
requirements:
|
47
38
|
- - "~>"
|
48
39
|
- !ruby/object:Gem::Version
|
49
|
-
version: '3
|
50
|
-
- - ">="
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: 3.1.0
|
40
|
+
version: '3'
|
53
41
|
- !ruby/object:Gem::Dependency
|
54
42
|
name: rake
|
55
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,6 +107,7 @@ files:
|
|
119
107
|
- lib/rack/defense/throttle_counter.rb
|
120
108
|
- lib/rack/defense/version.rb
|
121
109
|
- spec/defense_ban_spec.rb
|
110
|
+
- spec/defense_config_spec.rb
|
122
111
|
- spec/defense_throttle_spec.rb
|
123
112
|
- spec/spec_helper.rb
|
124
113
|
- spec/throttle_counter_spec.rb
|
@@ -150,5 +139,6 @@ summary: Throttle and filter requests
|
|
150
139
|
test_files:
|
151
140
|
- spec/spec_helper.rb
|
152
141
|
- spec/throttle_counter_spec.rb
|
142
|
+
- spec/defense_config_spec.rb
|
153
143
|
- spec/defense_ban_spec.rb
|
154
144
|
- spec/defense_throttle_spec.rb
|