class Rack::Session::Cookie

def delete_session(req, session_id, options)

def delete_session(req, session_id, options)
  # Nothing to do here, data is in the client
  generate_sid unless options[:drop]
end

def encode_session_data(session)

def encode_session_data(session)
  if encryptors.empty?
    coder.encode(session)
  else
    encryptors.first.encrypt(session)
  end
end

def extract_session_id(request)

def extract_session_id(request)
  unpacked_cookie_data(request)["session_id"]
end

def find_session(req, sid)

def find_session(req, sid)
  data = unpacked_cookie_data(req)
  data = persistent_session_id!(data)
  [data["session_id"], data]
end

def initialize(app, options = {})

def initialize(app, options = {})
  secrets = [*options[:secrets]]
  encryptor_opts = {
    purpose: options[:key], serialize_json: options[:serialize_json]
  }
  # For each secret, create an Encryptor. We have iterate this Array at
  # decryption time to achieve key rotation.
  @encryptors = secrets.map do |secret|
    Rack::Session::Encryptor.new secret, encryptor_opts
  end
  # If a legacy HMAC secret is present, initialize those features
  if options.has_key?(:legacy_hmac_secret)
    @legacy_hmac = options.fetch(:legacy_hmac, 'SHA1')
    @legacy_hmac_secret = options[:legacy_hmac_secret]
    @legacy_hmac_coder  = options.fetch(:legacy_hmac_coder, Base64::Marshal.new)
  else
    @legacy_hmac = false
  end
  warn <<-MSG unless secure?(options)
  SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
  This poses a security threat. It is strongly recommended that you
  provide a secret to prevent exploits that may be possible from crafted
  cookies. This will not be supported in future versions of Rack, and
  future versions will even invalidate your existing user cookies.
  Called from: #{caller[0]}.
  MSG
  # Potential danger ahead! Marshal without verification and/or
  # encryption could present a major security issue.
  @coder = options[:coder] ||= Base64::Marshal.new
  super(app, options.merge!(cookie_only: true))
end

def legacy_digest_match?(data, digest)

def legacy_digest_match?(data, digest)
  return false unless data && digest
  Rack::Utils.secure_compare(digest, legacy_generate_hmac(data))
end

def legacy_generate_hmac(data)

def legacy_generate_hmac(data)
  OpenSSL::HMAC.hexdigest(@legacy_hmac, @legacy_hmac_secret, data)
end

def persistent_session_id!(data, sid = nil)

def persistent_session_id!(data, sid = nil)
  data ||= {}
  data["session_id"] ||= sid || generate_sid
  data
end

def secure?(options)

set to true
* Customer :coder is used, with :let_coder_handle_secure_encoding
* The legacy HMAC option is enabled
initialized
* Encrypted cookies are enabled and one or more encryptor is
Were consider "secure" if:
def secure?(options)
  !@encryptors.empty? ||
    @legacy_hmac ||
    (options[:coder] && options[:let_coder_handle_secure_encoding])
end

def unpacked_cookie_data(request)

def unpacked_cookie_data(request)
  request.fetch_header(RACK_SESSION_UNPACKED_COOKIE_DATA) do |k|
    cookie_data = request.cookies[@key]
    session_data = nil
    # Try to decrypt the session data with our encryptors
    encryptors.each do |encryptor|
      begin
        session_data = encryptor.decrypt(cookie_data) if cookie_data
        break
      rescue Rack::Session::Encryptor::Error => error
        request.env[Rack::RACK_ERRORS].puts "Session cookie encryptor error: #{error.message}"
        next
      end
    end
    # If session decryption fails but there is @legacy_hmac_secret
    # defined, attempt legacy HMAC verification
    if !session_data && @legacy_hmac_secret
      # Parse and verify legacy HMAC session cookie
      session_data, _, digest = cookie_data.rpartition('--')
      session_data = nil unless legacy_digest_match?(session_data, digest)
      # Decode using legacy HMAC decoder
      session_data = @legacy_hmac_coder.decode(session_data)
    elsif !session_data && coder
      # Use the coder option, which has the potential to be very unsafe
      session_data = coder.decode(cookie_data)
    end
    request.set_header(k, session_data || {})
  end
end

def write_session(req, session_id, session, options)

def write_session(req, session_id, session, options)
  session = session.merge("session_id" => session_id)
  session_data = encode_session_data(session)
  if session_data.size > (4096 - @key.size)
    req.get_header(RACK_ERRORS).puts("Warning! Rack::Session::Cookie data size exceeds 4K.")
    nil
  else
    SessionId.new(session_id, session_data)
  end
end