padrino-cookies 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.
- data/README.md +0 -1
- data/lib/padrino-cookies/jar.rb +69 -16
- data/lib/padrino-cookies/version.rb +1 -1
- data/lib/padrino-cookies.rb +13 -0
- data/spec/cookies_spec.rb +79 -2
- metadata +11 -11
data/README.md
CHANGED
data/lib/padrino-cookies/jar.rb
CHANGED
@@ -1,9 +1,4 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
require 'active_support/core_ext/integer/time'
|
3
|
-
require 'active_support/core_ext/numeric/time'
|
4
|
-
require 'active_support/core_ext/numeric/bytes'
|
5
|
-
require 'active_support/core_ext/date/calculations'
|
6
|
-
|
7
2
|
module Padrino
|
8
3
|
module Cookies
|
9
4
|
class Jar
|
@@ -15,6 +10,12 @@ module Padrino
|
|
15
10
|
@request = app.request
|
16
11
|
@cookies = app.request.cookies
|
17
12
|
|
13
|
+
if app.settings.respond_to?(:cookie_secret)
|
14
|
+
@secret = app.settings.cookie_secret
|
15
|
+
elsif app.settings.respond_to?(:session_secret)
|
16
|
+
@secret = app.settings.session_secret
|
17
|
+
end
|
18
|
+
|
18
19
|
@options = {
|
19
20
|
path: '/',
|
20
21
|
httponly: true,
|
@@ -29,7 +30,7 @@ module Padrino
|
|
29
30
|
# Value of the cookie
|
30
31
|
#
|
31
32
|
# @example
|
32
|
-
#
|
33
|
+
# cookie[:remembrance]
|
33
34
|
# # => '71ab53190d2f863b5f3b12381d2d5986512f8e15b34d439e6b66e3daf41b5e35'
|
34
35
|
#
|
35
36
|
# @since 0.1.0
|
@@ -66,8 +67,11 @@ module Padrino
|
|
66
67
|
# @option options [String] :domain
|
67
68
|
# The scope in which this cookie is accessible
|
68
69
|
#
|
70
|
+
# @raise [Overflow]
|
71
|
+
# Raised when the value of the cookie exceeds the maximum size
|
72
|
+
#
|
69
73
|
# @example
|
70
|
-
#
|
74
|
+
# cookie[:remembrance] = '71ab53190d2f863b5f3b12381d2d5986512f8e15b34d439e6b66e3daf41b5e35'
|
71
75
|
#
|
72
76
|
# @since 0.1.0
|
73
77
|
# @api public
|
@@ -76,6 +80,8 @@ module Padrino
|
|
76
80
|
options = { value: options }
|
77
81
|
end
|
78
82
|
|
83
|
+
raise Overflow if options[:value].size > MAX_COOKIE_SIZE
|
84
|
+
|
79
85
|
@response.set_cookie(name, @options.merge(options))
|
80
86
|
@cookies[name.to_s] = options[:value]
|
81
87
|
end
|
@@ -205,32 +211,79 @@ module Padrino
|
|
205
211
|
# Sets a permanent cookie
|
206
212
|
#
|
207
213
|
# @example
|
208
|
-
#
|
214
|
+
# cookie.permanent[:remembrance] = '71ab53190d2f863b5f3b12381d2d5986512f8e15b34d439e6b66e3daf41b5e35'
|
209
215
|
#
|
210
216
|
# @since 0.1.0
|
211
217
|
# @api public
|
212
218
|
def permanent
|
213
|
-
@permanent ||= PermanentJar.new(self)
|
219
|
+
@permanent ||= PermanentJar.new(self, @secret)
|
220
|
+
end
|
221
|
+
|
222
|
+
###
|
223
|
+
# Signs a cookie with a cryptographic hash so it cannot be tampered with
|
224
|
+
#
|
225
|
+
# @example
|
226
|
+
# cookie.signed[:remembrance] = '71ab53190d2f863b5f3b12381d2d5986512f8e15b34d439e6b66e3daf41b5e35'
|
227
|
+
#
|
228
|
+
# @since 0.1.1
|
229
|
+
# @api public
|
230
|
+
def signed
|
231
|
+
@signed ||= SignedJar.new(self, @secret)
|
214
232
|
end
|
215
233
|
end # Jar
|
216
234
|
|
217
235
|
class PermanentJar # @private
|
218
|
-
def initialize(parent_jar)
|
236
|
+
def initialize(parent_jar, secret)
|
219
237
|
@parent_jar = parent_jar
|
238
|
+
@secret = secret
|
220
239
|
end
|
221
240
|
|
222
|
-
def []=(
|
223
|
-
unless options.is_a?(Hash)
|
224
|
-
options = { value: options }
|
225
|
-
end
|
226
|
-
|
241
|
+
def []=(name, options)
|
242
|
+
options = { value: options } unless options.is_a?(Hash)
|
227
243
|
options[:expires] = 1.year.from_now
|
228
|
-
@parent_jar[
|
244
|
+
@parent_jar[name] = options
|
245
|
+
end
|
246
|
+
|
247
|
+
def signed
|
248
|
+
@signed ||= SignedJar.new(self, @secret)
|
229
249
|
end
|
230
250
|
|
231
251
|
def method_missing(method, *args, &block)
|
232
252
|
@parent_jar.send(method, *args, &block)
|
233
253
|
end
|
234
254
|
end # PermanentJar
|
255
|
+
|
256
|
+
class SignedJar # @private
|
257
|
+
def initialize(parent_jar, secret)
|
258
|
+
if secret.blank? || secret.size < 64
|
259
|
+
raise ArgumentError, 'cookie_secret must be at least 64 characters long'
|
260
|
+
end
|
261
|
+
|
262
|
+
@parent_jar = parent_jar
|
263
|
+
@message_verifier = ActiveSupport::MessageVerifier.new(secret)
|
264
|
+
end
|
265
|
+
|
266
|
+
def [](name)
|
267
|
+
if value = @parent_jar[name]
|
268
|
+
@message_verifier.verify(value)
|
269
|
+
end
|
270
|
+
rescue
|
271
|
+
nil
|
272
|
+
end
|
273
|
+
|
274
|
+
def []=(name, options)
|
275
|
+
options = { value: options } unless options.is_a?(Hash)
|
276
|
+
options[:value] = @message_verifier.generate(options[:value])
|
277
|
+
@parent_jar[name] = options
|
278
|
+
end
|
279
|
+
|
280
|
+
def permanent
|
281
|
+
@permanent ||= PermanentJar.new(self, @secret)
|
282
|
+
end
|
283
|
+
|
284
|
+
def method_missing(method, *args, &block)
|
285
|
+
@parent_jar.send(method, *args, &block)
|
286
|
+
end
|
287
|
+
end # SignedJar
|
235
288
|
end # Cookies
|
236
289
|
end # Padrino
|
data/lib/padrino-cookies.rb
CHANGED
@@ -1,9 +1,22 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
+
require 'active_support/core_ext/integer/time'
|
3
|
+
require 'active_support/core_ext/numeric/time'
|
4
|
+
require 'active_support/core_ext/date/calculations'
|
5
|
+
require 'active_support/message_verifier'
|
6
|
+
|
2
7
|
require 'padrino-core'
|
3
8
|
FileSet.glob_require('padrino-cookies/**/*.rb', __FILE__)
|
4
9
|
|
5
10
|
module Padrino
|
6
11
|
module Cookies
|
12
|
+
MAX_COOKIE_SIZE = 4096
|
13
|
+
|
14
|
+
class Overflow < ArgumentError
|
15
|
+
def http_status
|
16
|
+
500
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
7
20
|
class << self
|
8
21
|
# @private
|
9
22
|
def registered(app)
|
data/spec/cookies_spec.rb
CHANGED
@@ -5,6 +5,20 @@ describe Padrino::Cookies do
|
|
5
5
|
route('foo=bar', 'bar=foo') { cookies }
|
6
6
|
end
|
7
7
|
|
8
|
+
context :secret do
|
9
|
+
it 'should use :cookie_secret when set' do
|
10
|
+
app.set :cookie_secret, 'cookie_secret'
|
11
|
+
secret = cookies.instance_variable_get(:@secret)
|
12
|
+
secret.should == 'cookie_secret'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should fall back to :session_secret when :cookie_secret is not set' do
|
16
|
+
app.set :session_secret, 'session_secret'
|
17
|
+
secret = cookies.instance_variable_get(:@secret)
|
18
|
+
secret.should == 'session_secret'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
8
22
|
context :[] do
|
9
23
|
it 'can retrieve existing cookies' do
|
10
24
|
cookies['foo'].should == 'bar'
|
@@ -33,6 +47,18 @@ describe Padrino::Cookies do
|
|
33
47
|
cookies['test'].should == 'test'
|
34
48
|
end
|
35
49
|
|
50
|
+
it 'should raise Overflow when more then 4096 bytes are used' do
|
51
|
+
cookies['test'] = 'C' * 4096
|
52
|
+
cookies['test'].should_not be_nil
|
53
|
+
|
54
|
+
expect { cookies['test'] = 'C' * 4097 }.to raise_error(Padrino::Cookies::Overflow)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should accept a hash of options' do
|
58
|
+
cookies['test'] = { value: 'test', path: '/' }
|
59
|
+
cookies['test'].should == 'test'
|
60
|
+
end
|
61
|
+
|
36
62
|
it 'should set the response headers when setting a cookie' do
|
37
63
|
result = route do
|
38
64
|
cookies['foo'] = 'bar'
|
@@ -86,7 +112,7 @@ describe Padrino::Cookies do
|
|
86
112
|
end
|
87
113
|
end
|
88
114
|
|
89
|
-
|
115
|
+
context :clear do
|
90
116
|
it 'can delete all cookies that are set' do
|
91
117
|
cookies['foo'].should == 'bar'
|
92
118
|
cookies['bar'].should == 'foo'
|
@@ -110,7 +136,7 @@ describe Padrino::Cookies do
|
|
110
136
|
end
|
111
137
|
end
|
112
138
|
|
113
|
-
|
139
|
+
context :keys do
|
114
140
|
it 'can give you a list of cookies that are set' do
|
115
141
|
cookies.keys.should == ['bar', 'foo']
|
116
142
|
end
|
@@ -161,11 +187,18 @@ describe Padrino::Cookies do
|
|
161
187
|
end
|
162
188
|
|
163
189
|
context :permanent do
|
190
|
+
before { app.set :cookie_secret, ('test' * 16) }
|
191
|
+
|
164
192
|
it 'should add cookies to the parent jar' do
|
165
193
|
cookies.permanent['baz'] = 'foo'
|
166
194
|
cookies['baz'].should == 'foo'
|
167
195
|
end
|
168
196
|
|
197
|
+
it 'should accept a hash of options' do
|
198
|
+
cookies.permanent['foo'] = { value: 'baz', path: '/' }
|
199
|
+
cookies['foo'].should == 'baz'
|
200
|
+
end
|
201
|
+
|
169
202
|
it 'should set a cookie that expires in the distant future' do
|
170
203
|
result = route do
|
171
204
|
cookies.permanent['baz'] = 'foo'
|
@@ -174,5 +207,49 @@ describe Padrino::Cookies do
|
|
174
207
|
|
175
208
|
result.should =~ /#{1.year.from_now.year}/
|
176
209
|
end
|
210
|
+
|
211
|
+
it 'should allow you to chain signed cookies' do
|
212
|
+
result = route do
|
213
|
+
cookies.permanent.signed['foo'] = 'baz'
|
214
|
+
response['Set-Cookie']
|
215
|
+
end
|
216
|
+
|
217
|
+
result.should =~ /#{1.year.from_now.year}/
|
218
|
+
result.should =~ /6cbc7824dbfd7121efb019bb55f01be1e07bcf58/
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context :signed do
|
223
|
+
before { app.set :cookie_secret, ('test' * 16) }
|
224
|
+
|
225
|
+
it 'should read signed values' do
|
226
|
+
cookies['foo'] = 'BAhJIghiYXoGOgZFRg==--6cbc7824dbfd7121efb019bb55f01be1e07bcf58'
|
227
|
+
cookies.signed['foo'].should == 'baz'
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'should write signed values' do
|
231
|
+
cookies.signed['foo'] = 'baz'
|
232
|
+
cookies['foo'].should == 'BAhJIghiYXoGOgZFRg==--6cbc7824dbfd7121efb019bb55f01be1e07bcf58'
|
233
|
+
end
|
234
|
+
|
235
|
+
it 'should accept a hash of options' do
|
236
|
+
cookies.signed['foo'] = { value: 'baz', path: '/' }
|
237
|
+
cookies.signed['foo'].should == 'baz'
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should require a 64 character secret' do
|
241
|
+
app.set :cookie_secret, ('C' * 63)
|
242
|
+
expect { cookies.signed['foo'] = 'baz' }.to raise_error(ArgumentError)
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'should allow you to chain permanent cookies' do
|
246
|
+
result = route do
|
247
|
+
cookies.signed.permanent['foo'] = 'baz'
|
248
|
+
response['Set-Cookie']
|
249
|
+
end
|
250
|
+
|
251
|
+
result.should =~ /#{1.year.from_now.year}/
|
252
|
+
result.should =~ /6cbc7824dbfd7121efb019bb55f01be1e07bcf58/
|
253
|
+
end
|
177
254
|
end
|
178
255
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: padrino-cookies
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
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-03-
|
12
|
+
date: 2012-03-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: padrino-core
|
16
|
-
requirement: &
|
16
|
+
requirement: &13846392 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *13846392
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &13845648 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 2.0.0
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *13845648
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec-html-matchers
|
38
|
-
requirement: &
|
38
|
+
requirement: &13844784 !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: *13844784
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rack-test
|
49
|
-
requirement: &
|
49
|
+
requirement: &13825020 !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: *13825020
|
58
58
|
description: A plugin for the Padrino web framework which adds support for Rails like
|
59
59
|
cookie manipulation
|
60
60
|
email:
|
@@ -97,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
97
|
version: '0'
|
98
98
|
requirements: []
|
99
99
|
rubyforge_project:
|
100
|
-
rubygems_version: 1.8.
|
100
|
+
rubygems_version: 1.8.17
|
101
101
|
signing_key:
|
102
102
|
specification_version: 3
|
103
103
|
summary: A plugin for the Padrino web framework which adds support for Rails like
|