Server-Side Scripting/Cookies and Sessions/Node.js (Express)
app.js
edit// Demonstrates a complete server-side website using:
// * static HTML and CSS
// * a template
// * a code module
//
// NOTE: Static pages (html, css, images, etc.) are placed in
// a folder named "static". Template pages are placed in a folder
// named "templates".
//
// Folder structure:
// app.js
// hello.js
// static
// index.html
// static.html
// styles.css
// templates
// template.html
//
// References:
// https://repl.it/languages/express
// https://expressjs.com/en/guide/routing.html
// https://www.npmjs.com/package/express-fileupload
// https://www.tutorialspoint.com/expressjs/expressjs_cookies.htm
// https://www.geeksforgeeks.org/session-cookies-in-nodejs/
// https://www.geeksforgeeks.org/node-js-crypto-randombytes-method/
const express = require("express");
const fileUpload = require('express-fileupload');
const cookieParser = require("cookie-parser");
const session = require("express-session");
const crypto = require("crypto");
const app = express();
app.use(express.static(__dirname + '/static'));
app.use(express.urlencoded({
extended: true
}));
app.use(fileUpload({
limits: { fileSize: 1 * 1024 * 1024 },
}));
app.use(cookieParser());
app.use(session({
resave: false,
saveUninitialized: false,
secret: crypto.randomBytes(16).toString("hex")
}));
const fs = require("fs");
fs.readdirSync("./routes").map((filename) => {
const module = require("./routes/" + filename);
const route = filename.replace(".js", "")
app.use("/" + route, module);
});
app.listen(3000, () => console.log('server started'));
routes/lesson12.js
edit// Demonstrates session and cookie processing. The username is stored
// as a cookie and an internal userid is saved in a session variable.
// Also demonstrates secure password authentication using bcrypt salt
// and hash.
//
// References:
// https://en.wikibooks.org/wiki/JavaScript
// https://www.geeksforgeeks.org/http-cookies-in-node-js/
// https://www.geeksforgeeks.org/session-cookies-in-nodejs/
// https://www.npmjs.com/package/bcrypt
const express = require("express");
const bcrypt = require("bcrypt");
const fs = require("fs");
const handlebars = require('handlebars');
const router = express.Router();
users = [
// Password is the same as the username, just salted and hashed.
// Don't do this in a production application! Use custom passwords.
{ "userid": 1, "username": "admin",
"password": "$2b$10$l20wKFNqyzWl9NgeexjQ9el9KY7HzbTAPefSyntaZE.jqJlHZI0Ba" },
{ "userid": 2, "username": "test",
"password": "$2b$10$T.7DuAdfGVzq8uP1.xYZLe8rbPrOE6/DtMqbT5.O/bYwTFMZDC6ru" }
]
router.get("/", function (request, response) {
let username = request.cookies.username;
let userid = request.session.userid;
result = build_form(username, userid);
response.send(result);
});
router.post("/", function (request, response) {
if (request.body["reload"]) {
response.redirect(request.originalUrl);
}
else if (request.body["log-out"]) {
request.session.destroy();
let username = request.cookies.username;
let userid = null;
result = build_form(username, userid);
response.send(result);
}
else if (request.body["forget-me"]) {
request.session.destroy();
result = build_form(null, null);
response.cookie("username", "", { expires: 0 });
response.send(result);
}
else {
let username = request.body.username;
let password = request.body.password;
let userid = authenticateUser(username, password);
if (userid) {
request.session.userid = userid;
result = build_form(username, userid);
response.cookie("username", username);
response.send(result);
}
else {
response.redirect(303, request.originalUrl);
}
}
});
function build_form(username, userid) {
let cookie = !!username;
let session = !!userid;
if (username && userid) {
welcome = "Welcome back " + username + "! You are logged in.";
}
else if (username) {
welcome = "Welcome back " + username + "! Please log in.";
}
else {
welcome = "Welcome! Please log in.";
}
let source = fs.readFileSync("./templates/lesson12.html");
let template = handlebars.compile(source.toString());
let data = {
cookie: cookie,
session: session,
welcome: welcome,
username: username
}
result = template(data);
return result
}
function authenticateUser(username, password) {
for (let index = 0; index < users.length; index++) {
let user = users[index];
if (user.username == username) {
if (bcrypt.compareSync(password, user.password)) {
// Should track successful logins
return user.userid;
} else {
// Should track failed attempts, lock account, etc.
return null;
}
}
}
return null;
}
function generateHashedPassword(password) {
// Use this function to generate hashed passwords to save in
// the users list or a database.
let salt = bcrypt.genSaltSync();
let hashed = bcrypt.hashSync(password, salt);
return hashed
}
module.exports = router;
templates/lesson12.html
edit<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Lesson 12</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Cookies and Sessions</h1>
<p>Cookie: {{cookie}}<br>Session: {{session}}</p>
<p>{{welcome}}</p>
<hr>
<form method="POST">
<p><label for="username">Username:</label>
<input type="text" id="username" name="username" value="{{username}}">
</p>
<p><label for="password">Password:</label>
<input type="password" id="password" name="password">
</p>
<input type="submit" id="log-in" name="log-in" value="Log In">
<input type="submit" id="log-out" name="log-out" value="Log Out">
<input type="submit" id="forget-me" name="forget-me" value="Forget Me">
<input type="submit" id="reload" name="Reload" value="Reload">
</form>
</body>
</html>
Try It
editSee Server-Side Scripting/Routes and Templates/Node.js (Express) to create a test environment.