import { NextFunction, Request, Response } from "express" import path from "path" import { constants, promises as fs } from "fs" import { verify, sign } from "jsonwebtoken" import config from "../config" type AuthorizedRequest = Request & { headers: { authorization: string } } let cachedSecret: string const SECRET_PATH = path.resolve(process.cwd(), "access/jwt_secret.json") getSecret() // Necessary until we can make async express middleware export function secure(request: AuthorizedRequest, response: Response, next: NextFunction): void { if (!cachedSecret) { response.status(408).json({ error: "Server still loading", }) return } const rawToken = request.headers.authorization const token1 = rawToken && rawToken.split(/\s/)[1] const token2 = request.cookies?.jwt const token = token1 || token2 verify(token, cachedSecret, (tokenError: any, decoded: any) => { if (tokenError) { response.status(200).json({ error: "Accès interdit sans identification", }) return } response.locals.jwt = decoded next() }) } let hasSecretReturn: boolean | undefined export async function hasSecret(): Promise { if (hasSecretReturn !== undefined) { return hasSecretReturn } try { // eslint-disable-next-line no-bitwise await fs.access(SECRET_PATH, constants.R_OK | constants.W_OK) hasSecretReturn = true } catch { hasSecretReturn = false } return hasSecretReturn } async function getSecret() { if (!cachedSecret) { try { const secretContent = await fs.readFile(SECRET_PATH) cachedSecret = secretContent && JSON.parse(secretContent.toString()).secret } catch (e: any) { cachedSecret = config.DEV_JWT_SECRET } } return cachedSecret } export async function getJwt(id: number, roles: string[]): Promise { const jwt = sign( { id, roles }, await getSecret() // __TEST__ // ? undefined // : { // expiresIn: "365d", // } ) return jwt }