rack-policy 0.1.0 → 0.2.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.
- data/CHANGELOG.md +14 -0
- data/Gemfile +0 -1
- data/README.md +28 -8
- data/examples/rails_3/Gemfile +8 -0
- data/examples/rails_3/rails_3.ru +51 -0
- data/lib/rack/policy/cookie_limiter.rb +42 -10
- data/lib/rack/policy/version.rb +1 -1
- data/spec/cookie_limiter_spec.rb +32 -6
- metadata +13 -10
data/CHANGELOG.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
0.2.0 (June 24, 2012)
|
2
|
+
|
3
|
+
* Fix bug when checking allowed cookie.
|
4
|
+
* Refactor cookie clearing to work off request and response cycle.
|
5
|
+
* Add cookie deletion.
|
6
|
+
* Add response headers handling and fix bug with cache revalidation.
|
7
|
+
* Add code comments.
|
8
|
+
* Improve documentation with sinatra and rackup examples.
|
9
|
+
* Add code example for rails 3 app.
|
10
|
+
|
11
|
+
0.1.0 (June 23, 2012)
|
12
|
+
|
13
|
+
* Add cookie limiter middleware.
|
14
|
+
* Add spec tests.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -30,8 +30,12 @@ By default when the Rack application is loaded no cookies will be set(provided n
|
|
30
30
|
Rack::Policy::CookieLimiter consent_token: 'allow_me'
|
31
31
|
```
|
32
32
|
|
33
|
+
The very same `consent_token` is used to toggle the limiter behaviour.
|
34
|
+
|
33
35
|
## Examples
|
34
36
|
|
37
|
+
Adding `Rack::Policy::CookieLimiter` do Rack applications
|
38
|
+
|
35
39
|
### Rails 3.x
|
36
40
|
|
37
41
|
```ruby
|
@@ -47,18 +51,18 @@ And then in your custome controller create actions responsible for setting and u
|
|
47
51
|
|
48
52
|
```ruby
|
49
53
|
class CookiePolicyController < ApplicationController
|
54
|
+
|
50
55
|
def allow
|
51
|
-
|
56
|
+
response.set_cookie 'rack.policy', {
|
52
57
|
value: 'true',
|
53
58
|
expires: 1.year.from_now.utc
|
54
59
|
}
|
60
|
+
render nothing: true
|
55
61
|
end
|
56
62
|
|
57
63
|
def deny
|
58
|
-
|
59
|
-
|
60
|
-
expires: Time.at(0)
|
61
|
-
}
|
64
|
+
response.delete_cookie 'rack.policy'
|
65
|
+
render nothing: true
|
62
66
|
end
|
63
67
|
end
|
64
68
|
```
|
@@ -69,7 +73,7 @@ end
|
|
69
73
|
# config/environment
|
70
74
|
|
71
75
|
Rails::Initializer.run do |config|
|
72
|
-
config.middleware.use Rack::Policy::
|
76
|
+
config.middleware.use Rack::Policy::CookieLimiter consent_token: 'rack.policy'
|
73
77
|
end
|
74
78
|
```
|
75
79
|
|
@@ -77,19 +81,35 @@ Set and unset cookie consent in similar way to Rails 3.x example.
|
|
77
81
|
|
78
82
|
### Sinatra
|
79
83
|
|
84
|
+
For classic style sinatra application do
|
85
|
+
|
80
86
|
```ruby
|
87
|
+
#!/usr/bin/env ruby -rubygems
|
81
88
|
require 'sinatra'
|
82
89
|
require 'rack/policy'
|
83
90
|
|
84
91
|
use Rack::Policy::CookieLimiter consent_token: 'rack.policy'
|
85
92
|
|
86
|
-
get('/
|
93
|
+
get('/') { "Allow cookies to be set? <a href='/allow'>Allow</a>" }
|
87
94
|
|
88
|
-
get('/allow') { }
|
95
|
+
get('/allow') { response.set_cookie 'rack.policy' }
|
96
|
+
|
97
|
+
get('/deny') { response.delete_cookie 'rack.policy' }
|
89
98
|
```
|
90
99
|
|
100
|
+
### Padrino app
|
101
|
+
|
91
102
|
### Rackup app
|
92
103
|
|
104
|
+
```ruby
|
105
|
+
#!/usr/bin/env rackup
|
106
|
+
require 'rack/policy'
|
107
|
+
|
108
|
+
use Rack::Policy::CookieLimiter consent_token: 'rack.policy'
|
109
|
+
|
110
|
+
run lambda { |env| [200, {'Content-Type' => 'text/plain'}, "Hello, world!\n"] }
|
111
|
+
```
|
112
|
+
|
93
113
|
## Contributing
|
94
114
|
|
95
115
|
1. Fork it
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# RAILS_ENV=production bundle exec rackup -p 3000 -s thin
|
2
|
+
|
3
|
+
require 'rails'
|
4
|
+
require 'rails/all'
|
5
|
+
require 'rack/policy'
|
6
|
+
|
7
|
+
class MyApp < Rails::Application
|
8
|
+
routes.append do
|
9
|
+
match '/hello' => 'policy#hello'
|
10
|
+
match '/allow' => 'policy#allow'
|
11
|
+
match '/deny' => 'policy#deny'
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'rack/policy'
|
15
|
+
|
16
|
+
config.middleware.use Rack::Policy::CookieLimiter
|
17
|
+
end
|
18
|
+
|
19
|
+
class PolicyController < ActionController::Base
|
20
|
+
|
21
|
+
def hello
|
22
|
+
response.set_cookie :custom_cookie, {
|
23
|
+
:value => 'illegal cookie',
|
24
|
+
:expires => 2.hours.from_now.utc
|
25
|
+
}
|
26
|
+
render :text => "Cookies #{cookies.inspect}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def allow
|
30
|
+
response.set_cookie :cookie_limiter, {
|
31
|
+
:value => 'true',
|
32
|
+
:expires => 2.hours.from_now.utc
|
33
|
+
}
|
34
|
+
render :text => "Cookies #{cookies.inspect}"
|
35
|
+
end
|
36
|
+
|
37
|
+
def deny
|
38
|
+
response.delete_cookie :cookie_limiter
|
39
|
+
render :text => "Cookies #{cookies.inspect}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
MyApp.initialize!
|
44
|
+
|
45
|
+
# Print middleware stack
|
46
|
+
Rails.configuration.middleware.each do |middleware|
|
47
|
+
puts "use #{middleware.inspect}"
|
48
|
+
end
|
49
|
+
puts "run #{Rails.application.class.name}.routes"
|
50
|
+
|
51
|
+
run MyApp
|
@@ -2,17 +2,20 @@
|
|
2
2
|
|
3
3
|
module Rack
|
4
4
|
module Policy
|
5
|
+
# This is the class for limiting cookie storage on client machine.
|
5
6
|
class CookieLimiter
|
6
7
|
include ::Rack::Utils
|
7
8
|
|
9
|
+
HTTP_COOKIE = "HTTP_COOKIE".freeze
|
8
10
|
SET_COOKIE = "Set-Cookie".freeze
|
9
11
|
CACHE_CONTROL = "Cache-Control".freeze
|
10
12
|
CONSENT_TOKEN = "cookie_limiter".freeze
|
11
13
|
|
12
|
-
attr_reader :app
|
13
|
-
|
14
|
-
attr_accessor :headers
|
14
|
+
attr_reader :app, :options
|
15
|
+
attr_accessor :status, :headers, :body
|
15
16
|
|
17
|
+
# @option options [String] :consent_token
|
18
|
+
#
|
16
19
|
def initialize(app, options={})
|
17
20
|
@app, @options = app, options
|
18
21
|
end
|
@@ -26,23 +29,41 @@ module Rack
|
|
26
29
|
end
|
27
30
|
|
28
31
|
def call(env)
|
29
|
-
status, headers, body = app.call(env)
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
self.status, self.headers, self.body = @app.call(env)
|
33
|
+
request = Rack::Request.new(env)
|
34
|
+
response = Rack::Response.new body, status, headers
|
35
|
+
clear_cookies!(request, response) unless allowed?(request)
|
36
|
+
finish(env)
|
33
37
|
end
|
34
38
|
|
35
|
-
|
36
|
-
|
39
|
+
# Returns `false` if the cookie policy disallows cookie storage
|
40
|
+
# for a given request, or `true` otherwise.
|
41
|
+
#
|
42
|
+
def allowed?(request)
|
43
|
+
if ( request.cookies.has_key?(consent_token.to_s) ||
|
44
|
+
parse_cookies.has_key?(consent_token.to_s) )
|
37
45
|
true
|
38
46
|
else
|
39
47
|
false
|
40
48
|
end
|
41
49
|
end
|
42
50
|
|
51
|
+
# Finish http response with proper headers
|
52
|
+
def finish(env)
|
53
|
+
if [204, 304].include?(status.to_i)
|
54
|
+
headers.delete "Content-Type"
|
55
|
+
[status.to_i, headers, []]
|
56
|
+
elsif env['REQUEST_METHOD'] == 'HEAD'
|
57
|
+
[status.to_i, headers, []]
|
58
|
+
else
|
59
|
+
[status.to_i, headers, body]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
43
63
|
protected
|
44
64
|
|
45
65
|
# Returns the response cookies converted to Hash
|
66
|
+
#
|
46
67
|
def parse_cookies
|
47
68
|
cookies = {}
|
48
69
|
if header = headers[SET_COOKIE]
|
@@ -57,9 +78,16 @@ module Rack
|
|
57
78
|
cookies
|
58
79
|
end
|
59
80
|
|
60
|
-
def clear_cookies!
|
81
|
+
def clear_cookies!(request, response)
|
82
|
+
cookies = parse_cookies
|
61
83
|
headers.delete(SET_COOKIE)
|
84
|
+
request.env.delete(HTTP_COOKIE)
|
62
85
|
revalidate_cache!
|
86
|
+
|
87
|
+
cookies.merge(request.cookies).each do |key, value|
|
88
|
+
response.delete_cookie key.to_sym
|
89
|
+
end
|
90
|
+
|
63
91
|
headers
|
64
92
|
end
|
65
93
|
|
@@ -71,6 +99,10 @@ module Rack
|
|
71
99
|
::Rack::Utils.set_cookie_header!(headers, key, value)
|
72
100
|
end
|
73
101
|
|
102
|
+
def delete_cookie(key, value)
|
103
|
+
::Rack::Utils.delete_cookie_header!(headers, key, value)
|
104
|
+
end
|
105
|
+
|
74
106
|
end # CookieLimiter
|
75
107
|
end # Policy
|
76
108
|
end # Rack
|
data/lib/rack/policy/version.rb
CHANGED
data/spec/cookie_limiter_spec.rb
CHANGED
@@ -7,21 +7,36 @@ describe Rack::Policy::CookieLimiter do
|
|
7
7
|
last_response.body.should == 'ok'
|
8
8
|
end
|
9
9
|
|
10
|
-
it "does not meter where the middleware is inserted"
|
10
|
+
it "does not meter where the middleware is inserted" do
|
11
|
+
mock_app {
|
12
|
+
use Rack::Policy::CookieLimiter
|
13
|
+
use Rack::Session::Cookie, :key => 'app.session', :path => '/'
|
14
|
+
run DummyApp
|
15
|
+
}
|
16
|
+
get '/'
|
17
|
+
last_response.should be_ok
|
18
|
+
last_response.headers['Set-Cookie'].should be_nil
|
19
|
+
end
|
11
20
|
|
12
21
|
context 'no consent' do
|
13
22
|
it 'removes cookie session header' do
|
14
|
-
mock_app
|
15
|
-
|
23
|
+
mock_app {
|
24
|
+
use Rack::Policy::CookieLimiter
|
25
|
+
run DummyApp
|
26
|
+
}
|
27
|
+
request '/'
|
16
28
|
last_response.should be_ok
|
17
29
|
last_response.headers['Set-Cookie'].should be_nil
|
18
30
|
end
|
19
31
|
|
20
32
|
it 'revalidates caches' do
|
21
|
-
mock_app
|
22
|
-
|
33
|
+
mock_app {
|
34
|
+
use Rack::Policy::CookieLimiter
|
35
|
+
run DummyApp
|
36
|
+
}
|
37
|
+
request '/'
|
23
38
|
last_response.should be_ok
|
24
|
-
last_response.headers['Cache-
|
39
|
+
last_response.headers['Cache-Control'].should =~ /must-revalidate/
|
25
40
|
end
|
26
41
|
end
|
27
42
|
|
@@ -46,4 +61,15 @@ describe Rack::Policy::CookieLimiter do
|
|
46
61
|
end
|
47
62
|
end
|
48
63
|
|
64
|
+
context 'finish response' do
|
65
|
+
it 'returns correct response for head request' do
|
66
|
+
mock_app {
|
67
|
+
use Rack::Policy::CookieLimiter
|
68
|
+
run DummyApp
|
69
|
+
}
|
70
|
+
head '/'
|
71
|
+
last_response.should be_ok
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
49
75
|
end # Rack::Policy::CookieLimiter
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-policy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
16
|
-
requirement: &
|
16
|
+
requirement: &2152703340 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '1.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2152703340
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rack-test
|
27
|
-
requirement: &
|
27
|
+
requirement: &2152702840 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2152702840
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &2152702300 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2152702300
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rake
|
49
|
-
requirement: &
|
49
|
+
requirement: &2152701660 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2152701660
|
58
58
|
description: This is Rack middleware that makes your app compliant with the 'EU ePrivacy
|
59
59
|
Directive'
|
60
60
|
email:
|
@@ -67,10 +67,13 @@ files:
|
|
67
67
|
- .rspec
|
68
68
|
- .rvmrc
|
69
69
|
- .travis.yml
|
70
|
+
- CHANGELOG.md
|
70
71
|
- Gemfile
|
71
72
|
- LICENSE
|
72
73
|
- README.md
|
73
74
|
- Rakefile
|
75
|
+
- examples/rails_3/Gemfile
|
76
|
+
- examples/rails_3/rails_3.ru
|
74
77
|
- lib/rack-policy.rb
|
75
78
|
- lib/rack/policy.rb
|
76
79
|
- lib/rack/policy/cookie_limiter.rb
|