Dr. Greg M. Bernstein
Update October 19th, 2021
express-session 1Express Middleware to help us:
express-session 2Uses other packages for:
request parameter for easy use by our software.Example files in: SessionJSONExample.zip. Start of a tour company JSON API
/tours, GET: returns list of tours in JSON/login, POST: takes email and password, returns user info/logout, GET: ends the session/addTour, POST: takes tour data, only admin usersFrom tourServer.mjs
import express from 'express';
const app = express(); 
import session from 'express-session';
import bcrypt from 'bcryptjs';
const cookieName = "TourSid"; // Session ID cookie name, use this to delete cookies too.
app.use(session({
    secret: 'website development CSUEB',
    resave: false,
    saveUninitialized: false,
    name: cookieName // Sets the name of the cookie used by the session middleware
}));
// Fake user and tour data
import { readFile } from 'fs/promises';
const users = JSON.parse(await readFile(new URL('./secUsers.json',
    import.meta.url)));
const tours = JSON.parse(await readFile(new URL('./tours.json',
    import.meta.url)));From tourServer.mjs, uses middleware
// This initializes session state
function setUpSessionMiddleware(req, res, next) {
    console.log(`\nsession object: ${JSON.stringify(req.session)}`);
    console.log(`session id: ${req.session.id}`);
    if (!req.session.user) {
        req.session.user = { role: "guest" };
    };
    next();
};
app.use(setUpSessionMiddleware);From tourServer.mjs
// Use this middleware to restrict paths to only logged in users
function checkCustomerMiddleware(req, res, next) {
    if (req.session.user.role === "guest") {
        res.status(401).json({ error: "Not permitted" });;
    } else {
        //      console.log(`\nSession info: ${JSON.stringify(req.session)} \n`);
        next();
    }
};
// Use this middleware to restrict paths only to admins
function checkAdminMiddleware(req, res, next) {
    if (req.session.user.role !== "admin") {
        res.status(401).json({ error: "Not permitted" });;
    } else {
        next();
    }
};From tourServer.mjs
// Only available to admin, returns updated tour list.
app.post('/addTour', checkAdminMiddleware, express.json(), function(req, res) {
    let temp = req.body;
    //  console.log(temp);
    // Note need to check input here to prevent injection attacks
    let event = {
        name: temp.name,
        date: temp.date,
    };
    tours.virtTours.push(event);
    res.json(tours.virtTours);
});From tourServer.mjs
// Available to all visitors, returns user info if successful
app.post('/login', express.json(), function(req, res) {
    let email = req.body.email;
    let password = req.body.password;
    // Find user
    let auser = users.find(function(user) {
        return user.email === email
    });
    if (!auser) { // Not found
        res.status(401).json({ error: true, message: "User/Password error" });
        return;
    }
    let verified = bcrypt.compareSync(password, auser.passHash);
    if (verified) {
        // Upgrade in priveledge, should generate new session id
        // Save old session information if any, create a new session
        let oldInfo = req.session.user;
        req.session.regenerate(function(err) {
            if (err) {
                console.log(err);
            }
            let newUserInfo = Object.assign(oldInfo, auser);
            delete newUserInfo.passHash;
            req.session.user = newUserInfo;
            res.json(newUserInfo);
        });
    } else {
        res.status(401).json({ error: true, message: "User/Password error" });
    }
});Using a Node.js program, addTourTest.mjs
/* Testing the POST /tours/add API */
import fetch from "node-fetch";
import urlBase from './testURL.mjs';
function extractCookies(rawStrings) {
    let cookies = [];
    rawStrings.forEach(function(ck) {
        cookies.push(ck.split(";")[0]); // Just grabs cookie name=value part
    });
    return cookies.join(";"); // If more than one cookie join with ;
}
let addTour = {
    url: urlBase + "addTour",
    options: {
        method: "POST",
        body: JSON.stringify({
            name: "Windsurf K2-18b, 110 Light Years",
            date: "Sometime in 2025",
        }),
        headers: { "Content-Type": "application/json" },
    },
};
let loginAdmin = {
    url: urlBase + "login",
    options: {
        method: "POST",
        body: JSON.stringify({
            // admin user, see users.json file
            email: "antisun1921@outlook.com",
            password: "R.r<E&xt",
        }),
        headers: { "Content-Type": "application/json" },
    },
};
let loginCust = {
    url: urlBase + "login",
    options: {
        method: "POST",
        body: JSON.stringify({
            // admin user, see users.json file
            email: "stedhorses1903@yahoo.com",
            password: "nMQs)5Vi",
        }),
        headers: { "Content-Type": "application/json" },
    },
};
async function someTests() {
    console.log("Try adding tour without logging in");
    try {
        let res = await fetch(addTour.url, addTour.options);
        console.log(`Add Tour result: ${res.statusText}`);
    } catch (e) {
        console.log(`Error: ${e}\n`);
    }
    console.log("Login as admin, then adding tour");
    try {
        let res = await fetch(loginAdmin.url, loginAdmin.options);
        console.log(`login results: ${res.statusText}`);
        // Look at the cookie
        let savedCookie = extractCookies(res.headers.raw()["set-cookie"]);
        console.log(`Saved cookie: ${savedCookie}`);
        addTour.options.headers.cookie = savedCookie;
        // User info from login
        let userInfo = await res.json();
        console.log(userInfo);
        res = await fetch(addTour.url, addTour.options);
        console.log(`Add Tour result: ${res.statusText}\n`);
        let data = await res.json();
        console.log(data);
    } catch (e) {
        console.log(`Error: ${e}\n`);
    }
    console.log("Login as customer, then try adding tour");
    try {
        let res = await fetch(loginCust.url, loginCust.options);
        console.log(`login results: ${res.statusText}`);
        // Look at the cookie
        let savedCookie = extractCookies(res.headers.raw()["set-cookie"]);
        console.log(`Saved cookie: ${savedCookie}`);
        addTour.options.headers.cookie = savedCookie;
        // User info from login
        let userInfo = await res.json();
        console.log(userInfo);
        res = await fetch(addTour.url, addTour.options);
        console.log(`Add Tour result: ${res.statusText}\n`);
        let data = await res.json();
        console.log(data);
    } catch (e) {
        console.log(`Error: ${e}\n`);
    }
}
someTests();From tourServer.mjs
app.get('/logout', function (req, res) {
    let options = req.session.cookie;
    req.session.destroy(function (err) {
        if (err) {
            console.log(err);
        }
        res.clearCookie(cookieName, options); // the cookie name and options
        res.json({message: "Goodbye"});
    })
});