module Roda::RodaPlugins::Sessions::RequestMethods
def _deserialize_session(data)
def _deserialize_session(data) opts = roda_class.opts[:sessions] begin data = Base64.urlsafe_decode64(data) rescue ArgumentError return _session_serialization_error("Unable to decode session: invalid base64") end length = data.bytesize if data.length < 61 # minimum length (1+16+12+32) (version+cipher_iv+minimum session+hmac) # 1 : version # 16 : cipher_iv # 12 : minimum_session # 2 : bitmap for gzip + padding info # 4 : creation time # 4 : update time # 2 : data # 32 : HMAC-SHA-256 return _session_serialization_error("Unable to decode session: data too short") end unless data.getbyte(0) == 0 # version marker return _session_serialization_error("Unable to decode session: version marker unsupported") end encrypted_data = data.slice!(0, length-32) unless Rack::Utils.secure_compare(data, OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, opts[:hmac_secret], encrypted_data+opts[:key])) if opts[:old_hmac_secret] && Rack::Utils.secure_compare(data, OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, opts[:old_hmac_secret], encrypted_data+opts[:key])) use_old_cipher_secret = true else return _session_serialization_error("Not decoding session: HMAC invalid") end end encrypted_data.slice!(0) cipher = OpenSSL::Cipher.new("aes-256-ctr") # Not rescuing cipher errors. If there is an error in the decryption, that's # either a bug in the plugin that needs to be fixed, or an attacker is already # able to forge a valid HMAC, in which case the error should be raised to # alert the application owner about the problem. cipher.decrypt cipher.key = opts[use_old_cipher_secret ? :old_cipher_secret : :cipher_secret] cipher_iv = cipher.iv = encrypted_data.slice!(0, 16) data = cipher.update(encrypted_data) << cipher.final bitmap, created_at, updated_at = data.unpack('vVV') padding_bytes = bitmap & PADDING_MASK if (max = opts[:max_seconds]) && Time.now.to_i > created_at + max return _session_serialization_error("Not returning session: maximum session time expired") end if (max = opts[:max_idle_seconds]) && Time.now.to_i > updated_at + max return _session_serialization_error("Not returning session: maximum session idle time expired") end data = data.slice(10+padding_bytes, data.bytesize) if bitmap & DEFLATE_BIT > 0 data = Zlib::Inflate.inflate(data) end env = @env env[SESSION_CREATED_AT] = created_at env[SESSION_UPDATED_AT] = updated_at env[SESSION_SERIALIZED] = data opts[:parser].call(data) end