Reference Source

js/security/todo/authentication_plugin_passport_local_file.js


// NPM IMPORTS
import assert     from 'assert'
import lowdb      from 'lowdb'
import FileAsync  from 'lowdb/adapters/FileAsync'
import path       from 'path'

// COMMON IMPORTS
import T from 'devapt-core-common/dist/js/utils/types'

// SERVER IMPORTS
import runtime from '../base/runtime'
import AuthenticationPluginPassportLocal from './authentication_plugin_passport_local'


let context = 'common/security/authentication_plugin_passport_local_file'



/**
 * Authentication class for Passport Local file strategy.
 * @author Luc BORIES
 * @license Apache-2.0
 */
export default class AuthenticationPluginPassportLocalFile extends AuthenticationPluginPassportLocal
{
    /**
     * Create an Authentication plugin class based on passport local file strategy.
     * @param {string|undefined} arg_log_context - optional.
     * @returns {nothing}
     */
	constructor(arg_log_context)
	{
		super(arg_log_context ? arg_log_context : context)
		
		this.is_authentication_passport_local_file = true
        
        this.passport.serializeUser(
            function(user, done)
            {
                done(null, this.get_user_id(user))
            }
        )
        
        this.passport.deserializeUser(
            function(id, done)
            {
                this.get_user_by_id(id).then(
                    function(user)
                    {
                        done(null, user)
                    },
                    function()
                    {
                        done('not found', false)
                    }
                )
            }
        )
	}
    
    
	/**
     * Enable authentication plugin with contextual informations.
     * @param {object|undefined} arg_settings - optional contextual settings.
     * @returns {object} - a promise object of a boolean result (success:true, failure:false)
     */
	enable(arg_settings)
	{
        let resolved_promise = super.enable(arg_settings)
        
        // SET FILE NAME
        this.file_name = null
        if (arg_settings && T.isString(arg_settings.file_name) )
        {
            this.file_name = arg_settings.file_name
        }
        
        // LOAD FILE DB
        this.file_db = null
        if (this.file_name)
        {
            resolved_promise = resolved_promise.then(
                function()
                {
                    const base_dir = runtime.get_setting('base_dir', null)
                    assert( T.isString(base_dir), context + ':enable:bad base dir string')
                    
                    const json_full_path = path.join(base_dir, this.file_name)
                    
                    // OPEN DATABASE
                    const db_settings = {
                        autosave:true
                    }
                    this.file_adapter = new FileAsync(json_full_path, db_settings)
                    this.file_db = lowdb(this.file_adapter)
                }
            )
        }
        
        return resolved_promise
    }
    
    
    /**
     * Authenticate a user with a file giving request credentials.
     * @param {object|undefined} arg_credentials - request credentials object
     * @returns {object} - a promise of boolean
     */
    authenticate(arg_credentials)
    {
        this.debug('authenticate')
        
        assert( T.isObject(this.db), context + ':authenticate:bad db object')
        assert( T.isObject(arg_credentials), context + ':authenticate:bad credentials object')
        assert( T.isString(arg_credentials.username), context + ':authenticate:bad credentials.username string')
        assert( T.isString(arg_credentials.password), context + ':authenticate:bad credentials.password string')
        
        // CREATE QUERY
        const username_field = this.username_fieldname ? this.username_fieldname : 'username'
        const password_field = this.id_password_fieldnamefieldname ? this.password_fieldname : 'password'
        let query = {}
        query[username_field] = arg_credentials.username
        query[password_field] = arg_credentials.password
        
        // EXECUTE QUERY
        try{
            const users = this.db('users').find(query)
            if (users)
            {
                const first_user = (T.isArray(users) && users.length > 0) ? users[0] : (T.isObject(users) ? users : null)
                if ( T.isFunction(arg_credentials.done_cb) )
                {
                    arg_credentials.done_cb(first_user)
                }
                
                this.debug('authenticate:success')
                return Promise.resolve(true)
            }
        }
        catch(e)
        {
        }
        
        this.debug('authenticate:failure')
        return Promise.resolve(false)
    }
    
    
    /**
     * Get user id from a user record.
     * @param {object} arg_user_record - user record object
     * @returns {string} - user id
     */
    get_user_id(arg_user_record)
    {
        const id_field = this.id_fieldname ? this.id_fieldname : 'id'
        return ( T.isObject(arg_user_record) && (id_field in arg_user_record) ) ? arg_user_record[id_field] : null
    }
    
    
    /**
     * Get user record by its id.
     * @param {string} arg_user_id - user id
     * @returns {string} - user id
     */
    get_user_by_id(arg_user_id)
    {
        assert( T.isObject(this.db), context + ':get_user_by_id:bad db object')
        
        // CREATE QUERY
        const id_field = this.id_fieldname ? this.id_fieldname : 'id'
        let query = {}
        query[id_field] = arg_user_id
        
        // EXECUTE QUERY
        try{
            let users = this.db('users').find(query)
            if (users)
            {
                return (T.isArray(users) && users.length > 0) ? users[0] : (T.isObject(users) ? users : null)
            }
        }
        catch(e)
        {
        }
        
        return null
    }
}