cookiejar_of_greed 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/cookiejar_of_greed.rb +2 -0
- data/lib/greed.rb +7 -0
- data/lib/greed/cookie.rb +33 -0
- data/lib/greed/cookie/domain_handler.rb +72 -0
- data/lib/greed/cookie/error.rb +7 -0
- data/lib/greed/cookie/expiration_handler.rb +29 -0
- data/lib/greed/cookie/iterator.rb +40 -0
- data/lib/greed/cookie/jar.rb +168 -0
- data/lib/greed/cookie/parser.rb +107 -0
- data/lib/greed/cookie/path_handler.rb +50 -0
- data/lib/greed/cookie/version.rb +7 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c7fed7210e10cc3b9c36b720a812aebf97c55a45c5a270dfd9d2e66ae9f4f1b3
|
4
|
+
data.tar.gz: 441f3d672b874199e0e13ab9e6c5b45ec9d967983cf3bd8d5c974dd882246e3e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c17fa636869e11c82b67473268e7945519c454fb1342696a02b9780d3c7b49cd0f7ae31e9fa7695aae2c71c39ad9a26f992390569df9bfa770f1ca2c48caef18
|
7
|
+
data.tar.gz: d19d1243dcf32fc5e427ed606517ead882177a5a5035c77146469cfe903d673e2e1108d564f3a08f1415003a525be0d2287e45a2ee83530840af9b750a47f5d0
|
data/lib/greed.rb
ADDED
data/lib/greed/cookie.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/dependencies/autoload'
|
3
|
+
require_relative './cookie/version'
|
4
|
+
|
5
|
+
module Greed
|
6
|
+
module Cookie
|
7
|
+
extend ::ActiveSupport::Autoload
|
8
|
+
|
9
|
+
autoload :Error
|
10
|
+
autoload :Iterator
|
11
|
+
autoload :Jar
|
12
|
+
autoload :Parser
|
13
|
+
|
14
|
+
'greed/cookie/expiration_handler'.tap do |load_path|
|
15
|
+
autoload :ExpirationHandler
|
16
|
+
autoload :ExpirationError, load_path
|
17
|
+
autoload :Expired, load_path
|
18
|
+
end
|
19
|
+
|
20
|
+
'greed/cookie/domain_handler'.tap do |load_path|
|
21
|
+
autoload :DomainHandler
|
22
|
+
autoload :DomainError, load_path
|
23
|
+
autoload :CrossDomainViolation, load_path
|
24
|
+
autoload :MalformedCookieDomain, load_path
|
25
|
+
end
|
26
|
+
|
27
|
+
'greed/cookie/path_handler'.tap do |load_path|
|
28
|
+
autoload :PathHandler
|
29
|
+
autoload :PathError, load_path
|
30
|
+
autoload :PathViolation, load_path
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'ipaddr'
|
4
|
+
require 'public_suffix'
|
5
|
+
|
6
|
+
module Greed
|
7
|
+
module Cookie
|
8
|
+
class DomainError < Error
|
9
|
+
end
|
10
|
+
class CrossDomainViolation < DomainError
|
11
|
+
end
|
12
|
+
class MalformedCookieDomain < DomainError
|
13
|
+
end
|
14
|
+
|
15
|
+
class DomainHandler
|
16
|
+
def determine_domain(document_domain, cookie_domain)
|
17
|
+
document_domain = document_domain.downcase
|
18
|
+
unless cookie_domain.present?
|
19
|
+
return {
|
20
|
+
domain: document_domain, # cookie domain not present
|
21
|
+
include_subdomains: false
|
22
|
+
}
|
23
|
+
end
|
24
|
+
document_ip_address = begin
|
25
|
+
::IPAddr.new(document_domain)
|
26
|
+
rescue ::IPAddr::Error
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
if document_ip_address
|
30
|
+
# handles IP Addresses
|
31
|
+
cookie_ip_address = begin
|
32
|
+
::IPAddr.new(cookie_domain)
|
33
|
+
rescue ::IPAddr::Error
|
34
|
+
raise CrossDomainViolation
|
35
|
+
end
|
36
|
+
raise CrossDomainViolation unless cookie_ip_address == document_ip_address
|
37
|
+
return {
|
38
|
+
domain: cookie_ip_address.to_s, # normalized
|
39
|
+
include_subdomains: false
|
40
|
+
}
|
41
|
+
end
|
42
|
+
cookie_domain = cookie_domain.downcase
|
43
|
+
# ignore leading dot
|
44
|
+
matched_data = /\A\s*\.?(?!\.)(\S+)\s*\z/.match(cookie_domain)
|
45
|
+
raise MalformedCookieDomain unless matched_data
|
46
|
+
cookie_domain = matched_data[1]
|
47
|
+
if document_domain == cookie_domain
|
48
|
+
# exact domain matched
|
49
|
+
return {
|
50
|
+
domain: document_domain,
|
51
|
+
include_subdomains: true
|
52
|
+
}
|
53
|
+
end
|
54
|
+
# prevent setting cookie on a top level domain
|
55
|
+
# "localhost" use cases should already ruled out with the exact domain match condition
|
56
|
+
raise CrossDomainViolation unless ::PublicSuffix.valid?(cookie_domain, ignore_private: true)
|
57
|
+
# prevent parent domain from setting cookie of a subdomain
|
58
|
+
raise CrossDomainViolation unless (document_domain[
|
59
|
+
document_domain.size - cookie_domain.size,
|
60
|
+
cookie_domain.size
|
61
|
+
] == cookie_domain) && \
|
62
|
+
(document_domain[
|
63
|
+
document_domain.size - cookie_domain.size - 1
|
64
|
+
] == ?.)
|
65
|
+
{
|
66
|
+
domain: cookie_domain, # set cookie for its parent domain
|
67
|
+
include_subdomains: true
|
68
|
+
}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/core_ext/time'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
module Greed
|
6
|
+
module Cookie
|
7
|
+
class ExpirationError < Error
|
8
|
+
end
|
9
|
+
class Expired < ExpirationError
|
10
|
+
end
|
11
|
+
|
12
|
+
class ExpirationHandler
|
13
|
+
def calculate_expiration(current_time, max_age, expires)
|
14
|
+
{
|
15
|
+
expires: if max_age
|
16
|
+
current_time + max_age.seconds
|
17
|
+
else
|
18
|
+
expires
|
19
|
+
end,
|
20
|
+
retrieved_at: current_time,
|
21
|
+
}.tap do |tapped|
|
22
|
+
tapped_expires = tapped[:expires]
|
23
|
+
return tapped unless tapped_expires # keep session cookie
|
24
|
+
raise Expired unless (current_time < tapped_expires) # reject expired cookie
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'public_suffix'
|
4
|
+
require 'strscan'
|
5
|
+
|
6
|
+
module Greed
|
7
|
+
module Cookie
|
8
|
+
module Iterator
|
9
|
+
private
|
10
|
+
|
11
|
+
def iterate_cookie_domain(domain_name)
|
12
|
+
chunk_scanner = /\A[-_\w\d]+\./
|
13
|
+
::Enumerator.new do |yielder|
|
14
|
+
scanner = ::StringScanner.new(domain_name.downcase)
|
15
|
+
until scanner.eos?
|
16
|
+
removed_part = scanner.scan(chunk_scanner)
|
17
|
+
break unless removed_part
|
18
|
+
yielder << scanner.rest
|
19
|
+
end
|
20
|
+
end.lazy.take_while do |parent_domain|
|
21
|
+
::PublicSuffix.valid?(parent_domain, ignore_private: true)
|
22
|
+
end.yield_self do |parent_domains|
|
23
|
+
[domain_name].chain(parent_domains)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def iterate_cookie_path(path)
|
28
|
+
ensured_absolute = path.sub(/\A\/*/, ?/)
|
29
|
+
::Enumerator.new do |yielder|
|
30
|
+
scanner = ::File.expand_path(?., ensured_absolute)
|
31
|
+
loop do
|
32
|
+
yielder << scanner
|
33
|
+
break if (scanner.blank?) || (?/ == scanner)
|
34
|
+
scanner = ::File.expand_path('..', scanner)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'active_support/core_ext/object/try'
|
4
|
+
require 'active_support/core_ext/time'
|
5
|
+
require 'ipaddr'
|
6
|
+
require 'time'
|
7
|
+
require 'uri'
|
8
|
+
|
9
|
+
module Greed
|
10
|
+
module Cookie
|
11
|
+
class Jar
|
12
|
+
include Iterator
|
13
|
+
|
14
|
+
def initialize(\
|
15
|
+
state = nil,
|
16
|
+
set_cookie_parser: nil,
|
17
|
+
get_current_time: nil,
|
18
|
+
calculate_expiration: nil,
|
19
|
+
determine_domain: nil,
|
20
|
+
determine_path: nil
|
21
|
+
)
|
22
|
+
@set_cookie_parser = set_cookie_parser || Parser.new.method(:parse)
|
23
|
+
@get_current_time = get_current_time || ::Time.method(:current)
|
24
|
+
@calculate_expiration = calculate_expiration || ExpirationHandler.new.method(:calculate_expiration)
|
25
|
+
@determine_domain = determine_domain || DomainHandler.new.method(:determine_domain)
|
26
|
+
@determine_path = determine_path || PathHandler.new.method(:determine_path)
|
27
|
+
@cookie_map = state || {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def append_cookie(document_uri, cookie_hash)
|
31
|
+
return false unless cookie_hash.present?
|
32
|
+
current_time = @get_current_time.call
|
33
|
+
parsed_document_uri = ::URI.parse(document_uri)
|
34
|
+
base = cookie_hash.slice(:name, :value, :secure)
|
35
|
+
domain_attributes = @determine_domain.call(
|
36
|
+
parsed_document_uri.hostname,
|
37
|
+
cookie_hash[:domain]
|
38
|
+
)
|
39
|
+
path_attributes = @determine_path.call(
|
40
|
+
parsed_document_uri.path,
|
41
|
+
cookie_hash[:path]
|
42
|
+
)
|
43
|
+
final_domain = domain_attributes[:domain]
|
44
|
+
final_path = path_attributes[:path]
|
45
|
+
domain_holder = @cookie_map[final_domain].try(:clone) || {}
|
46
|
+
path_holder = domain_holder[final_path].try(:clone) || {}
|
47
|
+
expires_attributes = @calculate_expiration.call(
|
48
|
+
current_time,
|
49
|
+
cookie_hash[:'max-age'],
|
50
|
+
cookie_hash[:expires]
|
51
|
+
)
|
52
|
+
path_holder[base[:name]] = base.merge(
|
53
|
+
domain_attributes,
|
54
|
+
expires_attributes,
|
55
|
+
path_attributes,
|
56
|
+
)
|
57
|
+
domain_holder[final_path] = path_holder
|
58
|
+
@cookie_map[final_domain] = domain_holder
|
59
|
+
true
|
60
|
+
rescue DomainError, PathError
|
61
|
+
return false
|
62
|
+
rescue Expired
|
63
|
+
removed_cookie = path_holder.delete(base[:name])
|
64
|
+
return false unless removed_cookie
|
65
|
+
domain_holder[final_path] = path_holder
|
66
|
+
@cookie_map[final_domain] = domain_holder
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
|
70
|
+
def dump
|
71
|
+
garbage_collect
|
72
|
+
@cookie_map.clone
|
73
|
+
end
|
74
|
+
|
75
|
+
def cookie_record_for(document_uri)
|
76
|
+
parsed_document_uri = begin
|
77
|
+
::URI.parse(document_uri)
|
78
|
+
rescue ::URI::Error
|
79
|
+
return []
|
80
|
+
end
|
81
|
+
is_secure = case parsed_document_uri
|
82
|
+
when ::URI::HTTPS
|
83
|
+
true
|
84
|
+
when ::URI::HTTP
|
85
|
+
false
|
86
|
+
else
|
87
|
+
return []
|
88
|
+
end
|
89
|
+
domain_name = parsed_document_uri.hostname
|
90
|
+
ip_address = begin
|
91
|
+
::IPAddr.new(domain_name)
|
92
|
+
rescue ::IPAddr::Error
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
return cookie_for_ip_address(parsed_document_uri.path, is_secure, ip_address) if ip_address
|
96
|
+
return [] unless domain_name.present?
|
97
|
+
cookie_for_domain(parsed_document_uri.path, is_secure, domain_name)
|
98
|
+
end
|
99
|
+
|
100
|
+
def cookie_header_for(document_uri)
|
101
|
+
cookie_record_for(document_uri).map do |cookie_record|
|
102
|
+
"#{cookie_record[:name]}=#{cookie_record[:value]}"
|
103
|
+
end.to_a.join('; ')
|
104
|
+
end
|
105
|
+
|
106
|
+
def parse_set_cookie(document_uri, header)
|
107
|
+
append_cookie(document_uri, @set_cookie_parser.call(header))
|
108
|
+
end
|
109
|
+
|
110
|
+
def garbage_collect
|
111
|
+
current_time = @get_current_time.call
|
112
|
+
@cookie_map = @cookie_map.map do |domain_name, domain_holder|
|
113
|
+
domain_holder.map do |path_name, path_holder|
|
114
|
+
path_holder.select do |_cookie_name, cookie_record|
|
115
|
+
!cookie_record[:expires] || current_time < cookie_record[:expires]
|
116
|
+
end.yield_self do |filtered_result|
|
117
|
+
break nil unless filtered_result.present?
|
118
|
+
[path_name, filtered_result]
|
119
|
+
end
|
120
|
+
end.compact.to_h.yield_self do |filtered_result|
|
121
|
+
break nil unless filtered_result.present?
|
122
|
+
[domain_name, filtered_result]
|
123
|
+
end
|
124
|
+
end.compact.to_h
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def compile_effective_cookies(domain_candidates, document_path, &cookie_selector)
|
131
|
+
path_candidates = iterate_cookie_path(document_path)
|
132
|
+
effective_cookies = {}
|
133
|
+
domain_candidates.each do |domain_candidate|
|
134
|
+
domain_holder = @cookie_map[domain_candidate]
|
135
|
+
next if domain_holder.blank?
|
136
|
+
path_candidates.each do |path_candidate|
|
137
|
+
path_holder = domain_holder[path_candidate]
|
138
|
+
next unless path_holder.present? && path_holder.respond_to?(:select)
|
139
|
+
path_holder = path_holder.select(&cookie_selector)
|
140
|
+
effective_cookies = path_holder.merge(effective_cookies)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
effective_cookies
|
144
|
+
end
|
145
|
+
|
146
|
+
def cookie_for_domain(document_path, is_document_secure, domain_name)
|
147
|
+
current_time = @get_current_time.call
|
148
|
+
domain_candidates = iterate_cookie_domain(domain_name)
|
149
|
+
compile_effective_cookies(domain_candidates, document_path) do |_cookie_name, cookie_record|
|
150
|
+
filter_cookie(cookie_record, is_document_secure, current_time) &&
|
151
|
+
((cookie_record[:domain] == domain_name) || cookie_record[:include_subdomains])
|
152
|
+
end.values
|
153
|
+
end
|
154
|
+
|
155
|
+
def cookie_for_ip_address(document_path, is_document_secure, ip_address)
|
156
|
+
current_time = @get_current_time.call
|
157
|
+
compile_effective_cookies([ip_address.to_s], document_path) do |_cookie_name, cookie_record|
|
158
|
+
filter_cookie(cookie_record, is_document_secure, current_time)
|
159
|
+
end.values
|
160
|
+
end
|
161
|
+
|
162
|
+
def filter_cookie(cookie_record, is_document_secure, current_time)
|
163
|
+
(!cookie_record[:expires] || current_time < cookie_record[:expires]) &&
|
164
|
+
(is_document_secure || !cookie_record[:secure])
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'active_support/core_ext/object/try'
|
4
|
+
require 'active_support/core_ext/time'
|
5
|
+
require 'memoist'
|
6
|
+
require 'strscan'
|
7
|
+
require 'time'
|
8
|
+
|
9
|
+
module Greed
|
10
|
+
module Cookie
|
11
|
+
class Parser
|
12
|
+
class << self
|
13
|
+
extend ::Memoist
|
14
|
+
|
15
|
+
memoize def _default_kv_matcher
|
16
|
+
/\A\s*([-_.+%\d\w]+)=\s*([^;]*)\s*(?:;\s*|\z)/
|
17
|
+
end
|
18
|
+
|
19
|
+
memoize def _default_flag_matcher
|
20
|
+
/\A\s*([-_\w\d]+)\s*(?:;\s*|\z)/
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(\
|
25
|
+
cookie_matcher: nil,
|
26
|
+
attribute_matcher: nil,
|
27
|
+
flag_matcher: nil
|
28
|
+
)
|
29
|
+
@cookie_matcher = cookie_matcher || self.class._default_kv_matcher
|
30
|
+
@attribute_matcher = attribute_matcher || self.class._default_kv_matcher
|
31
|
+
@flag_matcher = flag_matcher || self.class._default_flag_matcher
|
32
|
+
freeze
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse(set_cookie_header)
|
36
|
+
scanner = ::StringScanner.new(set_cookie_header)
|
37
|
+
matched = scanner.scan(@cookie_matcher)
|
38
|
+
return nil unless matched
|
39
|
+
captured = scanner.captures
|
40
|
+
mandatory_parsed = {
|
41
|
+
name: captured[0].tap do |cookie_name|
|
42
|
+
return nil unless cookie_name.present?
|
43
|
+
end,
|
44
|
+
value: captured[1],
|
45
|
+
}
|
46
|
+
flags_parsed = {}
|
47
|
+
attributes_parsed = {}
|
48
|
+
until scanner.eos? do
|
49
|
+
matched = scanner.scan(@flag_matcher)
|
50
|
+
if matched
|
51
|
+
captured = scanner.captures
|
52
|
+
flags_parsed.merge!(
|
53
|
+
"#{captured[0].downcase}": true,
|
54
|
+
)
|
55
|
+
next
|
56
|
+
end
|
57
|
+
matched = scanner.scan(@attribute_matcher)
|
58
|
+
if matched
|
59
|
+
captured = scanner.captures
|
60
|
+
attributes_parsed.merge!(
|
61
|
+
"#{captured[0].downcase}": captured[1],
|
62
|
+
)
|
63
|
+
next
|
64
|
+
end
|
65
|
+
return nil
|
66
|
+
end
|
67
|
+
combine_fragments(
|
68
|
+
mandatory_parsed,
|
69
|
+
attributes_parsed,
|
70
|
+
flags_parsed
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def combine_fragments(\
|
77
|
+
mandatory_parsed,
|
78
|
+
attributes_parsed,
|
79
|
+
flags_parsed
|
80
|
+
)
|
81
|
+
mandatory_parsed.merge(
|
82
|
+
expires: attributes_parsed[:expires].yield_self do |expires|
|
83
|
+
::Time.parse(expires)
|
84
|
+
rescue ArgumentError, TypeError
|
85
|
+
nil
|
86
|
+
end,
|
87
|
+
'max-age': attributes_parsed[:'max-age'].yield_self do |max_age|
|
88
|
+
Integer(max_age)
|
89
|
+
rescue ArgumentError, TypeError
|
90
|
+
nil
|
91
|
+
end,
|
92
|
+
domain: attributes_parsed[:domain].presence.try(:strip),
|
93
|
+
path: attributes_parsed[:path].presence.try(:strip),
|
94
|
+
samesite: attributes_parsed[:samesite].yield_self do |same_site|
|
95
|
+
break 'Lax' unless same_site.present?
|
96
|
+
%w[Strict Lax None]
|
97
|
+
.lazy
|
98
|
+
.select { |enum_value| enum_value.casecmp?(same_site) }
|
99
|
+
.first || 'Lax'
|
100
|
+
end,
|
101
|
+
secure: !!flags_parsed[:secure],
|
102
|
+
httponly: !!flags_parsed[:httponly],
|
103
|
+
)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
require 'active_support/core_ext/time'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
module Greed
|
7
|
+
module Cookie
|
8
|
+
class PathError < Error
|
9
|
+
end
|
10
|
+
class PathViolation < PathError
|
11
|
+
end
|
12
|
+
|
13
|
+
class PathHandler
|
14
|
+
include Iterator
|
15
|
+
|
16
|
+
def determine_path(document_path, cookie_path)
|
17
|
+
return generate_default_path(document_path) if cookie_path.blank?
|
18
|
+
# speed optimization for the common use case
|
19
|
+
if cookie_path == ?/
|
20
|
+
return {
|
21
|
+
path: ?/,
|
22
|
+
}
|
23
|
+
end
|
24
|
+
normalized_cookie_path = ::File.expand_path(?., cookie_path)
|
25
|
+
iterate_cookie_path(document_path).each do |path_candidate|
|
26
|
+
next unless path_candidate == normalized_cookie_path
|
27
|
+
return {
|
28
|
+
path: normalized_cookie_path,
|
29
|
+
}
|
30
|
+
end
|
31
|
+
raise PathViolation
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def generate_default_path(document_path)
|
37
|
+
# RFC 6265 5.1.4
|
38
|
+
if (document_path.blank?) ||
|
39
|
+
(!document_path.start_with?(?/))
|
40
|
+
return {
|
41
|
+
path: ?/,
|
42
|
+
}
|
43
|
+
end
|
44
|
+
{
|
45
|
+
path: ::File.expand_path('..', document_path),
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cookiejar_of_greed
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sarun Rattanasiri
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-02-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: memoist
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: public_suffix
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Cookiejar of greed is an implementation of cookiejar focused on browser
|
56
|
+
compatibility and loosely based on the standard.
|
57
|
+
email: midnight_w@gmx.tw
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- lib/cookiejar_of_greed.rb
|
63
|
+
- lib/greed.rb
|
64
|
+
- lib/greed/cookie.rb
|
65
|
+
- lib/greed/cookie/domain_handler.rb
|
66
|
+
- lib/greed/cookie/error.rb
|
67
|
+
- lib/greed/cookie/expiration_handler.rb
|
68
|
+
- lib/greed/cookie/iterator.rb
|
69
|
+
- lib/greed/cookie/jar.rb
|
70
|
+
- lib/greed/cookie/parser.rb
|
71
|
+
- lib/greed/cookie/path_handler.rb
|
72
|
+
- lib/greed/cookie/version.rb
|
73
|
+
homepage: https://github.com/the-cave/cookiejar-of-greed
|
74
|
+
licenses:
|
75
|
+
- BSD-3-Clause
|
76
|
+
metadata:
|
77
|
+
source_code_uri: https://github.com/the-cave/cookiejar-of-greed/tree/v0.0.1
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: 2.5.0
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubygems_version: 3.0.3
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: A compatibility-first cookiejar implementation
|
97
|
+
test_files: []
|