http-cookie 1.0.2 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +37 -0
- data/CHANGELOG.md +17 -0
- data/http-cookie.gemspec +5 -4
- data/lib/http/cookie/scanner.rb +12 -11
- data/lib/http/cookie/version.rb +1 -1
- data/lib/http/cookie.rb +1 -1
- data/lib/http/cookie_jar/abstract_store.rb +2 -2
- data/lib/http/cookie_jar/hash_store.rb +0 -2
- data/lib/http/cookie_jar/mozilla_store.rb +142 -19
- data/lib/http/cookie_jar/yaml_saver.rb +12 -2
- data/test/test_http_cookie.rb +30 -7
- data/test/test_http_cookie_jar.rb +13 -10
- metadata +26 -27
- data/.travis.yml +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5230b0bd44e032652855e7b9e60e3d994ca56adbd57550c7520930d4dbf734a4
|
4
|
+
data.tar.gz: 65240197f49ac57bac8c6f3d1104cfe4f8fff77e1ac992c05c72d74efbba8300
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fc5bb2e287d60d060c54eb9fb9ccb6d55c55e84ec35525deff8c088c873d6ac26db86f7f1cf3c03a7cbf05e397b6cd0e3a1e1171c2dcff8848e0345a34b0905
|
7
|
+
data.tar.gz: 1c85e07a65fac1d5440126bea27dbc01160edc9a791f56e021cd3142070eada54bf1ec3cda31c9d9273f23c3a84c8786c308bcdd27e03f7266c203dde4abdd6f
|
@@ -0,0 +1,37 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
pull_request:
|
8
|
+
branches:
|
9
|
+
- "*"
|
10
|
+
|
11
|
+
jobs:
|
12
|
+
test:
|
13
|
+
strategy:
|
14
|
+
fail-fast: false
|
15
|
+
matrix:
|
16
|
+
os: [ubuntu]
|
17
|
+
# We still kind of support Ruby 1.8.7
|
18
|
+
ruby: [2.7, "3.0", 3.1, head, jruby]
|
19
|
+
|
20
|
+
name: >-
|
21
|
+
${{matrix.os}}:ruby-${{matrix.ruby}}
|
22
|
+
runs-on: ${{matrix.os}}-latest
|
23
|
+
continue-on-error: ${{matrix.ruby == 'head' || matrix.ruby == 'jruby'}}
|
24
|
+
|
25
|
+
steps:
|
26
|
+
- name: Check out
|
27
|
+
uses: actions/checkout@v2
|
28
|
+
|
29
|
+
- name: Set up ruby and bundle
|
30
|
+
uses: ruby/setup-ruby@v1
|
31
|
+
with:
|
32
|
+
ruby-version: ${{matrix.ruby}}
|
33
|
+
bundler-cache: true
|
34
|
+
|
35
|
+
- name: Run rake
|
36
|
+
run: |
|
37
|
+
bundle exec rake
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
## 1.0.5 (2022-05-25)
|
2
|
+
|
3
|
+
- Silence SQLite3 warnings
|
4
|
+
|
5
|
+
## 1.0.4 (2021-06-07)
|
6
|
+
|
7
|
+
- Support Mozilla's cookie storage format up to version 7.
|
8
|
+
|
9
|
+
- Fix the time representation with creationTime and lastAccessed in
|
10
|
+
MozillaStore. (#8)
|
11
|
+
|
12
|
+
## 1.0.3 (2016-09-30)
|
13
|
+
|
14
|
+
- Treat comma as normal character in HTTP::Cookie.cookie_value_to_hash
|
15
|
+
instead of key-value pair separator. This should fix the problem
|
16
|
+
described in CVE-2016-7401.
|
17
|
+
|
1
18
|
## 1.0.2 (2013-09-10)
|
2
19
|
|
3
20
|
- Fix HTTP::Cookie.parse so that it does not raise ArgumentError
|
data/http-cookie.gemspec
CHANGED
@@ -25,10 +25,11 @@ Gem::Specification.new do |gem|
|
|
25
25
|
gem.extra_rdoc_files = ['README.md', 'LICENSE.txt']
|
26
26
|
|
27
27
|
gem.add_runtime_dependency("domain_name", ["~> 0.5"])
|
28
|
-
gem.add_development_dependency("sqlite3", ["~> 1.3
|
28
|
+
gem.add_development_dependency("sqlite3", ["~> 1.3"]) unless defined?(JRUBY_VERSION)
|
29
29
|
gem.add_development_dependency("bundler", [">= 1.2.0"])
|
30
|
-
gem.add_development_dependency("test-unit", [">= 2.4.3"])
|
31
|
-
gem.add_development_dependency("rake", [">= 0.9.2.2"])
|
32
|
-
gem.add_development_dependency("rdoc",
|
30
|
+
gem.add_development_dependency("test-unit", [">= 2.4.3", *("< 3" if RUBY_VERSION < "1.9")])
|
31
|
+
gem.add_development_dependency("rake", [">= 0.9.2.2", *("< 11" if RUBY_VERSION < "1.9")])
|
32
|
+
gem.add_development_dependency("rdoc", RUBY_VERSION > "1.9" ? "> 2.4.2" : "~> 2.4.2")
|
33
33
|
gem.add_development_dependency("simplecov", [">= 0"])
|
34
|
+
gem.add_development_dependency("json", ["< 2"]) if RUBY_VERSION < "2.0"
|
34
35
|
end
|
data/lib/http/cookie/scanner.rb
CHANGED
@@ -50,7 +50,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
50
50
|
}
|
51
51
|
end
|
52
52
|
|
53
|
-
def scan_value
|
53
|
+
def scan_value(comma_as_separator = false)
|
54
54
|
''.tap { |s|
|
55
55
|
case
|
56
56
|
when scan(/[^,;"]+/)
|
@@ -59,7 +59,9 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
59
59
|
# RFC 6265 2.2
|
60
60
|
# A cookie-value may be DQUOTE'd.
|
61
61
|
s << scan_dquoted
|
62
|
-
when check(
|
62
|
+
when check(/;/)
|
63
|
+
break
|
64
|
+
when comma_as_separator && check(RE_COOKIE_COMMA)
|
63
65
|
break
|
64
66
|
else
|
65
67
|
s << getch
|
@@ -68,12 +70,12 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
68
70
|
}
|
69
71
|
end
|
70
72
|
|
71
|
-
def scan_name_value
|
73
|
+
def scan_name_value(comma_as_separator = false)
|
72
74
|
name = scan_name
|
73
75
|
if skip(/\=/)
|
74
|
-
value = scan_value
|
76
|
+
value = scan_value(comma_as_separator)
|
75
77
|
else
|
76
|
-
scan_value
|
78
|
+
scan_value(comma_as_separator)
|
77
79
|
value = nil
|
78
80
|
end
|
79
81
|
[name, value]
|
@@ -159,7 +161,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
159
161
|
|
160
162
|
skip_wsp
|
161
163
|
|
162
|
-
name, value = scan_name_value
|
164
|
+
name, value = scan_name_value(true)
|
163
165
|
if value.nil?
|
164
166
|
@logger.warn("Cookie definition lacks a name-value pair.") if @logger
|
165
167
|
elsif name.empty?
|
@@ -176,7 +178,7 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
176
178
|
break
|
177
179
|
when skip(/;/)
|
178
180
|
skip_wsp
|
179
|
-
aname, avalue = scan_name_value
|
181
|
+
aname, avalue = scan_name_value(true)
|
180
182
|
next if aname.empty? || value.nil?
|
181
183
|
aname.downcase!
|
182
184
|
case aname
|
@@ -218,13 +220,12 @@ class HTTP::Cookie::Scanner < StringScanner
|
|
218
220
|
until eos?
|
219
221
|
skip_wsp
|
220
222
|
|
221
|
-
|
223
|
+
# Do not treat comma in a Cookie header value as separator; see CVE-2016-7401
|
224
|
+
name, value = scan_name_value(false)
|
222
225
|
|
223
226
|
yield name, value if value
|
224
227
|
|
225
|
-
|
226
|
-
# values of a header.
|
227
|
-
skip(/[;,]/)
|
228
|
+
skip(/;/)
|
228
229
|
end
|
229
230
|
end
|
230
231
|
end
|
data/lib/http/cookie/version.rb
CHANGED
data/lib/http/cookie.rb
CHANGED
@@ -128,7 +128,7 @@ class HTTP::Cookie
|
|
128
128
|
# new("name" => "uid", "value" => "a12345", "Domain" => 'www.example.org')
|
129
129
|
#
|
130
130
|
def initialize(*args)
|
131
|
-
@origin = @domain = @path =
|
131
|
+
@name = @origin = @domain = @path =
|
132
132
|
@expires = @max_age = nil
|
133
133
|
@for_domain = @secure = @httponly = false
|
134
134
|
@session = true
|
@@ -17,8 +17,8 @@ class HTTP::CookieJar::AbstractStore
|
|
17
17
|
begin
|
18
18
|
require 'http/cookie_jar/%s_store' % symbol
|
19
19
|
@@class_map.fetch(symbol)
|
20
|
-
rescue LoadError, IndexError
|
21
|
-
raise IndexError, 'cookie store unavailable: %s' % symbol.inspect
|
20
|
+
rescue LoadError, IndexError => e
|
21
|
+
raise IndexError, 'cookie store unavailable: %s, error: %s' % symbol.inspect, e.message
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -67,10 +67,8 @@ class HTTP::CookieJar
|
|
67
67
|
def each(uri = nil) # :yield: cookie
|
68
68
|
now = Time.now
|
69
69
|
if uri
|
70
|
-
thost = DomainName.new(uri.host)
|
71
70
|
tpath = uri.path
|
72
71
|
@jar.each { |domain, paths|
|
73
|
-
next unless thost.cookie_domain?(domain)
|
74
72
|
paths.each { |path, hash|
|
75
73
|
next unless HTTP::Cookie.path_match?(path, tpath)
|
76
74
|
hash.delete_if { |name, cookie|
|
@@ -10,7 +10,7 @@ class HTTP::CookieJar
|
|
10
10
|
# stored persistently in the SQLite3 database.
|
11
11
|
class MozillaStore < AbstractStore
|
12
12
|
# :stopdoc:
|
13
|
-
SCHEMA_VERSION =
|
13
|
+
SCHEMA_VERSION = 7
|
14
14
|
|
15
15
|
def default_options
|
16
16
|
{
|
@@ -22,14 +22,11 @@ class HTTP::CookieJar
|
|
22
22
|
|
23
23
|
ALL_COLUMNS = %w[
|
24
24
|
baseDomain
|
25
|
-
|
25
|
+
originAttributes
|
26
26
|
name value
|
27
27
|
host path
|
28
28
|
expiry creationTime lastAccessed
|
29
29
|
isSecure isHttpOnly
|
30
|
-
]
|
31
|
-
UK_COLUMNS = %w[
|
32
|
-
name host path
|
33
30
|
appId inBrowserElement
|
34
31
|
]
|
35
32
|
|
@@ -95,6 +92,11 @@ class HTTP::CookieJar
|
|
95
92
|
def initialize(options = nil)
|
96
93
|
super
|
97
94
|
|
95
|
+
@origin_attributes = encode_www_form({}.tap { |params|
|
96
|
+
params['appId'] = @app_id if @app_id.nonzero?
|
97
|
+
params['inBrowserElement'] = 1 if @in_browser_element
|
98
|
+
})
|
99
|
+
|
98
100
|
@filename = options[:filename] or raise ArgumentError, ':filename option is missing'
|
99
101
|
|
100
102
|
@sjar = HTTP::CookieJar::HashStore.new
|
@@ -134,7 +136,7 @@ class HTTP::CookieJar
|
|
134
136
|
|
135
137
|
# Returns the schema version of the database.
|
136
138
|
def schema_version
|
137
|
-
@schema_version ||= @db.execute("PRAGMA user_version").first[
|
139
|
+
@schema_version ||= @db.execute("PRAGMA user_version").first["user_version"]
|
138
140
|
rescue SQLite3::SQLException
|
139
141
|
@logger.warn "couldn't get schema version!" if @logger
|
140
142
|
return nil
|
@@ -147,8 +149,8 @@ class HTTP::CookieJar
|
|
147
149
|
@schema_version = version
|
148
150
|
end
|
149
151
|
|
150
|
-
def
|
151
|
-
self.schema_version =
|
152
|
+
def create_table_v5
|
153
|
+
self.schema_version = 5
|
152
154
|
@db.execute("DROP TABLE IF EXISTS moz_cookies")
|
153
155
|
@db.execute(<<-'SQL')
|
154
156
|
CREATE TABLE moz_cookies (
|
@@ -176,6 +178,62 @@ class HTTP::CookieJar
|
|
176
178
|
SQL
|
177
179
|
end
|
178
180
|
|
181
|
+
def create_table_v6
|
182
|
+
self.schema_version = 6
|
183
|
+
@db.execute("DROP TABLE IF EXISTS moz_cookies")
|
184
|
+
@db.execute(<<-'SQL')
|
185
|
+
CREATE TABLE moz_cookies (
|
186
|
+
id INTEGER PRIMARY KEY,
|
187
|
+
baseDomain TEXT,
|
188
|
+
originAttributes TEXT NOT NULL DEFAULT '',
|
189
|
+
name TEXT,
|
190
|
+
value TEXT,
|
191
|
+
host TEXT,
|
192
|
+
path TEXT,
|
193
|
+
expiry INTEGER,
|
194
|
+
lastAccessed INTEGER,
|
195
|
+
creationTime INTEGER,
|
196
|
+
isSecure INTEGER,
|
197
|
+
isHttpOnly INTEGER,
|
198
|
+
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)
|
199
|
+
)
|
200
|
+
SQL
|
201
|
+
@db.execute(<<-'SQL')
|
202
|
+
CREATE INDEX moz_basedomain
|
203
|
+
ON moz_cookies (baseDomain,
|
204
|
+
originAttributes);
|
205
|
+
SQL
|
206
|
+
end
|
207
|
+
|
208
|
+
def create_table
|
209
|
+
self.schema_version = SCHEMA_VERSION
|
210
|
+
@db.execute("DROP TABLE IF EXISTS moz_cookies")
|
211
|
+
@db.execute(<<-'SQL')
|
212
|
+
CREATE TABLE moz_cookies (
|
213
|
+
id INTEGER PRIMARY KEY,
|
214
|
+
baseDomain TEXT,
|
215
|
+
originAttributes TEXT NOT NULL DEFAULT '',
|
216
|
+
name TEXT,
|
217
|
+
value TEXT,
|
218
|
+
host TEXT,
|
219
|
+
path TEXT,
|
220
|
+
expiry INTEGER,
|
221
|
+
lastAccessed INTEGER,
|
222
|
+
creationTime INTEGER,
|
223
|
+
isSecure INTEGER,
|
224
|
+
isHttpOnly INTEGER,
|
225
|
+
appId INTEGER DEFAULT 0,
|
226
|
+
inBrowserElement INTEGER DEFAULT 0,
|
227
|
+
CONSTRAINT moz_uniqueid UNIQUE (name, host, path, originAttributes)
|
228
|
+
)
|
229
|
+
SQL
|
230
|
+
@db.execute(<<-'SQL')
|
231
|
+
CREATE INDEX moz_basedomain
|
232
|
+
ON moz_cookies (baseDomain,
|
233
|
+
originAttributes);
|
234
|
+
SQL
|
235
|
+
end
|
236
|
+
|
179
237
|
def db_prepare(sql)
|
180
238
|
st = @db.prepare(sql)
|
181
239
|
yield st
|
@@ -226,7 +284,7 @@ class HTTP::CookieJar
|
|
226
284
|
when 4
|
227
285
|
@db.execute("ALTER TABLE moz_cookies RENAME TO moz_cookies_old")
|
228
286
|
@db.execute("DROP INDEX moz_basedomain")
|
229
|
-
|
287
|
+
create_table_v5
|
230
288
|
@db.execute(<<-'SQL')
|
231
289
|
INSERT INTO moz_cookies
|
232
290
|
(baseDomain, appId, inBrowserElement, name, value, host, path, expiry,
|
@@ -236,7 +294,42 @@ class HTTP::CookieJar
|
|
236
294
|
FROM moz_cookies_old
|
237
295
|
SQL
|
238
296
|
@db.execute("DROP TABLE moz_cookies_old")
|
297
|
+
when 5
|
298
|
+
@db.execute("ALTER TABLE moz_cookies RENAME TO moz_cookies_old")
|
299
|
+
@db.execute("DROP INDEX moz_basedomain")
|
300
|
+
create_table_v6
|
301
|
+
@db.create_function('CONVERT_TO_ORIGIN_ATTRIBUTES', 2) { |func, appId, inBrowserElement|
|
302
|
+
params = {}
|
303
|
+
params['appId'] = appId if appId.nonzero?
|
304
|
+
params['inBrowserElement'] = inBrowserElement if inBrowserElement.nonzero?
|
305
|
+
func.result = encode_www_form(params)
|
306
|
+
}
|
307
|
+
@db.execute(<<-'SQL')
|
308
|
+
INSERT INTO moz_cookies
|
309
|
+
(baseDomain, originAttributes, name, value, host, path, expiry,
|
310
|
+
lastAccessed, creationTime, isSecure, isHttpOnly)
|
311
|
+
SELECT baseDomain,
|
312
|
+
CONVERT_TO_ORIGIN_ATTRIBUTES(appId, inBrowserElement),
|
313
|
+
name, value, host, path, expiry, lastAccessed, creationTime,
|
314
|
+
isSecure, isHttpOnly
|
315
|
+
FROM moz_cookies_old
|
316
|
+
SQL
|
317
|
+
@db.execute("DROP TABLE moz_cookies_old")
|
318
|
+
when 6
|
319
|
+
@db.execute("ALTER TABLE moz_cookies ADD appId INTEGER DEFAULT 0")
|
320
|
+
@db.execute("ALTER TABLE moz_cookies ADD inBrowserElement INTEGER DEFAULT 0")
|
321
|
+
@db.create_function('SET_APP_ID', 1) { |func, originAttributes|
|
322
|
+
func.result = get_query_param(originAttributes, 'appId').to_i # nil.to_i == 0
|
323
|
+
}
|
324
|
+
@db.create_function('SET_IN_BROWSER', 1) { |func, originAttributes|
|
325
|
+
func.result = get_query_param(originAttributes, 'inBrowserElement').to_i # nil.to_i == 0
|
326
|
+
}
|
327
|
+
@db.execute(<<-'SQL')
|
328
|
+
UPDATE moz_cookies SET appId = SET_APP_ID(originAttributes),
|
329
|
+
inBrowserElement = SET_IN_BROWSER(originAttributes)
|
330
|
+
SQL
|
239
331
|
@logger.info("Upgraded database to schema version %d" % schema_version) if @logger
|
332
|
+
self.schema_version += 1
|
240
333
|
else
|
241
334
|
break
|
242
335
|
end
|
@@ -259,16 +352,17 @@ class HTTP::CookieJar
|
|
259
352
|
def db_add(cookie)
|
260
353
|
@stmt[:add].execute({
|
261
354
|
:baseDomain => cookie.domain_name.domain || cookie.domain,
|
262
|
-
:
|
263
|
-
:inBrowserElement => @in_browser_element ? 1 : 0,
|
355
|
+
:originAttributes => @origin_attributes,
|
264
356
|
:name => cookie.name, :value => cookie.value,
|
265
357
|
:host => cookie.dot_domain,
|
266
358
|
:path => cookie.path,
|
267
359
|
:expiry => cookie.expires_at.to_i,
|
268
|
-
:creationTime => cookie.created_at
|
269
|
-
:lastAccessed => cookie.accessed_at
|
360
|
+
:creationTime => serialize_usectime(cookie.created_at),
|
361
|
+
:lastAccessed => serialize_usectime(cookie.accessed_at),
|
270
362
|
:isSecure => cookie.secure? ? 1 : 0,
|
271
363
|
:isHttpOnly => cookie.httponly? ? 1 : 0,
|
364
|
+
:appId => @app_id,
|
365
|
+
:inBrowserElement => @in_browser_element ? 1 : 0,
|
272
366
|
})
|
273
367
|
cleanup if (@gc_index += 1) >= @gc_threshold
|
274
368
|
|
@@ -295,6 +389,36 @@ class HTTP::CookieJar
|
|
295
389
|
self
|
296
390
|
end
|
297
391
|
|
392
|
+
if RUBY_VERSION >= '1.9'
|
393
|
+
def encode_www_form(enum)
|
394
|
+
URI.encode_www_form(enum)
|
395
|
+
end
|
396
|
+
|
397
|
+
def get_query_param(str, key)
|
398
|
+
URI.decode_www_form(str).find { |k, v|
|
399
|
+
break v if k == key
|
400
|
+
}
|
401
|
+
end
|
402
|
+
else
|
403
|
+
require 'cgi'
|
404
|
+
|
405
|
+
def encode_www_form(enum)
|
406
|
+
enum.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v)}" }.join('&')
|
407
|
+
end
|
408
|
+
|
409
|
+
def get_query_param(str, key)
|
410
|
+
CGI.parse(str)[key].first
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
def serialize_usectime(time)
|
415
|
+
time ? (time.to_f * 1e6).floor : 0
|
416
|
+
end
|
417
|
+
|
418
|
+
def deserialize_usectime(value)
|
419
|
+
Time.at(value ? value / 1e6 : 0)
|
420
|
+
end
|
421
|
+
|
298
422
|
public
|
299
423
|
|
300
424
|
def add(cookie)
|
@@ -337,7 +461,6 @@ class HTTP::CookieJar
|
|
337
461
|
now = Time.now
|
338
462
|
if uri
|
339
463
|
thost = DomainName.new(uri.host)
|
340
|
-
tpath = uri.path
|
341
464
|
|
342
465
|
@stmt[:cookies_for_domain].execute({
|
343
466
|
:baseDomain => thost.domain || thost.hostname,
|
@@ -355,8 +478,8 @@ class HTTP::CookieJar
|
|
355
478
|
attrs[:domain] = row['host']
|
356
479
|
attrs[:path] = row['path']
|
357
480
|
attrs[:expires_at] = Time.at(row['expiry'])
|
358
|
-
attrs[:accessed_at] =
|
359
|
-
attrs[:created_at] =
|
481
|
+
attrs[:accessed_at] = deserialize_usectime(row['lastAccessed'])
|
482
|
+
attrs[:created_at] = deserialize_usectime(row['creationTime'])
|
360
483
|
attrs[:secure] = secure
|
361
484
|
attrs[:httponly] = row['isHttpOnly'] != 0
|
362
485
|
})
|
@@ -364,7 +487,7 @@ class HTTP::CookieJar
|
|
364
487
|
if cookie.valid_for_uri?(uri)
|
365
488
|
cookie.accessed_at = now
|
366
489
|
@stmt[:update_lastaccessed].execute({
|
367
|
-
'lastAccessed' => now
|
490
|
+
'lastAccessed' => serialize_usectime(now),
|
368
491
|
'id' => row['id'],
|
369
492
|
})
|
370
493
|
yield cookie
|
@@ -383,8 +506,8 @@ class HTTP::CookieJar
|
|
383
506
|
attrs[:domain] = row['host']
|
384
507
|
attrs[:path] = row['path']
|
385
508
|
attrs[:expires_at] = Time.at(row['expiry'])
|
386
|
-
attrs[:accessed_at] =
|
387
|
-
attrs[:created_at] =
|
509
|
+
attrs[:accessed_at] = deserialize_usectime(row['lastAccessed'])
|
510
|
+
attrs[:created_at] = deserialize_usectime(row['creationTime'])
|
388
511
|
attrs[:secure] = row['isSecure'] != 0
|
389
512
|
attrs[:httponly] = row['isHttpOnly'] != 0
|
390
513
|
})
|
@@ -21,7 +21,7 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
21
21
|
|
22
22
|
def load(io, jar)
|
23
23
|
begin
|
24
|
-
data =
|
24
|
+
data = load_yaml(io)
|
25
25
|
rescue ArgumentError => e
|
26
26
|
case e.message
|
27
27
|
when %r{\Aundefined class/module Mechanize::}
|
@@ -31,7 +31,7 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
31
31
|
yaml = io.read
|
32
32
|
# a gross hack
|
33
33
|
yaml.gsub!(%r{^( [^ ].*:) !ruby/object:Mechanize::Cookie$}, "\\1")
|
34
|
-
data =
|
34
|
+
data = load_yaml(yaml)
|
35
35
|
rescue Errno::ESPIPE
|
36
36
|
@logger.warn "could not rewind the stream for conversion" if @logger
|
37
37
|
rescue ArgumentError
|
@@ -73,4 +73,14 @@ class HTTP::CookieJar::YAMLSaver < HTTP::CookieJar::AbstractSaver
|
|
73
73
|
def default_options
|
74
74
|
{}
|
75
75
|
end
|
76
|
+
|
77
|
+
if YAML.name == 'Psych' && Psych::VERSION >= '3.1'
|
78
|
+
def load_yaml(yaml)
|
79
|
+
YAML.safe_load(yaml, :permitted_classes => %w[Time HTTP::Cookie Mechanize::Cookie DomainName], :aliases => true)
|
80
|
+
end
|
81
|
+
else
|
82
|
+
def load_yaml(yaml)
|
83
|
+
YAML.load(yaml)
|
84
|
+
end
|
85
|
+
end
|
76
86
|
end
|
data/test/test_http_cookie.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require File.expand_path('helper', File.dirname(__FILE__))
|
3
|
+
require 'psych' if !defined?(YAML) && RUBY_VERSION == "1.9.2"
|
4
|
+
require 'yaml'
|
3
5
|
|
4
6
|
class TestHTTPCookie < Test::Unit::TestCase
|
5
7
|
def setup
|
@@ -441,17 +443,28 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
441
443
|
['Bar', 'value 2'],
|
442
444
|
['Baz', 'value3'],
|
443
445
|
['Bar', 'value"4'],
|
446
|
+
['Quux', 'x, value=5'],
|
444
447
|
]
|
445
448
|
|
446
449
|
cookie_value = HTTP::Cookie.cookie_value(pairs.map { |name, value|
|
447
450
|
HTTP::Cookie.new(:name => name, :value => value)
|
448
451
|
})
|
449
452
|
|
450
|
-
assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"', cookie_value
|
453
|
+
assert_equal 'Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"; Quux="x, value=5"', cookie_value
|
451
454
|
|
452
455
|
hash = HTTP::Cookie.cookie_value_to_hash(cookie_value)
|
453
456
|
|
454
|
-
assert_equal
|
457
|
+
assert_equal pairs.map(&:first).uniq.size, hash.size
|
458
|
+
|
459
|
+
hash.each_pair { |name, value|
|
460
|
+
_, pvalue = pairs.assoc(name)
|
461
|
+
assert_equal pvalue, value
|
462
|
+
}
|
463
|
+
|
464
|
+
# Do not treat comma in a Cookie header value as separator; see CVE-2016-7401
|
465
|
+
hash = HTTP::Cookie.cookie_value_to_hash('Quux=x, value=5; Foo=value1; Bar="value 2"; Baz=value3; Bar="value\\"4"')
|
466
|
+
|
467
|
+
assert_equal pairs.map(&:first).uniq.size, hash.size
|
455
468
|
|
456
469
|
hash.each_pair { |name, value|
|
457
470
|
_, pvalue = pairs.assoc(name)
|
@@ -1062,6 +1075,16 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
1062
1075
|
}
|
1063
1076
|
end
|
1064
1077
|
|
1078
|
+
if YAML.name == 'Psych' && Psych::VERSION >= '3.1'
|
1079
|
+
private def load_yaml(yaml)
|
1080
|
+
YAML.safe_load(yaml, :permitted_classes => %w[Time HTTP::Cookie Mechanize::Cookie DomainName], :aliases => true)
|
1081
|
+
end
|
1082
|
+
else
|
1083
|
+
private def load_yaml(yaml)
|
1084
|
+
YAML.load(yaml)
|
1085
|
+
end
|
1086
|
+
end
|
1087
|
+
|
1065
1088
|
def test_yaml_expires
|
1066
1089
|
require 'yaml'
|
1067
1090
|
cookie = HTTP::Cookie.new(cookie_values)
|
@@ -1069,29 +1092,29 @@ class TestHTTPCookie < Test::Unit::TestCase
|
|
1069
1092
|
assert_equal false, cookie.session?
|
1070
1093
|
assert_equal nil, cookie.max_age
|
1071
1094
|
|
1072
|
-
ycookie =
|
1095
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1073
1096
|
assert_equal false, ycookie.session?
|
1074
1097
|
assert_equal nil, ycookie.max_age
|
1075
1098
|
assert_in_delta cookie.expires, ycookie.expires, 1
|
1076
1099
|
|
1077
1100
|
cookie.expires = nil
|
1078
|
-
ycookie =
|
1101
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1079
1102
|
assert_equal true, ycookie.session?
|
1080
1103
|
assert_equal nil, ycookie.max_age
|
1081
1104
|
|
1082
1105
|
cookie.expires = Time.now + 3600
|
1083
|
-
ycookie =
|
1106
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1084
1107
|
assert_equal false, ycookie.session?
|
1085
1108
|
assert_equal nil, ycookie.max_age
|
1086
1109
|
assert_in_delta cookie.expires, ycookie.expires, 1
|
1087
1110
|
|
1088
1111
|
cookie.max_age = 3600
|
1089
|
-
ycookie =
|
1112
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1090
1113
|
assert_equal false, ycookie.session?
|
1091
1114
|
assert_in_delta cookie.created_at + 3600, ycookie.expires, 1
|
1092
1115
|
|
1093
1116
|
cookie.max_age = nil
|
1094
|
-
ycookie =
|
1117
|
+
ycookie = load_yaml(cookie.to_yaml)
|
1095
1118
|
assert_equal true, ycookie.session?
|
1096
1119
|
assert_equal nil, ycookie.expires
|
1097
1120
|
end
|
@@ -20,11 +20,7 @@ module TestHTTPCookieJar
|
|
20
20
|
assert_raises(NameError) {
|
21
21
|
HTTP::CookieJar::ErroneousStore
|
22
22
|
}
|
23
|
-
|
24
|
-
assert_includes $LOADED_FEATURES, rb
|
25
|
-
else
|
26
|
-
assert_includes $LOADED_FEATURES, rb[(dir.size + 1)..-1]
|
27
|
-
end
|
23
|
+
assert($LOADED_FEATURES.any? { |file| FileTest.identical?(file, rb) })
|
28
24
|
}
|
29
25
|
end
|
30
26
|
|
@@ -45,11 +41,7 @@ module TestHTTPCookieJar
|
|
45
41
|
assert_raises(NameError) {
|
46
42
|
HTTP::CookieJar::ErroneousSaver
|
47
43
|
}
|
48
|
-
|
49
|
-
assert_includes $LOADED_FEATURES, rb
|
50
|
-
else
|
51
|
-
assert_includes $LOADED_FEATURES, rb[(dir.size + 1)..-1]
|
52
|
-
end
|
44
|
+
assert($LOADED_FEATURES.any? { |file| FileTest.identical?(file, rb) })
|
53
45
|
}
|
54
46
|
end
|
55
47
|
end
|
@@ -139,6 +131,17 @@ module TestHTTPCookieJar
|
|
139
131
|
assert_equal(0, @jar.cookies(URI('http://www.rubyforge.org/')).length)
|
140
132
|
end
|
141
133
|
|
134
|
+
def test_host_only_with_unqualified_hostname
|
135
|
+
@jar.add(HTTP::Cookie.new(cookie_values(
|
136
|
+
:origin => 'http://localhost/', :domain => 'localhost', :for_domain => false)))
|
137
|
+
|
138
|
+
assert_equal(1, @jar.cookies(URI('http://localhost/')).length)
|
139
|
+
|
140
|
+
assert_equal(1, @jar.cookies(URI('http://Localhost/')).length)
|
141
|
+
|
142
|
+
assert_equal(1, @jar.cookies(URI('https://Localhost/')).length)
|
143
|
+
end
|
144
|
+
|
142
145
|
def test_empty_value
|
143
146
|
url = URI 'http://rubyforge.org/'
|
144
147
|
values = cookie_values(:value => "")
|
metadata
CHANGED
@@ -1,114 +1,114 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http-cookie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akinori MUSHA
|
8
8
|
- Aaron Patterson
|
9
9
|
- Eric Hodel
|
10
10
|
- Mike Dalessio
|
11
|
-
autorequire:
|
11
|
+
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2022-05-25 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: domain_name
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
|
-
- - ~>
|
20
|
+
- - "~>"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '0.5'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- - ~>
|
27
|
+
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0.5'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: sqlite3
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
-
- - ~>
|
34
|
+
- - "~>"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: 1.3
|
36
|
+
version: '1.3'
|
37
37
|
type: :development
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- - ~>
|
41
|
+
- - "~>"
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 1.3
|
43
|
+
version: '1.3'
|
44
44
|
- !ruby/object:Gem::Dependency
|
45
45
|
name: bundler
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
|
-
- -
|
48
|
+
- - ">="
|
49
49
|
- !ruby/object:Gem::Version
|
50
50
|
version: 1.2.0
|
51
51
|
type: :development
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
|
-
- -
|
55
|
+
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: 1.2.0
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: test-unit
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
61
61
|
requirements:
|
62
|
-
- -
|
62
|
+
- - ">="
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: 2.4.3
|
65
65
|
type: :development
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
|
-
- -
|
69
|
+
- - ">="
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: 2.4.3
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
73
|
name: rake
|
74
74
|
requirement: !ruby/object:Gem::Requirement
|
75
75
|
requirements:
|
76
|
-
- -
|
76
|
+
- - ">="
|
77
77
|
- !ruby/object:Gem::Version
|
78
78
|
version: 0.9.2.2
|
79
79
|
type: :development
|
80
80
|
prerelease: false
|
81
81
|
version_requirements: !ruby/object:Gem::Requirement
|
82
82
|
requirements:
|
83
|
-
- -
|
83
|
+
- - ">="
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: 0.9.2.2
|
86
86
|
- !ruby/object:Gem::Dependency
|
87
87
|
name: rdoc
|
88
88
|
requirement: !ruby/object:Gem::Requirement
|
89
89
|
requirements:
|
90
|
-
- -
|
90
|
+
- - ">"
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: 2.4.2
|
93
93
|
type: :development
|
94
94
|
prerelease: false
|
95
95
|
version_requirements: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
|
-
- -
|
97
|
+
- - ">"
|
98
98
|
- !ruby/object:Gem::Version
|
99
99
|
version: 2.4.2
|
100
100
|
- !ruby/object:Gem::Dependency
|
101
101
|
name: simplecov
|
102
102
|
requirement: !ruby/object:Gem::Requirement
|
103
103
|
requirements:
|
104
|
-
- -
|
104
|
+
- - ">="
|
105
105
|
- !ruby/object:Gem::Version
|
106
106
|
version: '0'
|
107
107
|
type: :development
|
108
108
|
prerelease: false
|
109
109
|
version_requirements: !ruby/object:Gem::Requirement
|
110
110
|
requirements:
|
111
|
-
- -
|
111
|
+
- - ">="
|
112
112
|
- !ruby/object:Gem::Version
|
113
113
|
version: '0'
|
114
114
|
description: HTTP::Cookie is a Ruby library to handle HTTP Cookies based on RFC 6265. It
|
@@ -127,8 +127,8 @@ extra_rdoc_files:
|
|
127
127
|
- README.md
|
128
128
|
- LICENSE.txt
|
129
129
|
files:
|
130
|
-
- .
|
131
|
-
- .
|
130
|
+
- ".github/workflows/ci.yml"
|
131
|
+
- ".gitignore"
|
132
132
|
- CHANGELOG.md
|
133
133
|
- Gemfile
|
134
134
|
- LICENSE.txt
|
@@ -156,24 +156,23 @@ homepage: https://github.com/sparklemotion/http-cookie
|
|
156
156
|
licenses:
|
157
157
|
- MIT
|
158
158
|
metadata: {}
|
159
|
-
post_install_message:
|
159
|
+
post_install_message:
|
160
160
|
rdoc_options: []
|
161
161
|
require_paths:
|
162
162
|
- lib
|
163
163
|
required_ruby_version: !ruby/object:Gem::Requirement
|
164
164
|
requirements:
|
165
|
-
- -
|
165
|
+
- - ">="
|
166
166
|
- !ruby/object:Gem::Version
|
167
167
|
version: '0'
|
168
168
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
169
|
requirements:
|
170
|
-
- -
|
170
|
+
- - ">="
|
171
171
|
- !ruby/object:Gem::Version
|
172
172
|
version: '0'
|
173
173
|
requirements: []
|
174
|
-
|
175
|
-
|
176
|
-
signing_key:
|
174
|
+
rubygems_version: 3.3.14
|
175
|
+
signing_key:
|
177
176
|
specification_version: 4
|
178
177
|
summary: A Ruby library to handle HTTP Cookies based on RFC 6265
|
179
178
|
test_files:
|
data/.travis.yml
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
language: ruby
|
2
|
-
rvm:
|
3
|
-
- 1.8.7
|
4
|
-
- ree
|
5
|
-
- 1.9.3
|
6
|
-
- 2.0.0
|
7
|
-
- ruby-head
|
8
|
-
- jruby-18mode
|
9
|
-
- jruby-19mode
|
10
|
-
- jruby-head
|
11
|
-
- rbx-18mode
|
12
|
-
- rbx-19mode
|
13
|
-
matrix:
|
14
|
-
allow_failures:
|
15
|
-
- rvm: ruby-head
|
16
|
-
- rvm: rbx-18mode
|
17
|
-
- rvm: rbx-19mode
|