npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

users-session-manager

v1.0.16

Published

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

Downloads

219

Readme

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

Constants

Functions

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

| Param | Type | Description | | --- | --- | --- | | sessionTimeout | number | The 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

| Param | Type | | --- | --- | | 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

| Param | Type | Description | | --- | --- | --- | | username | string | The 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

| Param | Type | Description | | --- | --- | --- | | key | string | The session_key provided on successful login | | data | object | The 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

| Param | Type | Description | | --- | --- | --- | | key | string | The 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

| Param | Type | Description | | --- | --- | --- | | key | string | The 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

| Param | Type | Description | | --- | --- | --- | | key | string | The 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

| Param | Type | Description | | --- | --- | --- | | key | string | The 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

| Param | Type | Description | | --- | --- | --- | | key | string | The 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

| Param | Type | Description | | --- | --- | --- | | key | string | The session_key | | username | string | The 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

| Param | Type | Description | | --- | --- | --- | | key | string | the 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

| Param | Type | Description | | --- | --- | --- | | key | string | The 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

| Param | Type | | --- | --- | | msg | string |