UNPKG

@tomei/sso

Version:
188 lines (168 loc) 6.1 kB
import { ClassError, ObjectBase } from '@tomei/general'; import { ComponentConfig } from '@tomei/config'; import { IUserPasswordHistoryAttr } from '../../interfaces/user-password-history.interface'; import { UserPasswordHistoryRepository } from './user-password-history.repository'; import { PasswordHashService } from '../../components/password-hash'; export class UserPasswordHistory extends ObjectBase implements IUserPasswordHistoryAttr { ObjectId: string; ObjectName: string; ObjectType = 'UserPasswordHistory'; TableName = 'sso_UserPasswordHistory'; UserId: number; PasswordHash: string; private _CreatedAt: Date; private static _Repo = new UserPasswordHistoryRepository(); get HistoryId(): string { return this.ObjectId; } set HistoryId(value: string) { this.ObjectId = value; } get CreatedAt(): Date { return this._CreatedAt; } private constructor(params?: IUserPasswordHistoryAttr) { super(); if (params) { this.ObjectId = params.HistoryId; this.UserId = params.UserId; this.PasswordHash = params.PasswordHash; this._CreatedAt = params.CreatedAt; } } public static async init( historyId?: number, dbTransaction?: any, ): Promise<UserPasswordHistory> { try { if (historyId) { const data = await UserPasswordHistory._Repo.findByPk( historyId.toString(), dbTransaction, ); if (!data) { throw new ClassError( 'UserPasswordHistory', 'UserPasswordHistoryErrMsg01', 'UserPasswordHistory not found', 'init', 400, ); } return new UserPasswordHistory(data.get({ plain: true })); } return new UserPasswordHistory(); } catch (error) { throw error; } } public static async validate( dbTransaction: any, UserId: number, Password: string, passwordHashService: PasswordHashService, ): Promise<void> { // This method used to check if password entered is valid by checking previous password history try { // Part 1-2: Retrieve password history policy by using component config, call ComponentConfig. by passing: // - ComponentName: "@tomei/sso" // - ConfigKey: "passwordHistory" // If no password history set, use default value 3 const passwordHistoryPolicy = ComponentConfig.getComponentConfigValue( '@tomei/sso', 'passwordHistory', ) || 3; // Part 3-4: Retrieve records from the table by using class._repo findAll() by passing: // where: { UserId: params.UserId } // order: [['CreatedAt', 'DESC']] // limit: passwordHistory count above. // If no record found, return null. let passwordHistory = await UserPasswordHistory._Repo.findAll({ where: { UserId: UserId }, order: [['CreatedAt', 'DESC']], limit: passwordHistoryPolicy, transaction: dbTransaction, }); if (passwordHistory?.length < 1) { return null; } else { // Part 5: If record found, map each record to compare params.Password and record.PasswordHash using the params.passwordHashService. If match, stop the mapping, and return ClassError: // ClassName: "UserPasswordHistory" // MethodName: "validate" // MessageCode: "UserPasswordHistory01" // Message: You cannot reuse your last ${passwordHistory} passwords. Please choose a new and unique password. for (let index = 0; index < passwordHistory.length; index++) { const isPasswordSame = await passwordHashService.verify( Password, passwordHistory[index].PasswordHash, ); if (isPasswordSame) { throw new ClassError( 'UserPasswordHistory', 'UserPasswordHistory01', `You cannot reuse your last ${passwordHistoryPolicy} passwords. Please choose a new and unique password.`, 'validate', 403, ); } } } } catch (error) { throw error; } } public static async create( dbTransaction: any, UserId: number, PasswordHash: string, ): Promise<void> { // This method used to check if password entered is valid by checking previous password history try { // Part 1-2: Retrieve password history policy by using component config, call ComponentConfig. by passing: // - ComponentName: "@tomei/sso" // - ConfigKey: "passwordHistory" // If no password history set, use default value 3 const passwordHistoryPolicy = ComponentConfig.getComponentConfigValue( '@tomei/sso', 'passwordHistory', ) || 3; // Part 3: Insert new password history by calling class _repo create() method. const userPasswordHistory = new UserPasswordHistory(); let passwordHistory = await UserPasswordHistory._Repo.create( { HistoryId: userPasswordHistory.createId(), UserId: UserId, PasswordHash: PasswordHash, }, { transaction: dbTransaction, }, ); // Part 3: When inserted successfully, retrieve all the password history for the user to check // how many previous password records. If records more than the passwordHistory count from // config. Remove the oldest record. if (passwordHistory) { let passwordHistoryList = await UserPasswordHistory._Repo.findAll({ where: { UserId: UserId }, order: [['CreatedAt', 'DESC']], transaction: dbTransaction, }); if (passwordHistoryList.length > passwordHistoryPolicy) { let deleteList = passwordHistoryList.slice(passwordHistoryPolicy); let historyIdList = deleteList.map((record) => record.HistoryId); await UserPasswordHistory._Repo.destroyMultiple( historyIdList, dbTransaction, ); } } } catch (error) { throw error; } } }