aboutsummaryrefslogblamecommitdiffstats
path: root/actionpack/lib/action_dispatch/middleware/session/cookie_store.rb
blob: 92a86ee22963593d2ca385a7019345d2becdd188 (plain) (tree)
1
2
3
4
                                           
                                              
 
                     



































                                                                                
                                     

                                                
                                                             
                                 
           
 



                                                              
 
                                       
                                                        

              
 
             
 


                                                                                     
           
 
                             

                                                    
                                             

                                    

           

                                                   

           

                                                   

           



                                                    
           
       
     
   
require 'active_support/core_ext/hash/keys'
require 'active_support/core_ext/object/blank'

module ActionDispatch
  module Session
    # This cookie-based session store is the Rails default. Sessions typically
    # contain at most a user_id and flash message; both fit within the 4K cookie
    # size limit. Cookie-based sessions are dramatically faster than the
    # alternatives.
    #
    # If you have more than 4K of session data or don't want your data to be
    # visible to the user, pick another session store.
    #
    # CookieOverflow is raised if you attempt to store more than 4K of data.
    #
    # A message digest is included with the cookie to ensure data integrity:
    # a user cannot alter his +user_id+ without knowing the secret key
    # included in the hash. New apps are generated with a pregenerated secret
    # in config/environment.rb. Set your own for old apps you're upgrading.
    #
    # Session options:
    #
    # * <tt>:secret</tt>: An application-wide key string or block returning a
    #   string called per generated digest. The block is called with the
    #   CGI::Session instance as an argument. It's important that the secret
    #   is not vulnerable to a dictionary attack. Therefore, you should choose
    #   a secret consisting of random numbers and letters and more than 30
    #   characters. Examples:
    #
    #     :secret => '449fe2e7daee471bffae2fd8dc02313d'
    #     :secret => Proc.new { User.current_user.secret_key }
    #
    # * <tt>:digest</tt>: The message digest algorithm used to verify session
    #   integrity defaults to 'SHA1' but may be any digest provided by OpenSSL,
    #   such as 'MD5', 'RIPEMD160', 'SHA256', etc.
    #
    # To generate a secret key for an existing application, run
    # "rake secret" and set the key in config/environment.rb.
    #
    # Note that changing digest or secret invalidates all existing sessions!
    class CookieStore < AbstractStore
      class OptionsHash < Hash
        def initialize(by, env, default_options)
          @session_data = env[AbstractStore::ENV_SESSION_KEY]
          merge!(default_options)
        end

        def [](key)
          key == :id ? @session_data[:session_id] : super(key)
        end
      end

      def initialize(app, options = {})
        super(app, options.merge!(:cookie_only => true))
        freeze
      end

      private

        def prepare!(env)
          env[ENV_SESSION_KEY] = SessionHash.new(self, env)
          env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
        end

        def load_session(env)
          request = ActionDispatch::Request.new(env)
          data = request.cookie_jar.signed[@key]
          data = persistent_session_id!(data)
          data.stringify_keys!
          [data["session_id"], data]
        end

        def set_cookie(request, options)
          request.cookie_jar.signed[@key] = options
        end

        def set_session(env, sid, session_data)
          persistent_session_id!(session_data, sid)
        end

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