Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

users-session-manager

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

users-session-manager

A simple Node.js library to manage users sessions on a web application or any kind of JS apps

  • 1.0.16
  • latest
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
4
increased by100%
Maintainers
1
Weekly downloads
 
Created
Source

GitHub Workflow Status Coverage Status npm version npm npm bundle size GitHub

users-session-manager

A simple Node.js module to manage users sessions on a web application or any kind of JS apps It uses a Singleton pattern to ensure that only one instance of the module is running at a time. SessionManager is a singleton class that can be used to manage users sessions. For every user that logs in, a new session is created and stored in the database. Every session has a unique ID that is generated by the system. Every session has a setTimeout that expires after a certain time (setSessionTimeout). When a user logs out, the session is deleted from the class. Every action fires an event that can be used to listen to the session manager.

Readme Card https://nodei.co/npm/users-session-manager.png?downloads=true&downloadRank=true&stars=true

Installation

Install with:

npm i users-session-manager

Example of usage:

// Import module with ES6 syntax
import { SessionManager } from 'users-session-manager'
// or
// const SessionManager = require('users-session-manager')

// Create a new instance of the SessionManager class
const SM = new SessionManager()

// Change session Expiration time:
SM.setSessionTimeOut(6)

// Call this to initialize a new user session
SM.loadNewSession("Luca")
SM.loadNewSession("Fabio")

// You can listen to events emitted from this library through eventEmitter object exported
SM.on("activeUserDeleted", (key) => {
    console.log(`User ${key} has been deleted`)
})

setInterval(() => {
    console.log(SM.getLoggedUsers())
}, 5000)

Example of Frontend and Backend session exchange


// Frontend
let session_key = ""

/**
 * Function to call try_login API
 *
 * @param {*} user username text
 * @param {*} pwd password text
 * @return {*} false if wrong login or the user table ROW of the selected user JSON format
 */
async function TryLogin(user, pwd) {
    //console.log(ENDPOINT)
    let credentials = {
        "username": user,
        "password": md5(pwd)
    }
    const rawResponse = await fetch(ENDPOINT + API_ROUTE, {
        method: 'POST',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'api_name': 'try_login'
        },
        body: JSON.stringify(credentials)
    })
    const user_data = await rawResponse.json()
    if (user_data.length > 0)
        session_key = user_data[0].session_key // save session key to the global variable.

        //console.log("user_data: ", user_data)
    return user_data
}

// And on the next calls, you can use the session_key to call the API

/**
 * Function to call get_table_data API
 *
 * @param {*} siteid number
 * @return {*} JSON object
 */
async function GetTableData(page) {
    let body = {
        page
    }
    const rawResponse = await fetch(ENDPOINT + API_ROUTE, {
        method: 'POST',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'session_key': session_key,
            'api_name': 'get_table_data'
        },
        body: JSON.stringify(body)
    })
    const sectors = await rawResponse.json()
    if (sectors.logout) Logout()
        //console.log("sectors: ", sectors)
    return sectors
}

// Backend

// API.js route (cutted from the original file)
...
case 'try_login':
    response = {
        accepted: false,
        message: '',
        user_data: {}
    }
    if (typeof(req.body) === 'object') {
        try {
            const body = req.body
            const db_response = await db.tryLogin(body.username, body.password, true) // true to get the session key
            if (db_response !== false) {
                response.accepted = true
                response.message = 'Welcome! 😘'
                response.user_data = db_response
                response.user_data.session_key = loadNewSession(body.username) // generate a new session key
            } else {
                response.accepted = false
                response.message = 'Wrong username or password... Are you a f**ing HACKER? 💩💩💩'
            }
        } catch (error) {
            response.accepted = false
            response.message = 'Error in API call!'
            response.user_data = null
        } finally {
            res.send(JSON.stringify(response))
        }
    }
    break
case 'get_table_data':
    response = {
        accepted: false,
        message: '',
        table_data: {}
    }
    if (typeof(req.body) === 'object') {
        try {
            const body = req.body
            if (await db.validateApiRequest(req.headers.session_key, "get_data")) {
                const dbResponse = await db.getTableData(body.table)
                if (dbResponse !== false) {
                    response.accepted = true
                    response.message = 'OK'
                    response.table_data = dbResponse
                } else {
                    response.accepted = false
                    response.message = 'Error in API call!'
                    response.table_data = null
                }
            } else {
                response.accepted = false
                response.message = 'Action not allowed!'
                console.warn('Action not allowed! api_name:', api_name)
            }
        } catch (error) {
            response.accepted = false
            response.message = 'Error in API call!'
            response.analytics = null
        } finally {
            res.send(JSON.stringify(response))
        }
    }
    break
...

// In file db.js (cutted from the original file)
...
/** 
 * @async
 * @description Validate the session key
 * @param {string} sessionKey Session key
 * @param {string} action Action to validate
 * @throws Will throw if query to DB will fail
 * @returns {Promise<boolean>} Return true if session key is valid, false otherwise
 */
async function validateApiRequest(sessionKey, action = undefined) {
    const username = getUsernameFromSessionKey(sessionKey)
    if (username) {
        let user_data = undefined
        const query_user_id = {
            text: 'SELECT users_management, dataset_management ' +
                'FROM users WHERE username = $1;',
            values: [username]
        }
        try {
            const userIdRes = await pool.query(query_user_id)
                // console.log('[getUserProfilePic]', userProfilePicPathRes.rows)
            if (!userIdRes.rows.length) {
                user_data = undefined
                return false
            } else {
                /* This may be a string or null */
                user_data = userIdRes.rows[0]
            }
        } catch (err) {
            console.error(err)
            throw err.message
        }
        switch (action) {
            case "get_data":
                {
                    // check data validity here
                }
                break
            default:
                return true
        }
    }
    return false
}
...

Integrate with Socket.io server to notify clients

// Import module with ES6 syntax
import { SessionManager } from '../index.js';

const http = require('http')

// Create a new instance of the SessionManager class
const SM = new SessionManager();

/**
 * Create and start an ioSocket server
 * @param {*} app
 * "Express" handle
 * @param {*} port
 * Port the server should listen on
 * @returns {SocketIO.Server}
 * The newly created server
 */
 function startServer(app, port) {
    // Create an http server
    const server = http.createServer(app)
    server.listen(port)
    server.on('error', function(error) { onError(error, port) })
    server.on('listening', function() { onListening(server) })

    // Create the socketIO server
    const ENDPOINT = `localhost:3000`;
    const { Server } = require("socket.io");
    const io = new Server(server, {
        cors: {
            origin: ENDPOINT,
            methods: ["GET", "POST"]
        }
    });

    io.on('connection', (sk) => {
        console.log('Browser Connected!')
        sk.on('session_key', async function(data) {
            const key = data.session_key
            console.log(`User ${data.user} joined key ${key}`)
            sk.join(key)
        })
    })

    return io
}

SM.initSocketReferences(startServer(app, port)) // Initialize the socket references

SM.on("notifyClientToLogout", (io, key) => { // When a user logs out, notify the client
    console.debug(`Session is expired for key ${key}... Logging out now!`)
    io.in(key).emit('logout') // Emit the logout event to the client
})

Exported APIs

  • eventEmitter: Node.js Event Emitter object, is extended by the class. It fires the following events:
    • 'error': Called when some error happens (eg: Session is rejected)
    • 'sessionDeleted': Called when a session is deleted or if expired
    • 'sessionCreated': Called when a user session is created
    • 'notifyClientToLogout': Called when a session timer is expired, bind this to a Socket.io server to force clients to logout

Integrate with metrics tools like PM2

const io = require('@pm2/io') // Initialize the pm2 io module

// The PM2 IO metrics to monitor the number of connected users
const realtimeUser = io.counter({
    name: 'Realtime Users',
    id: 'app/realtime/users',
})

SM.on("sessionCreated", (key) => { // When a user logs out, notify the client
    realtimeUser.inc() // Increment the number of active users
})

SM.on("sessionDeleted", (key) => { // When a user logs out, notify the client
    realtimeUser.dec() // Decrement the number of active users
})

Classes

SessionManagerEventEmitter

SessionManager is a class that manages the sessions of the users.

Constants

sessions : Object

The sessions of the users.

MIN_SESSION_TIMEOUT : number

The minimum session timeout.

settings : Object

The settings of the session manager.

Functions

log(msg)void

Logs a message to the console if the debug flag is set to true in the config.

SessionManager ⇐ EventEmitter

SessionManager is a class that manages the sessions of the users.

Kind: global class Extends: EventEmitter

sessionManager.setSessionTimeOut(sessionTimeout) ⇒ boolean

This function is used to set the session timeout

Kind: instance method of SessionManager Returns: boolean - true or false: true if ok

ParamTypeDescription
sessionTimeoutnumberThe session timeout in seconds

Example

setSessionTimeOut(3000) // Returns true or false

sessionManager.getSessionTimeout() ⇒ number

This function is used to get the session timeout

Kind: instance method of SessionManager Returns: number - The session timeout in seconds Example

getSessionTimeOut() // Returns 3000

sessionManager.getLoggedUsers() ⇒ array

This function is used to get the list of logged users

Kind: instance method of SessionManager Returns: array - The list of logged users Example

getLoggedUsers() // Returns ['Gino', 'Gino2']

sessionManager.initSocketReference(ioRef) ⇒ boolean

Function to copy the Socket IO http server reference

Kind: instance method of SessionManager Returns: boolean - true or false, true if ok

ParamType
ioRef*

sessionManager.getSocketReference() ⇒ SocketIO.Server

Function to get the socket reference

Kind: instance method of SessionManager Returns: SocketIO.Server - The socket reference

sessionManager.loadNewSession(username) ⇒ string

Function to add users sessions in this module. Use it at login

Kind: instance method of SessionManager Returns: string - user unique key

ParamTypeDescription
usernamestringThe username provided on successful login

Example

addSession('Gino') // Returns 'session_key'

sessionManager.setSessionData(key, data) ⇒ boolean

Function to set the property 'data' of a session. Use it for example to store something in the session, like the user actions history, etc.

Kind: instance method of SessionManager Returns: boolean - true or false, true if ok Throws:

  • Error If the session_key is not found
ParamTypeDescription
keystringThe session_key provided on successful login
dataobjectThe data to be stored in the session

Example

setSessionData('session_key', {'actions': ["logged in", ...]}) // Returns true or false

sessionManager.getSessionData(key) ⇒ object

Function to get the property 'data' of a session. Use it for example to get the user actions history, etc.

Kind: instance method of SessionManager Returns: object - The data stored in the session Throws:

  • Error If the session_key is not found
ParamTypeDescription
keystringThe session_key provided on successful login

Example

getSessionData('session_key') // Returns {'actions': ["logged in", ...]}

sessionManager.restartSessionTimer(key) ⇒ boolean

Function that restart the session timer. Use it after an API call to keep the session alive.

Kind: instance method of SessionManager Returns: boolean - true or false, true if ok Throws:

  • Error If the session key is not found
ParamTypeDescription
keystringThe session_key

Example

restartSessionTimer('session_key') // Returns true or false

sessionManager.getSessionDetails(key) ⇒ object | boolean

Function to get details of a session. Use it to get the username, the creation date and the data.

Kind: instance method of SessionManager Returns: object | boolean - The session details or false if not found Throws:

  • Error If the session key is not found
ParamTypeDescription
keystringThe session_key

Example

getSessionDetails('session_key') // Returns {'username': 'Gino', 'createdAt': 1523456789, 'data': {'actions': ["logged in", ...]}}

sessionManager.deleteSession(key) ⇒ boolean

Function to delete users sessions in this module. Use it at client logout

Kind: instance method of SessionManager
Returns: boolean - true or false, true if ok Throws:

  • Error If the session_key is not found
ParamTypeDescription
keystringThe session_key provided on successful login

Example

deleteSession('session_key') // Returns true or false

sessionManager.deleteAllSessions() ⇒ boolean

Function to delete all sessions

Kind: instance method of SessionManager Returns: boolean - true or false, true if ok

sessionManager.sendLogoutMessage(key) ⇒ boolean

Use this to notify the client to logout with WebSocket

Kind: instance method of SessionManager Returns: boolean - true or false, true if ok

ParamTypeDescription
keystringThe session_key

Example

sendLogoutMessage('session_key') // Returns true or false

sessionManager.createNewSessionTimer(key, username) ⇒ NodeJS.Timeout

Function to return a new setTimeout object and start it.

Kind: instance method of SessionManager

ParamTypeDescription
keystringThe session_key
usernamestringThe username, only for logging features

Example

createNewSessionTimer('session_key', 'username') // Returns a new setTimeout object

sessionManager.checkSessionStatus(key) ⇒ boolean

Use this before every API.js function execution.n the stored collection

Kind: instance method of SessionManager Returns: boolean - true or false: true if session is active Throws:

  • Error if the session is not valid
  • Error if the session is expired
ParamTypeDescription
keystringthe user key generated at login

Example

checkSessionStatus('my_session_key') // true or false

sessionManager.getUsernameFromSessionKey(key) ⇒ string

Function to get the username from a session key

Kind: instance method of SessionManager Returns: string - The username or false if not found

ParamTypeDescription
keystringThe session key

Example

getUsernameFromSessionKey('123456789_123456789') // 'username'

sessions : Object

The sessions of the users.

Kind: global constant

MIN_SESSION_TIMEOUT : number

The minimum session timeout.

Kind: global constant

settings : Object

The settings of the session manager.

Kind: global constant

log(msg) ⇒ void

Logs a message to the console if the debug flag is set to true in the config.

Kind: global function

ParamType
msgstring

Keywords

FAQs

Package last updated on 02 Feb 2022

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc