<commit_before>
events = require 'events'

module.exports =

    ##
    ## 
    ##
    class HttpSessions extends floyd.Context
        
        configure: (config)->
        
            @_hiddenKeys.push 'Registry', 'Session'
            @_TOKENS = config.tokens
  
            super new floyd.Config
            
                data:
                    cookie:
                        name: 'FSID'
                                        
                    registry:
                        type: 'http.sessions.Registry'
                        interval: 60
                        timeout: 3600
                        
                        sessions:
                            type: 'http.sessions.Session'
                    
            , config	

        ##
        ##
        ##
        boot: (done)->
            
            @_registry = new (floyd.tools.objects.resolve @data.registry.type) @data.registry
            
            super done
        
        ##
        ##
        ##
        start: (done)->
            
            exclude = @data.find 'no-session-routes', []
            
            ## use the next HttpContext (idealy our parent) to connect req handler
            @delegate '_addMiddleware', (req, res, next)=>
                return next() if @data.disabled				
                
                for expr in exclude
                    return next() if req.url.match expr
                
                @_load @_getSID(req), (err, sess)=>
                    return next(err) if err
                        
                    #console.log 'session', sess.public
                    
                    req.session = sess.public
                    
                    _end = res.end
                    res.end = (args)=>
                        @_release req, sess, (err)=>							
                            return next(err) if err
                                            
                            req.session = null 		## <-- remove references to avoid memory leaks
                            
                            _end.apply res, args
                                
                    ##	
                    next()
                    
            
            ##
            super done
        
        
        ##
        ##
        ##
        login: (token, user, pass, _fn)->
            
            fn = (err, user)=>
                if err
                    setTimeout ()=>
                        _fn err
                    , 2500
                    
                else _fn null, user
            
            sid = token.substr 40 ## TODO - validate token
        
            sess = @_registry.get(sid)
            
            return fn(new Error 'login failed') if !sess || !user || !pass
            
            users = @parent.children.users
            
            users.get user, (err, data)=>	

                return fn(err || new Error 'login failed') if err || !data
                
                if data.active is false || !floyd.tools.crypto.password.verify pass, data.pass
                    console.warn 'access denied for %s@%s', user, sid
                     
                    fn new Error 'login failed' 
                
                else
                    data.lastlogin = +new Date()
                    
                    @_checkPasswordHash user, pass, data, (err, data)=>
                        return fn(err) if err
                        
                        users.set user, data, (err)=>
                    
                            data = floyd.tools.objects.clone data,	
                                login: user
                        
                            delete data.pass
                        
                            sess.public.user = data
                        
                            ##
                            fn null, data
                    
        
        ##
        ##
        ##
        _checkPasswordHash: (user, pass, data, fn)->
            
            cfg = floyd.tools.crypto.password._options

            parts = data.pass.split '-'
            
            if parts.length is 1 \          ## check for old-style password hash 
            or cfg.hasher isnt parts[1] \   ## check for new hash config
            or cfg.keySize isnt (parseInt parts[2]) \
            or cfg.iterations isnt (parseInt parts[3])
                
                data.pass = floyd.tools.crypto.password.create pass
            
                console.warn 'replacing password hash', data.pass
                
                
            ##
            fn null, data
        
        ##
        ##
        ##
        logout: (token, fn)->
            
            sid = token.substr 40 ## TODO - validate token
            
            #console.log 'logout %s@%s', user, sid
            
            if (sess = @_registry.get(sid))
                
                sess.public.user = floyd.tools.objects.unlink sess.public.user
                
                
            fn()
                
        <commit_msg>replaced session.public.user unlink with delete on logout<commit_after>
events = require 'events'

module.exports =

    ##
    ## 
    ##
    class HttpSessions extends floyd.Context
        
        configure: (config)->
        
            @_hiddenKeys.push 'Registry', 'Session'
            @_TOKENS = config.tokens
  
            super new floyd.Config
            
                data:
                    cookie:
                        name: 'FSID'
                                        
                    registry:
                        type: 'http.sessions.Registry'
                        interval: 60
                        timeout: 3600
                        
                        sessions:
                            type: 'http.sessions.Session'
                    
            , config	

        ##
        ##
        ##
        boot: (done)->
            
            @_registry = new (floyd.tools.objects.resolve @data.registry.type) @data.registry
            
            super done
        
        ##
        ##
        ##
        start: (done)->
            
            exclude = @data.find 'no-session-routes', []
            
            ## use the next HttpContext (idealy our parent) to connect req handler
            @delegate '_addMiddleware', (req, res, next)=>
                return next() if @data.disabled				
                
                for expr in exclude
                    return next() if req.url.match expr
                
                @_load @_getSID(req), (err, sess)=>
                    return next(err) if err
                        
                    #console.log 'session', sess.public
                    
                    req.session = sess.public
                    
                    _end = res.end
                    res.end = (args)=>
                        @_release req, sess, (err)=>							
                            return next(err) if err
                                            
                            req.session = null 		## <-- remove references to avoid memory leaks
                            
                            _end.apply res, args
                                
                    ##	
                    next()
                    
            
            ##
            super done
        
        
        ##
        ##
        ##
        login: (token, user, pass, _fn)->
            
            fn = (err, user)=>
                if err
                    setTimeout ()=>
                        _fn err
                    , 2500
                    
                else _fn null, user
            
            sid = token.substr 40 ## TODO - validate token
        
            sess = @_registry.get(sid)
            
            return fn(new Error 'login failed') if !sess || !user || !pass
            
            users = @parent.children.users
            
            users.get user, (err, data)=>	

                return fn(err || new Error 'login failed') if err || !data
                
                if data.active is false || !floyd.tools.crypto.password.verify pass, data.pass
                    console.warn 'access denied for %s@%s', user, sid
                     
                    fn new Error 'login failed' 
                
                else
                    data.lastlogin = +new Date()
                    
                    @_checkPasswordHash user, pass, data, (err, data)=>
                        return fn(err) if err
                        
                        users.set user, data, (err)=>
                    
                            data = floyd.tools.objects.clone data,	
                                login: user
                        
                            delete data.pass
                        
                            sess.public.user = data
                        
                            ##
                            fn null, data
                    
        
        ##
        ##
        ##
        _checkPasswordHash: (user, pass, data, fn)->
            
            cfg = floyd.tools.crypto.password._options

            parts = data.pass.split '-'
            
            if parts.length is 1 \          ## check for old-style password hash 
            or cfg.hasher isnt parts[1] \   ## check for new hash config
            or cfg.keySize isnt (parseInt parts[2]) \
            or cfg.iterations isnt (parseInt parts[3])
                
                data.pass = floyd.tools.crypto.password.create pass
            
                console.warn 'replacing password hash', data.pass
                
                
            ##
            fn null, data
        
        ##
        ##
        ##
        logout: (token, fn)->
            
            sid = token.substr 40 ## TODO - validate token
            
            #console.log 'logout %s@%s', user, sid
            
            if (sess = @_registry.get(sid))
                
                delete sess.public.user
                
                
            fn()
                
        
{'fraction_non_alphanumeric': 0.07751937984496124, 'fraction_numerical': 0.003532528701795702, 'mean_word_length': 0.6981006331222925, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '120050', 'n_tokens_mistral': 2376, 'n_tokens_neox': 2198, 'n_words': 573}