http-security 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.travis.yml +21 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +17 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +20 -0
- data/README.md +90 -0
- data/Rakefile +34 -0
- data/http-security.gemspec +23 -0
- data/lib/http/security.rb +2 -0
- data/lib/http/security/exceptions.rb +8 -0
- data/lib/http/security/headers.rb +12 -0
- data/lib/http/security/headers/cache_control.rb +36 -0
- data/lib/http/security/headers/content_security_policy.rb +71 -0
- data/lib/http/security/headers/content_security_policy_report_only.rb +10 -0
- data/lib/http/security/headers/pragma.rb +24 -0
- data/lib/http/security/headers/public_key_pins.rb +60 -0
- data/lib/http/security/headers/public_key_pins_report_only.rb +10 -0
- data/lib/http/security/headers/set_cookie.rb +75 -0
- data/lib/http/security/headers/strict_transport_security.rb +29 -0
- data/lib/http/security/headers/x_content_type_options.rb +24 -0
- data/lib/http/security/headers/x_frame_options.rb +39 -0
- data/lib/http/security/headers/x_permitted_cross_domain_policies.rb +47 -0
- data/lib/http/security/headers/x_xss_protection.rb +34 -0
- data/lib/http/security/http_date.rb +13 -0
- data/lib/http/security/malformed_header.rb +33 -0
- data/lib/http/security/parsers.rb +14 -0
- data/lib/http/security/parsers/cache_control.rb +62 -0
- data/lib/http/security/parsers/content_security_policy.rb +128 -0
- data/lib/http/security/parsers/content_security_policy_report_only.rb +10 -0
- data/lib/http/security/parsers/expires.rb +19 -0
- data/lib/http/security/parsers/parser.rb +408 -0
- data/lib/http/security/parsers/pragma.rb +25 -0
- data/lib/http/security/parsers/public_key_pins.rb +43 -0
- data/lib/http/security/parsers/public_key_pins_report_only.rb +10 -0
- data/lib/http/security/parsers/set_cookie.rb +62 -0
- data/lib/http/security/parsers/strict_transport_security.rb +42 -0
- data/lib/http/security/parsers/x_content_type_options.rb +19 -0
- data/lib/http/security/parsers/x_frame_options.rb +47 -0
- data/lib/http/security/parsers/x_permitted_cross_domain_policies.rb +33 -0
- data/lib/http/security/parsers/x_xss_protection.rb +27 -0
- data/lib/http/security/response.rb +323 -0
- data/lib/http/security/version.rb +5 -0
- data/spec/data/alexa.csv +100 -0
- data/spec/headers/cache_control_spec.rb +40 -0
- data/spec/headers/content_security_policy_spec.rb +46 -0
- data/spec/headers/pragma_spec.rb +26 -0
- data/spec/headers/public_key_pins_spec.rb +68 -0
- data/spec/headers/set_cookie_spec.rb +122 -0
- data/spec/headers/strict_transport_security_spec.rb +39 -0
- data/spec/headers/x_content_type_options_spec.rb +26 -0
- data/spec/headers/x_frame_options_spec.rb +86 -0
- data/spec/headers/x_permitted_cross_domain_policies_spec.rb +108 -0
- data/spec/headers/x_xss_protection_spec.rb +59 -0
- data/spec/parsers/cache_control_spec.rb +26 -0
- data/spec/parsers/content_security_policy_report_only_spec.rb +48 -0
- data/spec/parsers/content_security_policy_spec.rb +74 -0
- data/spec/parsers/expires_spec.rb +71 -0
- data/spec/parsers/parser_spec.rb +317 -0
- data/spec/parsers/pragma_spec.rb +10 -0
- data/spec/parsers/public_key_pins_spec.rb +81 -0
- data/spec/parsers/set_cookie_spec.rb +55 -0
- data/spec/parsers/strict_transport_security_spec.rb +62 -0
- data/spec/parsers/x_content_type_options_spec.rb +10 -0
- data/spec/parsers/x_frame_options_spec.rb +24 -0
- data/spec/parsers/x_permitted_cross_domain_policies_spec.rb +34 -0
- data/spec/parsers/x_xss_protection_spec.rb +39 -0
- data/spec/response_spec.rb +262 -0
- data/spec/spec_helper.rb +13 -0
- data/tasks/alexa.rb +40 -0
- metadata +171 -0
@@ -0,0 +1,317 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require 'http/security/parsers/parser'
|
3
|
+
|
4
|
+
describe Parsers::Parser do
|
5
|
+
describe "#http_date" do
|
6
|
+
subject { super().http_date }
|
7
|
+
|
8
|
+
it "parses rfc1123-date" do
|
9
|
+
date = "Thu, 04 Dec 2015 16:00:00 GMT"
|
10
|
+
|
11
|
+
expect(subject.parse(date)).to eq(date: date)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "parses rfc850-date" do
|
15
|
+
date = "Thursday, 04-Dec-15 16:00:00 GMT"
|
16
|
+
|
17
|
+
expect(subject.parse(date)).to eq(date: date)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "parses rfc1123-date" do
|
21
|
+
date = "Thu Dec 04 16:00:00 2015"
|
22
|
+
|
23
|
+
expect(subject.parse(date)).to eq(date: date)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#header_extension" do
|
28
|
+
subject { super().header_extension }
|
29
|
+
|
30
|
+
let(:name) { 'foo' }
|
31
|
+
|
32
|
+
context "when parsing a token" do
|
33
|
+
it "should tag the token name" do
|
34
|
+
expect(subject.parse(name)).to eq(name: name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when parsing a token and a value" do
|
39
|
+
let(:value) { 'bar' }
|
40
|
+
|
41
|
+
it "should tag the token and value" do
|
42
|
+
expect(subject.parse("#{name}=#{value}")).to eq(
|
43
|
+
name: name,
|
44
|
+
value: value
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#uri" do
|
51
|
+
let(:transform) { Parsers::Parser::Transform.new }
|
52
|
+
subject { super().uri }
|
53
|
+
|
54
|
+
it "parses a uri without a scheme specified" do
|
55
|
+
uri = "www.example.com"
|
56
|
+
expect(transform.apply(subject.parse(uri))).to eq(URI.parse(uri))
|
57
|
+
end
|
58
|
+
|
59
|
+
it "parses a uri with a scheme specified" do
|
60
|
+
uri = "https://www.example.com"
|
61
|
+
expect(transform.apply(subject.parse(uri))).to eq(URI.parse(uri))
|
62
|
+
end
|
63
|
+
|
64
|
+
it "parses a uri with a path specified" do
|
65
|
+
uri = "http://www.example.com/about"
|
66
|
+
expect(transform.apply(subject.parse(uri))).to eq(URI.parse(uri))
|
67
|
+
end
|
68
|
+
|
69
|
+
it "parses a uri with parameters" do
|
70
|
+
uri = "http://www.example.com/about?parameter1=val1¶meter2=val2"
|
71
|
+
expect(transform.apply(subject.parse(uri))).to eq(URI.parse(uri))
|
72
|
+
end
|
73
|
+
|
74
|
+
it "parses a uri with a redirect address in its parameters" do
|
75
|
+
uri = "http://www.example.com/url?sa=X&q=http://example2.com/article/headline_20101013&ct=ga&cad=:n1:n2:t1286988171:&cd=yQ=AG-Tx"
|
76
|
+
expect(transform.apply(subject.parse(uri))).to eq(URI.parse(uri))
|
77
|
+
end
|
78
|
+
|
79
|
+
it "parses a uri with fragments" do
|
80
|
+
uri = "http://www.example.com/url#fragment"
|
81
|
+
expect(transform.apply(subject.parse(uri))).to eq(URI.parse(uri))
|
82
|
+
end
|
83
|
+
|
84
|
+
it "parses an ftp uri" do
|
85
|
+
uri = "ftp://ftp.is.co.za/rfc/rfc1808.txt"
|
86
|
+
expect(transform.apply(subject.parse(uri))).to eq(URI.parse(uri))
|
87
|
+
end
|
88
|
+
|
89
|
+
it "parses a uri with a port" do
|
90
|
+
uri = "telnet://192.0.2.16:80/"
|
91
|
+
expect(transform.apply(subject.parse(uri))).to eq(URI.parse(uri))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe described_class::Transform do
|
96
|
+
describe "boolean" do
|
97
|
+
it "should map '0' to false" do
|
98
|
+
expect(subject.apply({boolean: '0'})).to be false
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should map 'no' to false" do
|
102
|
+
expect(subject.apply({boolean: 'no'})).to be false
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should map 'false' to false" do
|
106
|
+
expect(subject.apply({boolean: 'false'})).to be false
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should map '1' to true" do
|
110
|
+
expect(subject.apply({boolean: '1'})).to be true
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should map 'yes' to true" do
|
114
|
+
expect(subject.apply({boolean: 'yes'})).to be true
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should map 'true' to false" do
|
118
|
+
expect(subject.apply({boolean: 'true'})).to be true
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "numeric" do
|
123
|
+
it "should coerce Strings to Integer values" do
|
124
|
+
expect(subject.apply({numeric: '42'})).to be 42
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe "escaped_char" do
|
129
|
+
context "when the escaped char is a control character" do
|
130
|
+
let(:char) { 'n' }
|
131
|
+
|
132
|
+
it "should map it to the control character" do
|
133
|
+
expect(subject.apply({escaped_char: 'n'})).to be == "\n"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context "when the escaped char is a printable character" do
|
138
|
+
let(:char) { 'x' }
|
139
|
+
|
140
|
+
it "should return the printable character" do
|
141
|
+
expect(subject.apply({escaped_char: char})).to be == char
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "string" do
|
147
|
+
context "when given one String" do
|
148
|
+
let(:string) { "foo bar" }
|
149
|
+
|
150
|
+
it "should return the String" do
|
151
|
+
expect(subject.apply({string: string})).to be == string
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context "when given multiple Strings" do
|
156
|
+
let(:strings) { ['foo', "\n", 'bar'] }
|
157
|
+
|
158
|
+
it "should join the Strings" do
|
159
|
+
expect(subject.apply({string: strings})).to be == strings.join
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "date" do
|
165
|
+
let(:string) { 'Tue, 24 Mar 2015 00:00:00 GMT' }
|
166
|
+
let(:date) { Date.parse(string) }
|
167
|
+
|
168
|
+
it "should return an HTTPDate" do
|
169
|
+
expect(subject.apply({date: string})).to be_kind_of(HTTPDate)
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should coerce Strings to Date values" do
|
173
|
+
expect(subject.apply({date: string})).to be == date
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe "uri" do
|
178
|
+
let(:string) { 'https://www.example.com/?foo=bar' }
|
179
|
+
let(:uri) { URI(string) }
|
180
|
+
|
181
|
+
it "should parse Strings as URIs" do
|
182
|
+
expect(subject.apply({uri: string})).to be == uri
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "list" do
|
187
|
+
context "when given a single element" do
|
188
|
+
let(:element) { 'foo' }
|
189
|
+
|
190
|
+
it "should return an Array of the element" do
|
191
|
+
expect(subject.apply({list: element})).to be == [element]
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context "when given multiple elements" do
|
196
|
+
let(:elements) { %w[foo bar baz] }
|
197
|
+
|
198
|
+
it "should return the elements" do
|
199
|
+
expect(subject.apply({list: elements})).to be == elements
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "key" do
|
205
|
+
let(:name) { 'foo' }
|
206
|
+
let(:key) { :foo }
|
207
|
+
|
208
|
+
it "should return a Hash with the name and true" do
|
209
|
+
expect(subject.apply({key: name})).to be == {key => true}
|
210
|
+
end
|
211
|
+
|
212
|
+
context "when given mixed-case String" do
|
213
|
+
let(:name) { 'fooBar' }
|
214
|
+
let(:key) { :foobar }
|
215
|
+
|
216
|
+
it "should downcase the String" do
|
217
|
+
expect(subject.apply({key: name})).to be == {key => true}
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
context "when given a hyphenated String" do
|
222
|
+
let(:name) { 'foo-bar' }
|
223
|
+
let(:key) { :foo_bar }
|
224
|
+
|
225
|
+
it "should replace the hyphens with underscores" do
|
226
|
+
expect(subject.apply({key: name})).to be == {key => true}
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe "key with simple value" do
|
232
|
+
let(:name) { 'foo' }
|
233
|
+
let(:key) { :foo }
|
234
|
+
let(:value) { 'bar' }
|
235
|
+
|
236
|
+
it "should return a Hash of the name and value" do
|
237
|
+
expect(subject.apply({key: name, value: value})).to be == {
|
238
|
+
key => value
|
239
|
+
}
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "key with values" do
|
244
|
+
let(:name) { 'foo' }
|
245
|
+
let(:key) { :foo }
|
246
|
+
let(:value) { {'x' => 1} }
|
247
|
+
|
248
|
+
it "should return a Hash of the name and value" do
|
249
|
+
expect(subject.apply({key: name, values: value})).to be == {
|
250
|
+
key => value
|
251
|
+
}
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
describe "name" do
|
256
|
+
let(:name) { 'foo' }
|
257
|
+
|
258
|
+
it "should return a Hash with the name and true" do
|
259
|
+
expect(subject.apply({name: name})).to be == {name => true}
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
describe "name with simple value" do
|
264
|
+
let(:name) { 'foo' }
|
265
|
+
let(:value) { 'bar' }
|
266
|
+
|
267
|
+
it "should return a Hash of the name and value" do
|
268
|
+
expect(subject.apply({name: name, value: value})).to be == {
|
269
|
+
name => value
|
270
|
+
}
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe "name with a tree of values" do
|
275
|
+
let(:name) { 'foo' }
|
276
|
+
let(:tree) { {'x' => 1} }
|
277
|
+
|
278
|
+
it "should return a Hash of the name and values" do
|
279
|
+
expect(subject.apply({name: name, values: tree})).to be == {
|
280
|
+
name => tree
|
281
|
+
}
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
describe "directives" do
|
286
|
+
context "when given a single Hash" do
|
287
|
+
let(:hash) { {foo: 'bar'} }
|
288
|
+
|
289
|
+
it "should return the Hash" do
|
290
|
+
expect(subject.apply({directives: hash})).to be == hash
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
context "when given multiple Hashes" do
|
295
|
+
let(:hash1) { {foo: 'bar'} }
|
296
|
+
let(:hash2) { {baz: 'quix'} }
|
297
|
+
let(:hashes) { [hash1, hash2] }
|
298
|
+
let(:hash) { hash1.merge(hash2) }
|
299
|
+
|
300
|
+
it "should return a merged Hash" do
|
301
|
+
expect(subject.apply({directives: hashes})).to be == hash
|
302
|
+
end
|
303
|
+
|
304
|
+
context "when the Hashes share key names" do
|
305
|
+
let(:hash1) { {foo: '1', bar: '2'} }
|
306
|
+
let(:hash2) { {bar: '3', baz: '4'} }
|
307
|
+
let(:hashes) { [hash1, hash2] }
|
308
|
+
let(:hash) { {foo: '1', bar: ['2', '3'], baz: '4'} }
|
309
|
+
|
310
|
+
it "should combine the values into an Array" do
|
311
|
+
expect(subject.apply({directives: hashes})).to be == hash
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'http/security/parsers/public_key_pins'
|
3
|
+
|
4
|
+
describe Parsers::PublicKeyPins do
|
5
|
+
let(:pin_sha256) { 'klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=' }
|
6
|
+
let(:header) { "pin-sha256=\"#{pin_sha256}\"" }
|
7
|
+
|
8
|
+
it "parses the one pin-sha256=..." do
|
9
|
+
expect(subject.parse(header)).to be == {pin_sha256: pin_sha256}
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when given multiple pin-sha256= directives" do
|
13
|
+
let(:primary) { pin_sha256 }
|
14
|
+
let(:secondary) { 'M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE=' }
|
15
|
+
let(:header) { "pin-sha256=\"#{primary}\"; pin-sha256=\"#{secondary}\"" }
|
16
|
+
|
17
|
+
it "parses the pin-sha256=... directives into an Array" do
|
18
|
+
expect(subject.parse(header)).to be == {pin_sha256: [primary, secondary]}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when given pin- directives with unsupported hash algorithms" do
|
23
|
+
let(:pin_sha9000) { "foo" }
|
24
|
+
let(:header) { "#{super()}; pin-sha9000=\"#{pin_sha9000}\"" }
|
25
|
+
|
26
|
+
it "parses the unsupported pin- directives" do
|
27
|
+
expect(subject.parse(header)).to be == {
|
28
|
+
pin_sha256: pin_sha256,
|
29
|
+
'pin-sha9000' => pin_sha9000
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when the max-age= directive is present" do
|
35
|
+
let(:max_age) { 31536000 }
|
36
|
+
let(:header) { "pin-sha256=\"#{pin_sha256}\"; max-age=#{max_age}" }
|
37
|
+
|
38
|
+
it "accepts pin-sha256=...; max-age=..." do
|
39
|
+
expect(subject.parse(header)).to be == {
|
40
|
+
pin_sha256: pin_sha256,
|
41
|
+
max_age: max_age
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when the includeSubdomains directive is present" do
|
46
|
+
let(:header) { "#{super()}; includeSubdomains" }
|
47
|
+
|
48
|
+
it "accepts pin-sha256=...; max-age=...; includeSubdomains" do
|
49
|
+
expect(subject.parse(header)).to be == {
|
50
|
+
pin_sha256: pin_sha256,
|
51
|
+
max_age: max_age,
|
52
|
+
includesubdomains: true
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when the report-uri directive is present" do
|
58
|
+
let(:report_uri) { URI('https://www.example.com/') }
|
59
|
+
let(:header) { "#{super()}; report-uri=\"#{report_uri}\"" }
|
60
|
+
|
61
|
+
it "accepts pin-sha256=...; max-age=...; includeSubdomains" do
|
62
|
+
expect(subject.parse(header)).to be == {
|
63
|
+
pin_sha256: pin_sha256,
|
64
|
+
max_age: max_age,
|
65
|
+
report_uri: report_uri
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "when the strict directive is present" do
|
72
|
+
let(:header) { "#{super()}; strict" }
|
73
|
+
|
74
|
+
it "accepts pin-sha256=...; strict" do
|
75
|
+
expect(subject.parse(header)).to be == {
|
76
|
+
pin_sha256: pin_sha256,
|
77
|
+
strict: true
|
78
|
+
}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "http/security/parsers/set_cookie"
|
3
|
+
|
4
|
+
describe Parsers::SetCookie do
|
5
|
+
it "accepts 'name=value'" do
|
6
|
+
expect(subject.parse('foo=bar')).to be == [{cookie: {foo: 'bar'}}]
|
7
|
+
end
|
8
|
+
|
9
|
+
it "accepts 'name=value; Expires=...'" do
|
10
|
+
expires = "Wed, 09 Jun 2021 10:18:14 GMT"
|
11
|
+
|
12
|
+
expect(subject.parse("foo=bar; Expires=#{expires}")).to be == [{
|
13
|
+
cookie: {foo: 'bar'},
|
14
|
+
expires: Date.parse(expires)
|
15
|
+
}]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "accepts 'name=value; Path=...; Expires=...; Secure; Domain=...; HttpOnly'" do
|
19
|
+
path = '/accounts'
|
20
|
+
expires = "Wed, 09 Jun 2021 10:18:14 GMT"
|
21
|
+
domain = '.example.com'
|
22
|
+
|
23
|
+
expect(subject.parse("foo=bar; Path=#{path}; Expires=#{expires}; Secure; Domain=#{domain}; HttpOnly")).to be == [{
|
24
|
+
cookie: {foo: 'bar'},
|
25
|
+
path: path,
|
26
|
+
expires: Date.parse(expires),
|
27
|
+
secure: 'Secure',
|
28
|
+
domain: domain,
|
29
|
+
http_only: 'HttpOnly'
|
30
|
+
}]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "accepts multiple cookie values" do
|
34
|
+
path = '/'
|
35
|
+
domain = '.twitter.com'
|
36
|
+
expires = 'Sat, 19 Nov 2016 00:27:36 GMT'
|
37
|
+
|
38
|
+
expect(subject.parse("foo=bar; Path=#{path}; Domain=#{domain}; Secure; HTTPOnly, bar=baz; Domain=#{domain}; Path=#{path}; Expires=#{expires}")).to be == [
|
39
|
+
{
|
40
|
+
cookie: {foo: 'bar'},
|
41
|
+
path: path,
|
42
|
+
domain: domain,
|
43
|
+
secure: 'Secure',
|
44
|
+
http_only: 'HTTPOnly'
|
45
|
+
},
|
46
|
+
|
47
|
+
{
|
48
|
+
cookie: {bar: 'baz'},
|
49
|
+
domain: domain,
|
50
|
+
path: path,
|
51
|
+
expires: Date.parse(expires)
|
52
|
+
}
|
53
|
+
]
|
54
|
+
end
|
55
|
+
end
|