cookiejar_of_greed 0.0.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.
- 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: []
|