/* eslint-disable @typescript-eslint/no-non-null-assertion */ import jwt from 'jsonwebtoken'; import { Response } from 'express'; import { createHash } from 'crypto'; import * as Db from '@/Db'; import { AUTH_COOKIE_NAME } from '@/constants'; import { JwtPayload, JwtToken } from '../Interfaces'; import { User } from '@db/entities/User'; import config from '@/config'; export function issueJWT(user: User): JwtToken { const { id, email, password } = user; const expiresIn = 7 * 86400000; // 7 days const payload: JwtPayload = { id, email, password: password ?? null, }; if (password) { payload.password = createHash('sha256') .update(password.slice(password.length / 2)) .digest('hex'); } const signedToken = jwt.sign(payload, config.getEnv('userManagement.jwtSecret'), { expiresIn: expiresIn / 1000 /* in seconds */, }); return { token: signedToken, expiresIn, }; } export async function resolveJwtContent(jwtPayload: JwtPayload): Promise { const user = await Db.collections.User.findOne(jwtPayload.id, { relations: ['globalRole'], }); let passwordHash = null; if (user?.password) { passwordHash = createHash('sha256') .update(user.password.slice(user.password.length / 2)) .digest('hex'); } if (!user || jwtPayload.password !== passwordHash || user.email !== jwtPayload.email) { // When owner hasn't been set up, the default user // won't have email nor password (both equals null) throw new Error('Invalid token content'); } return user; } export async function resolveJwt(token: string): Promise { const jwtPayload = jwt.verify(token, config.getEnv('userManagement.jwtSecret')) as JwtPayload; return resolveJwtContent(jwtPayload); } export async function issueCookie(res: Response, user: User): Promise { const userData = issueJWT(user); res.cookie(AUTH_COOKIE_NAME, userData.token, { maxAge: userData.expiresIn, httpOnly: true, sameSite: 'lax', }); }