import { IsBoolean, IsEmail, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID } from 'class-validator'; import * as jsonwebtoken from "jsonwebtoken"; import { config } from './config'; import { User } from './models/entities/User'; /** * This class is responsible for all things JWT creation. */ export class JwtCreator { /** * Creates a new refresh token for a given user * @param user User entity that the refresh token shall be created for * @param expiry_timestamp Timestamp for the token expiry. Will be generated if not provided. */ public static createRefresh(user: User, expiry_timestamp?: number) { if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 10 * 36000; } return jsonwebtoken.sign({ refreshTokenCount: user.refreshTokenCount, id: user.id, exp: expiry_timestamp }, config.jwt_secret) } /** * Creates a new access token for a given user * @param user User entity that the access token shall be created for * @param expiry_timestamp Timestamp for the token expiry. Will be generated if not provided. */ public static createAccess(user: User, expiry_timestamp?: number) { if (!expiry_timestamp) { expiry_timestamp = Math.floor(Date.now() / 1000) + 10 * 36000; } return jsonwebtoken.sign({ userdetails: new JwtUser(user), exp: expiry_timestamp }, config.jwt_secret) } /** * Creates a new password reset token for a given user. * The token is valid for 15 minutes or 1 use - whatever comes first. * @param user User entity that the password reset token shall be created for */ public static createReset(user: User) { let expiry_timestamp = Math.floor(Date.now() / 1000) + 15 * 60; return jsonwebtoken.sign({ id: user.id, refreshTokenCount: user.refreshTokenCount, exp: expiry_timestamp }, config.jwt_secret) } } /** * Special variant of the user class that */ export class JwtUser { @IsInt() id: number; @IsUUID(4) uuid: string; @IsOptional() @IsEmail() email?: string; @IsOptional() @IsString() username?: string; @IsString() @IsNotEmpty() firstname: string; @IsString() @IsOptional() middlename?: string; @IsString() @IsNotEmpty() lastname: string; permissions: string[]; @IsBoolean() enabled: boolean; @IsInt() @IsNotEmpty() refreshTokenCount?: number; @IsString() @IsOptional() profilePic?: string; /** * Creates a new instance of this class based on a provided user entity. * @param user User entity that shall be encapsulated in a jwt. */ public constructor(user: User) { this.id = user.id; this.firstname = user.firstname; this.middlename = user.middlename; this.lastname = user.lastname; this.username = user.username; this.email = user.email; this.refreshTokenCount = user.refreshTokenCount; this.uuid = user.uuid; this.profilePic = user.profilePic; this.permissions = this.getPermissions(user); } /** * Handels getting the permissions granted to this user (direct or indirect). * @param user User which's permissions shall be gotten. */ public getPermissions(user: User): string[] { let returnPermissions: string[] = new Array(); for (let permission of user.permissions) { returnPermissions.push(permission.toString()); } for (let group of user.groups) { for (let permission of group.permissions) { returnPermissions.push(permission.toString()); } } return Array.from(new Set(returnPermissions)); } }