import { IRepository , InetLocation , IService , RefreshToken , IAuthDependencies , LoginToken , LoggedInUser , Consts , Account , IVerificationGeneratorDependencies , Messages } from '@btcp/bootcamp-entities' ; import { RefreshTokenService } from './refresh-token.service' ; import { UnauthorizedException , ConflictException , NotFoundException } from './exceptions' ; export class AuthService implements IService { HOURS_TO_BLOCK = Consts . HOURS_TO_BLOCK ; LOGIN_ATTEMPTS_TO_BLOCK = Consts . LOGIN_ATTEMPTS_TO_BLOCK ; private readonly _utils : IAuthDependencies ; private readonly _verificationGenerator : IVerificationGeneratorDependencies ; private readonly _repository : IRepository < string , Account > ; private readonly _refreshToken : RefreshTokenService ; constructor ( repository , authDependencies , verificationGenerator , refreshToken ) { this . _repository = repository ; this . _utils = authDependencies ; this . _verificationGenerator = verificationGenerator ; this . _refreshToken = refreshToken ; } async createAccessToken ( payload ) { return this . _utils . getAccessToken ( payload ) ; } async createRefreshToken ( userId , inetLoc ) { const refreshTokenDto = new RefreshToken ( ) ; refreshTokenDto . id = userId ; refreshTokenDto . refreshToken = this . _verificationGenerator . createVerificationCode ( ) ; refreshTokenDto . ip = inetLoc . ip ; refreshTokenDto . browser = inetLoc . browser ; refreshTokenDto . country = inetLoc . country ; await this . _refreshToken . save ( refreshTokenDto ) ; return refreshTokenDto . refreshToken ; } async findRefreshToken ( token ) { const refreshToken = await this . _refreshToken . findToken ( token ) ; if ( ! refreshToken ) { throw new UnauthorizedException ( Messages . USER_LOGGED_OUT ) ; } return refreshToken . id ; } async createLoginToken ( payload , inetLocation ) { return { access_token : await this . createAccessToken ( payload ) , refresh_token : await this . createRefreshToken ( payload . sub , inetLocation ) } as LoginToken ; } async validateUser ( username , pass ) { const user = await this . _repository . getByQuery ( { email : username , verified : true } ) ; if ( ! user ) { return null ; } this . isUserBlocked ( user ) ; await this . checkPassword ( pass , user ) ; await this . passwordsAreMatch ( user ) ; const retUser = { userId : user . id , firstName : user . firstName , lastName : user . lastName , username : user . email , roles : user . roles } ; return retUser ; } private isUserBlocked ( user ) { if ( user . blockExpires > Date . now ( ) ) { throw new ConflictException ( Messages . USER_HAS_BEEN_BLOCKED ) ; } } private async checkPassword ( attemptPass , user ) { const match = await this . _utils . encryptedCompare ( attemptPass , user . pw ) ; if ( ! match ) { await this . passwordsDoNotMatch ( user ) ; throw new NotFoundException ( Messages . WRONG_EMAIL_PASSWORD ) ; } return match ; } private async passwordsAreMatch ( user ) { user . loginAttempts = 0 ; await this . _repository . save ( user ) ; } private async blockUser ( user ) { user . blockExpires = this . _verificationGenerator . getExpirationDate ( this . HOURS_TO_BLOCK ) ; await this . _repository . save ( user ) ; } private async passwordsDoNotMatch ( user ) { user . loginAttempts += 1 ; await this . _repository . save ( user ) ; if ( user . loginAttempts >= this . LOGIN_ATTEMPTS_TO_BLOCK ) { await this . blockUser ( user ) ; throw new ConflictException ( Messages . USER_BLOCKED ) ; } } }