/** * Authentication helper functions. * @module app/services/authentication/helpers */ import jsonwebtoken from "jsonwebtoken"; import expressJwt from "express-jwt"; import { createHmac, createHash, randomBytes } from "crypto"; /** * Generate a random secret * @return {string} a random 64-byte secret token */ export const generateSecret = () => randomBytes(64).toString("hex"); /** * Store a password as SHA256 using the secret token * @param {string} plainPassword the plaintext password * @return {string} the sha256 of the password */ export const encryptPassword = (plainPassword) => createHmac("sha256", process.env.TOKEN_SECRET) .update(plainPassword, "utf8") .digest("hex"); /** * Generate a JSON web token with the desired payload. * @param {Object} payload the object to attach to the JWT * @return {string} a JSON web token */ export const generateAccessToken = (payload) => jsonwebtoken.sign(payload, process.env.TOKEN_SECRET); /** * Middleware to encrypt any passwords before they hit the database. */ export const storeEncryptedPassword = (request, response, next) => { if (request.body.password) { request.body.password = encryptPassword(request.body.password); } next(); }; /** * Hash a password, used in testing and when seeding the databse. * Typically the passwords are hashed on the client side before being transmitted, * and then hashed again before being inserted into the database. * @param {string} plaintext the plaintext password * @return {string} the SHA256 of the password */ export function hashPassword(plaintext) { return createHash("sha256").update(plaintext, "utf8").digest("base64"); } /** * Express JWT middleware. * @param {object} options options to pass to express-jwt * @return {Function} the express-jwt middleware */ export function checkAccessToken(options = {}) { if (!process.env.TOKEN_SECRET) return null; return expressJwt({ secret: process.env.TOKEN_SECRET, algorithms: ["HS256"], credentialsRequired: true, ...options, }); } /** * Middleware to check if a user is active before performing an API call. */ export async function checkUserIsActive(request, response, next) { const User = request.bookshelf.model("User"); const user = await new User({ user_id: request.user.user_id, }).fetch(); if (!user.get("is_active")) { next(new Error("UserNotActive")); } else { next(); } }