import { ApiService } from "../abstractions/api.service" ; import { AuditService as AuditServiceAbstraction } from "../abstractions/audit.service" ; import { CryptoFunctionService } from "../abstractions/cryptoFunction.service" ; import { throttle } from "../misc/throttle" ; import { Utils } from "../misc/utils" ; import { BreachAccountResponse } from "../models/response/breachAccountResponse" ; import { ErrorResponse } from "../models/response/errorResponse" ; const PwnedPasswordsApi = "https://api.pwnedpasswords.com/range/" ; export class AuditService implements AuditServiceAbstraction { constructor ( private cryptoFunctionService , private apiService ) { } @ throttle ( 100 , ( ) => "passwordLeaked" ) async passwordLeaked ( password ) { const hashBytes = await this . cryptoFunctionService . hash ( password , "sha1" ) ; const hash = Utils . fromBufferToHex ( hashBytes ) . toUpperCase ( ) ; const hashStart = hash . substr ( 0 , 5 ) ; const hashEnding = hash . substr ( 5 ) ; const response = await this . apiService . nativeFetch ( new Request ( PwnedPasswordsApi + hashStart ) ) ; const leakedHashes = await response . text ( ) ; const match = leakedHashes . split ( /\r?\n/ ) . find ( ( v ) => { return v . split ( ":" ) [ 0 ] === hashEnding ; } ) ; return match != null ? parseInt ( match . split ( ":" ) [ 1 ] , 10 ) : 0 ; } async breachedAccounts ( username ) { try { return await this . apiService . getHibpBreach ( username ) ; } catch ( e ) { const error = e as ErrorResponse ; if ( error . statusCode === 404 ) { return [ ] ; } throw new Error ( ) ; } } }