lib/utopia/session/encrypted_cookie.rb in utopia-0.12.6 vs lib/utopia/session/encrypted_cookie.rb in utopia-1.0.0
- old
+ new
@@ -19,102 +19,100 @@
# THE SOFTWARE.
require 'openssl'
require 'digest/sha2'
+require_relative 'lazy_hash'
+require_relative '../session'
+
module Utopia
module Session
-
+ # Stores all session data client side using a private symmetric encrpytion key.
class EncryptedCookie
- RACK_SESSION = "rack.session"
- RACK_SESSION_OPTIONS = "rack.session.options"
-
- def initialize(app, options={})
+ def initialize(app, options = {})
@app = app
- @cookie = options[:cookie] || (RACK_SESSION + ".encrypted")
- @secret = Digest::SHA256.digest(options[:secret])
+ @cookie_name = options.delete(:cookie_name) || (RACK_SESSION + ".encrypted")
- @default_options = {
+ @secret = options.delete(:secret)
+
+ @options = {
:domain => nil,
:path => "/",
:expires_after => nil
}.merge(options)
end
def call(env)
- original_session = load_session(env).dup
+ session_hash = prepare_session(env)
status, headers, body = @app.call(env)
- if original_session != env[RACK_SESSION]
- commit_session(env, status, headers, body)
+ if session_hash.changed?
+ commit(session_hash.values, headers)
end
return [status, headers, body]
end
-
- private
-
- def load_session(env)
- session = {}
-
+
+ protected
+
+ def prepare_session(env)
+ env[RACK_SESSION] = LazyHash.new do
+ self.load_session_values(env)
+ end
+ end
+
+ # Load session
+ def load_session_values(env)
+ values = {}
+
request = Rack::Request.new(env)
- data = request.cookies[@cookie]
-
+ data = request.cookies[@cookie_name]
+
if data
- session = decrypt(data) rescue session
+ values = decrypt(data) rescue values
end
-
- env[RACK_SESSION] = session
- env[RACK_SESSION_OPTIONS] = @default_options.dup
-
- return session
+
+ return values
end
- def commit_session(env, status, headers, body)
- session = env[RACK_SESSION]
-
- data = encrypt(session)
-
- if data.size > (1024 * 4)
- env["rack.errors"].puts "Error: #{self.class.name} data exceeds 4K. Content Dropped!"
- else
- options = env[RACK_SESSION_OPTIONS]
- cookie = {:value => data}
- cookie[:expires] = Time.now + options[:expires_after] unless options[:expires_after].nil?
-
- Rack::Utils.set_cookie_header!(headers, @cookie, cookie.merge(options))
- end
+ def commit(values, headers)
+ data = encrypt(values)
+
+ cookie = {:value => data}
+
+ cookie[:expires] = Time.now + @options[:expires_after] unless @options[:expires_after].nil?
+
+ Rack::Utils.set_cookie_header!(headers, @cookie_name, cookie.merge(@options))
end
def encrypt(hash)
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
c.encrypt
-
+
# your pass is what is used to encrypt/decrypt
c.key = @secret
c.iv = iv = c.random_iv
-
+
e = c.update(Marshal.dump(hash))
e << c.final
-
+
return [iv, e].pack("m16m*")
end
-
+
def decrypt(data)
iv, e = data.unpack("m16m*")
-
+
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
c.decrypt
-
+
c.key = @secret
c.iv = iv
-
+
d = c.update(e)
d << c.final
-
+
return Marshal.load(d)
end
end
-
end
end
\ No newline at end of file