class RSence::SessionManager
SessionManager
does session creation, validation, expiration and storage duties.
Attributes
randgen[R]
Public Class Methods
new( transporter )
click to toggle source
Makes everything ready to run
Calls superclass method
# File lib/rsence/sessionmanager.rb, line 35 def initialize( transporter ) super() @transporter = transporter @valuemanager = @transporter.valuemanager @plugins = @transporter.plugins ## 'Unique' Random String generator for ses_key:s and cookie_key:s @randgen = RandGen.new( @config[:key_length] ) # regex to match ipv4 addresses @ipv4_reg = /^([1][0-9][0-9]|[2][0-5][0-9]|[1-9][0-9]|[1-9])\.([1][0-9][0-9]|[2][0-5][0-9]|[1-9][0-9]|[0-9])\.([1][0-9][0-9]|[2][0-5][0-9]|[1-9][0-9]|[0-9])\.([1][0-9][0-9]|[2][0-5][0-9]|[1-9][0-9]|[0-9])$/ end
Public Instance Methods
check_ses( msg, ses_key, ses_seed=false )
click to toggle source
Returns the current session data, if the session is valid. Otherwise stops the client and returns false.
# File lib/rsence/sessionmanager.rb, line 234 def check_ses( msg, ses_key, ses_seed=false ) # first, check if the session key exists (sync) if @session_keys.has_key?( ses_key ) # get the session's id based on its key ses_id = @session_keys[ ses_key ] # get the session's data based on its id ses_data = @sessions[ ses_id ] if not ses_data.has_key?(:_msg_unused) and @config[:clone_cookie_sessions] and ses_seed clone_ses( msg, ses_data, ses_id, ses_key, ses_seed ) return [true, true] else refresh_ses( msg, ses_data, ses_id, ses_key, ses_seed ) return [true, false] end ## The session was either faked or expired: elsif RSence.args[:debug] ### Tells the client to stop connecting with its session key and reload instead to get a new one. stop_client_with_message( msg, @config[:messages][:invalid_session][:title], @config[:messages][:invalid_session][:descr], @config[:messages][:invalid_session][:uri] ) ## Return failure return [false, false] else msg.error_msg( [ "COMM.Transporter.stop = true;", "setTimeout(function(){window.location.reload(true);},3000);", "COMM.Transporter.setInterruptAnim('Session failure, reloading in 3 seconds..','#039');", "setTimeout(function(){COMM.Transporter.setInterruptAnim('Reloading...');},2500);", "setTimeout(function(){COMM.Transporter.setInterruptAnim('Session failure, reloading in 1 seconds..');},2000);", "setTimeout(function(){COMM.Transporter.setInterruptAnim('Session failure, reloading in 2 seconds..');},1000);", ] ) return [ false, false ] end end
clone_ses( msg, old_data, old_id, old_key, ses_seed )
click to toggle source
# File lib/rsence/sessionmanager.rb, line 183 def clone_ses( msg, old_data, old_id, old_key, ses_seed ) if @plugins @plugins.delegate( :dump_ses, old_data ) @plugins.delegate( :dump_ses_id, old_id ) end begin old_dump = Marshal.dump( old_data ) if @plugins @plugins.delegate( :load_ses_id, old_id ) @plugins.delegate( :load_ses, old_data ) end ses_data = Marshal.load( old_dump ) rescue => e warn "Unable to clone session #{old_id}, because: #{e.message}" init_ses( msg, ses_seed ) return end old_data[:timeout] = Time.now.to_i + @config[:cloned_session_expires_in] timeout = Time.now.to_i + @config[:timeout_secs] cookie_key = @randgen.gen_many(@config[:cookie_key_multiplier]).join('') ses_key = @randgen.gen ses_sha = SHA1.hexdigest(ses_key+ses_seed) ses_data[:timeout] = timeout ses_data[:ses_key] = ses_key ses_data[:cookie_key] = cookie_key ses_data[:plugin_incr] = @plugins.incr ses_id = new_ses_id( cookie_key, ses_key, timeout ) ses_data[:ses_id] = ses_id @sessions[ ses_id ] = ses_data @session_keys[ ses_sha ] = ses_id @session_cookie_keys.delete( old_data[:cookie_key] ) @session_cookie_keys[ cookie_key ] = ses_id msg.ses_key = ses_key msg.session = ses_data if @plugins @plugins.delegate( :load_ses_id, ses_id ) @plugins.delegate( :load_ses, ses_data ) end if @clone_targets.has_key? old_id @clone_targets[ old_id ].push( ses_id ) else @clone_targets[ old_id ] = [ ses_id ] end @clone_sources[ ses_id ] = old_id msg.cloned_source = old_data msg.new_session = false msg.restored_session = true end
expire_ses_by_req( req, res )
click to toggle source
# File lib/rsence/sessionmanager.rb, line 480 def expire_ses_by_req( req, res ) cookie_raw = req.cookies # checks, if a cookie named 'ses_key' is found if cookie_raw.has_key?('ses_key') # gets just the data itself (discards comment, domain, expiration etc) cookie_key = cookie_raw['ses_key'].split(';')[0] end # if a cookie key is found (non-false), checks if it's valid if cookie_key # checks for validity by looking the key up in @session_cookie_keys cookie_key_exist = @session_cookie_keys.has_key?( cookie_key ) # sets the cookie key to false, if it doesn't exist cookie_key = false unless cookie_key_exist end # at this point, the cookie key seems valid: if cookie_key and cookie_key_exist # get the session identifier ses_id = @session_cookie_keys[ cookie_key ] # Expire the session expire_session( ses_id ) return true end return false end
init_msg( request, response, options = { :cookies => false, :servlet => false } )
click to toggle source
Creates a message and checks the session
# File lib/rsence/sessionmanager.rb, line 520 def init_msg( request, response, options = { :cookies => false, :servlet => false } ) cookies = options[:cookies] if options.has_key?(:query) query = options[:query] else query = request.query end ## Perform old-session cleanup on all sync:s expire_sessions ## The 'ses_id' request query key is required. ## The client defaults to '0', which means the ## client needs to be initialized. ## The client's ses_id is the server's ses_key. if not options.has_key?( :ses_key ) return Message.new( @transporter, request, response, options ) else ## get the ses_key from the request query: ses_key = options[:ses_key] ## The message object binds request, response ## and all user/session -related data to one ## object, which is passed around where ## request/response/user/session -related ## data is needed. msg = Message.new( @transporter, request, response, options ) ## The client tells that its ses_key is '0', ## until the server tells it otherwise. (req_num, ses_seed) = ses_key.split(':.o.:') if req_num == '0' # If Broker encounters a '/hello' request, it # sets cookies to true. # # It means that a session should have its cookies # checked. # if cookies ses_status = check_cookie( msg, ses_seed ) # Otherwise, a new session is created: else init_ses( msg, ses_seed ) ses_status = true end # for non-'0' ses_keys: else ## Validate the session key ses_status = check_ses( msg, ses_seed )[0] ## Renew the cookie even when the request is a "x" (not "hello") if @config[:session_cookies] and ses_status renew_cookie( msg, msg.session[:cookie_key] ) end end # /ses_key ## msg.ses_valid is false by default, meaning ## it's not valid or hasn't been initialized. msg.ses_valid = ses_status return msg end # /ses_key end
init_ses( msg=nil, ses_seed=false )
click to toggle source
Creates a new session
# File lib/rsence/sessionmanager.rb, line 54 def init_ses( msg=nil, ses_seed=false ) if ses_seed == false ses_seed = @randgen.gen end ## Assigns new timeout for the session time_now = Time.now.to_i # seconds since epoch timeout = time_now + @config[:timeout_secs] ## Creates a new session key ses_key = @randgen.gen ## Creates a new cookie key cookie_key = @randgen.gen_many(@config[:cookie_key_multiplier]).join('') ## Makes a new database row for the session, returns its id ses_id = new_ses_id( cookie_key, ses_key, timeout ) ses_sha = SHA1.hexdigest(ses_key+ses_seed) ### Default session data structure, ### Please don't mess with it, unless you know exactly what you are doing. ses_data = { # the time, when the session will time out :timeout => timeout, :plugin_incr => @plugins.incr, # session id, used internally :ses_id => ses_id, # session key, used externally (client sync) :ses_key => ses_sha, # session key, used externally (client cookies) :cookie_key => cookie_key, # user id, map to your own user management code :user_id => 0, # unused in msg context: :_msg_unused => true, # user info, map to your own user management code :user_info => {}, # valuemanager data :values => { :sync => [], # value id's to sync to client :check => [], # value id's to validate in server (from client) :by_id => {} # values by id } } # bind the session data to @sessions by its id @sessions[ ses_id ] = ses_data # map the key back to the id @session_keys[ ses_sha ] = ses_id # map the ses_id to cookie key @session_cookie_keys[ cookie_key ] = ses_id if msg ### Tell the client what the new key is msg.ses_key = ses_key ### Set the session data and id to the message object msg.session = ses_data # Flag the session as new, so associated # plugins know when to create new data msg.new_session = true end # Returns the cookie key, so it can be sent in the response header return cookie_key end
js_str( str )
click to toggle source
# File lib/rsence/sessionmanager.rb, line 281 def js_str( str ) return str.to_json.gsub('<','<').gsub('>','>').gsub(/\[\[(.*?)\]\]/,'<\1>') end
refresh_ses( msg, ses_data, ses_id, ses_key, ses_seed )
click to toggle source
# File lib/rsence/sessionmanager.rb, line 136 def refresh_ses( msg, ses_data, ses_id, ses_key, ses_seed ) # new time-out ses_data[:timeout] = Time.now.to_i + @config[:timeout_secs] # re-generates the ses_key for each sync if @config[:disposable_keys] # disposes the old (current) ses_key: @session_keys.delete( ses_key ) unless ses_seed ses_seed = ses_key end # gets a new ses_key: ses_key = @randgen.gen ses_sha = SHA1.hexdigest(ses_key+ses_seed) # re-maps the session id to the new key @session_keys[ses_sha] = ses_id # changes the session key in the session data ses_data[:ses_key] = ses_sha # tell the client what its new session key is msg.ses_key = ses_key end if @config[:clone_cookie_sessions] and @clone_targets.has_key? ses_id targets = [] @clone_targets[ ses_id ].length.times do |n| target_id = @clone_targets[ ses_id ].shift target_ses = @sessions[ target_id ] if @sessions.has_key?( target_id ) and @sessions[ target_id ].class == Hash targets.push( target_ses ) end end @clone_targets.delete( ses_id ) if @clone_targets[ ses_id ].empty? msg.cloned_targets = targets unless targets.empty? end ### Bind the session data and id to the message object msg.session = ses_data end
stop_client_with_message( msg, title = 'Unknown Issue', descr = 'No issue description given.', uri = RSence.config[:index_html][:respond_address] )
click to toggle source
Displays error message and stops the client
# File lib/rsence/sessionmanager.rb, line 286 def stop_client_with_message( msg, title = 'Unknown Issue', descr = 'No issue description given.', uri = RSence.config[:index_html][:respond_address] ) msg.error_msg( [ "jsLoader.load('default_theme');", "jsLoader.load('controls');", "jsLoader.load('servermessage');", "ReloadApp.nu( #{js_str(title)}, #{js_str(descr)}, #{js_str(uri)} );" ] ) end