class Rack::Protection::MaximumCookie
Constants
- COOKIE_DOMAIN_RE
- COOKIE_KEY_RE
- HEADER_SEP_RE
- VERSION
Attributes
app[R]
handler[R]
public_suffix_list[R]
Public Class Methods
new(app, options={}, &block)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 66 def initialize(app, options={}, &block) @app = app @handler = block @options = {}.tap do |h| h[:limit] = Integer(options.fetch(:limit, 50)) h[:bytesize_limit] = Integer(options.fetch(:bytesize_limit, 4_096)) h[:overhead] = Integer(options.fetch(:overhead, 3)) h[:stateful?] = !!options.fetch(:stateful?, options.fetch(:stateful, false)) h[:strict?] = h[:stateful?] || !!options.fetch(:strict?, options.fetch(:strict, false)) h[:per_domain?] = h[:strict?] || !!options.fetch(:per_domain?, options.fetch(:per_domain, true)) h.freeze end if strict? # Allow non-ICANN domains to be handled the same as ICANN domains. @public_suffix_list = PublicSuffix::List.parse(::File.read(PublicSuffix::List::DEFAULT_LIST_PATH), :private_domains=>false) end unless limit? || bytesize_limit? abort 'No limits, nothing to do!' end end
Public Instance Methods
bytesize_limit()
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 42 def bytesize_limit @options[:bytesize_limit] end
bytesize_limit?()
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 46 def bytesize_limit? @options[:bytesize_limit] >= 0 end
call(env)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 91 def call(env) status, headers, body = app.call(env) if headers.key?(SET_COOKIE) check_cookies env, Rack::Request.new(env), normalize_cookie_header(headers[SET_COOKIE]) end [status, headers, body] end
limit()
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 34 def limit @options[:limit] end
limit?()
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 38 def limit? @options[:limit] >= 0 end
overhead()
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 50 def overhead @options[:overhead] end
per_domain?()
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 54 def per_domain? @options[:per_domain?] end
stateful?()
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 62 def stateful? @options[:stateful?] end
strict?()
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 58 def strict? @options[:strict?] end
Private Instance Methods
check_bytesize_limit_per_domain(env, acc, limit)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 160 def check_bytesize_limit_per_domain(env, acc, limit) bad_domains = acc .keep_if { |_, value| value > limit } .keys if bad_domains.any? && handle(env) raise_error "Too much cookie data for domain(s): #{bad_domains.join(', ')}" end end
check_limit_per_domain(env, acc, limit)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 150 def check_limit_per_domain(env, acc, limit) bad_domains = acc .keep_if { |_, value| value > limit } .keys if bad_domains.any? && handle(env) raise_error "Too many cookies for domain(s): #{bad_domains.join(', ')}" end end
domain(hostname)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 181 def domain(hostname) return hostname if hostname =~ Resolv::IPv4::Regex || hostname =~ Resolv::IPv6::Regex PublicSuffix.domain(hostname, :list=>public_suffix_list) || hostname end
fold(request, response_cookie_keys) { |first, bytesize| ... }
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 215 def fold(request, response_cookie_keys) # Assume that all request cookies have a domain of the default # subdomain (e.g. foo.example.com) or its second-level domain (e.g. # example.com). domains = [foldcase(request.hostname)].tap do |a| a.unshift(domain(a.first)) a.uniq! end request.cookies.each_pair do |key, value| # *Try* to prevent double-counting cookies (i.e. on the response # and the request). next if domains.any? { |domain| response_cookie_keys[domain].include?(key) } # *Try* to estimate the upper bound of the size of the cookie and its # directives in the original Set-Cookie header. # TODO: Replace this with a simpler byte count for efficiency? mock_cookie = String.new("#{key}=#{value}").tap do |s| s << "; Expires=#{Date.today.httpdate}" s << '; Max-Age=123456' s << "; Domain=#{domains.last}" s << "; Path=#{request.script_name}" s << '; Secure' if request.ssl? s << '; HttpOnly; SameSite=strict' end yield domains.first, mock_cookie.bytesize end end
foldcase(str)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 198 def foldcase(str) str.downcase(:fold) end
foldcase!(str)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 202 def foldcase!(str) str.downcase!(:fold) end
handle(env)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 187 def handle(env) handler.nil? || handler.call(env) end
propogate_values(hash)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 245 def propogate_values(hash) hash.each_key do |subdomain| sld = domain(subdomain) next if sld == subdomain next unless hash.key?(sld) hash[subdomain] += hash[sld] end end
raise_error(message)
click to toggle source
# File lib/rack/protection/maximum_cookie.rb, line 254 def raise_error(message) fail message end