import { Injectable } from '@nestjs/common'; import { EncryptionAlgorithm } from '../core/domain/username.types'; import * as bcrypt from 'bcrypt'; import * as argon2 from 'argon2'; import { PasswordVerifierPort } from '../core/application/ports/password-verifier.port'; @Injectable() export class PasswordVerifier implements PasswordVerifierPort { verify = async ( passwordToVerify: string, encryptedPassword: string, ): Promise => { const encryptionAlgorithm: EncryptionAlgorithm = this.guessEncryptionAlgorithm(encryptedPassword); switch (encryptionAlgorithm) { case EncryptionAlgorithm.BCRYPT: return await bcrypt.compare(passwordToVerify, encryptedPassword); case EncryptionAlgorithm.ARGON2D: case EncryptionAlgorithm.ARGON2I: case EncryptionAlgorithm.ARGON2ID: return await argon2.verify(encryptedPassword, passwordToVerify, { type: this.argonType(encryptionAlgorithm), }); } }; private guessEncryptionAlgorithm = ( password: string, ): EncryptionAlgorithm => { if (password.substring(1, 9) === 'argon2id') return EncryptionAlgorithm.ARGON2ID; if (password.substring(1, 8) === 'argon2i') return EncryptionAlgorithm.ARGON2I; if (password.substring(1, 8) === 'argon2d') return EncryptionAlgorithm.ARGON2D; return EncryptionAlgorithm.BCRYPT; }; private argonType = ( encryptionAlgorithm: EncryptionAlgorithm, ): typeof argon2.argon2d | typeof argon2.argon2i | typeof argon2.argon2id => { switch (encryptionAlgorithm) { case EncryptionAlgorithm.ARGON2D: return argon2.argon2d; case EncryptionAlgorithm.ARGON2I: return argon2.argon2i; default: return argon2.argon2id; } }; }