vendor/rack/lib/rack/session/cookie.rb in relevance-castronaut-0.5.4 vs vendor/rack/lib/rack/session/cookie.rb in relevance-castronaut-0.6.0

- old
+ new

@@ -1,27 +1,32 @@ +require 'openssl' + module Rack module Session # Rack::Session::Cookie provides simple cookie based session management. # The session is a Ruby Hash stored as base64 encoded marshalled data # set to :key (default: rack.session). + # When the secret key is set, cookie data is checked for data integrity. # # Example: # # use Rack::Session::Cookie, :key => 'rack.session', # :domain => 'foo.com', # :path => '/', - # :expire_after => 2592000 + # :expire_after => 2592000, + # :secret => 'change_me' # # All parameters are optional. class Cookie def initialize(app, options={}) @app = app @key = options[:key] || "rack.session" + @secret = options[:secret] @default_options = {:domain => nil, :path => "/", :expire_after => nil}.merge(options) end @@ -35,10 +40,15 @@ def load_session(env) request = Rack::Request.new(env) session_data = request.cookies[@key] + if @secret && session_data + session_data, digest = session_data.split("--") + session_data = nil unless digest == generate_hmac(session_data) + end + begin session_data = session_data.unpack("m*").first session_data = Marshal.load(session_data) env["rack.session"] = session_data rescue @@ -50,10 +60,14 @@ def commit_session(env, status, headers, body) session_data = Marshal.dump(env["rack.session"]) session_data = [session_data].pack("m*") + if @secret + session_data = "#{session_data}--#{generate_hmac(session_data)}" + end + if session_data.size > (4096 - @key.size) env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.") [status, headers, body] else options = env["rack.session.options"] @@ -62,9 +76,13 @@ cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil? response = Rack::Response.new(body, status, headers) response.set_cookie(@key, cookie.merge(options)) response.to_a end + end + + def generate_hmac(data) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA1.new, @secret, data) end end end end