import bCrypt from "bcryptjs"; import { AggregateRoot, Email, IDomainError, Name, Result, UniqueID, } from "@shared/contexts"; export interface IUserProps { name: Name; email: Email; password?: string; hashed_password?: string; } export interface IUser { id: UniqueID; name: Name; email: Email; hashed_password: string; verifyPassword: (candidatePassword: string) => boolean; } export class User extends AggregateRoot implements IUser { public static create( props: IUserProps, id?: UniqueID, ): Result { //const isNew = !!id === false; // Se hace en el constructor de la Entidad /* if (isNew) { id = UniqueEntityID.create(); }*/ const user = new User(props, id); return Result.ok(user); } public static async hashPassword(password): Promise { return hashPassword(password, await genSalt()); } private _hashed_password: string; private constructor(props: IUserProps, id?: UniqueID) { super({ ...props, password: "", hashed_password: "" }, id); this._protectPassword(props); } get name(): Name { return this.props.name; } get email(): Email { return this.props.email; } get hashed_password(): string { return this._hashed_password; } public verifyPassword(candidatePassword: string): boolean { return bCrypt.compareSync(candidatePassword, this._hashed_password!); } private async _protectPassword(props: IUserProps) { const { password, hashed_password } = props; if (password) { this._hashed_password = await User.hashPassword(password); } else { this._hashed_password = hashed_password!; } } } async function genSalt(rounds = 10): Promise { return new Promise((resolve, reject) => { bCrypt.genSalt(rounds, function (err, salt) { if (err) return reject(err); return resolve(salt); }); }); } async function hashPassword(password: string, salt: string): Promise { return new Promise((resolve, reject) => { bCrypt.hash(password, salt, function (err, hash) { if (err) return reject(err); return resolve(hash); }); }); } User.hashPassword("123456").then((value) => console.log(value));