import * as request from 'web-request' ; import { injectable } from 'inversify' ; import config from '../config' ; import { MaxVerificationsAttemptsReached , NotCorrectVerificationCode , VerificationIsNotFound } from '../exceptions/exceptions' ; import { Logger } from '../logger' ; const QR = require ( 'qr-image' ) ; @ injectable ( ) export class VerificationClient implements VerificationClientInterface { private logger = Logger . getInstance ( 'VERIFICATION_CLIENT' ) ; tenantToken : string ; baseUrl : string ; constructor ( baseUrl ) { request . defaults ( { headers : { 'Accept' : 'application/json' , 'Content-Type' : 'application/json' } , throwResponseError : true } ) ; this . baseUrl = baseUrl ; this . tenantToken = config . auth . token ; } async initiateVerification ( method , data ) { try { const result = await request . json < InitiateResult > ( `/methods/${ method }/actions/initiate` , { baseUrl : this . baseUrl , auth : { bearer : this . tenantToken } , method : 'POST' , body : data } ) ; result . method = method ; delete result . code ; if ( result . totpUri ) { const buffer = QR . imageSync ( result . totpUri , { type : 'png' , size : 20 } ) ; result . qrPngDataUri = 'data:image/png;base64,' + buffer . toString ( 'base64' ) ; } return result ; } catch ( error ) { this . logger . exception ( 'Initiate' , error ) ; throw error ; } } async resendVerification ( method , data ) { try { const result = await request . json < InitiateResult > ( `/methods/${ method }/actions/resend` , { baseUrl : this . baseUrl , auth : { bearer : this . tenantToken } , method : 'POST' , body : data } ) ; result . method = method ; return result ; } catch ( error ) { this . logger . exception ( 'Resend' , error ) ; throw error ; } } async validateVerification ( method , id , input ) { try { return await request . json < ValidationResult > ( `/methods/${ method }/verifiers/${ id }/actions/validate` , { baseUrl : this . baseUrl , auth : { bearer : this . tenantToken } , method : 'POST' , body : input } ) ; } catch ( e ) { if ( e . statusCode === 422 ) { if ( e . response . body . data . attempts >= config . verify . maxAttempts ) { await this . invalidateVerification ( method , id ) ; throw new MaxVerificationsAttemptsReached ( 'You have used all attempts to enter code' ) ; } throw new NotCorrectVerificationCode ( 'Not correct code' ) ; } if ( e . statusCode === 404 ) { throw new VerificationIsNotFound ( 'Code was expired or not found. Please retry' ) ; } this . logger . exception ( 'Validate' , e ) ; throw e ; } } async invalidateVerification ( method , id ) { await request . json < Result > ( `/methods/${ method }/verifiers/${ id }` , { baseUrl : this . baseUrl , auth : { bearer : this . tenantToken } , method : 'DELETE' } ) ; } async getVerification ( method , id ) { try { return await request . json < ValidationResult > ( `/methods/${ method }/verifiers/${ id }` , { baseUrl : this . baseUrl , auth : { bearer : this . tenantToken } , method : 'GET' } ) ; } catch ( e ) { if ( e . statusCode === 404 ) { throw new VerificationIsNotFound ( 'Code was expired or not found. Please retry' ) ; } this . logger . exception ( 'getVerification' , e ) ; throw e ; } } async checkVerificationPayloadAndCode ( inputVerification , consumer , payload , removeSecret ? ) { const verification = await this . getVerification ( inputVerification . method , inputVerification . verificationId ) ; if ( verification . data . consumer !== consumer || JSON . stringify ( verification . data . payload ) !== JSON . stringify ( payload ) ) { throw new Error ( 'Invalid verification payload' ) ; } return await this . validateVerification ( inputVerification . method , inputVerification . verificationId , { code : inputVerification . code , removeSecret } ) ; } } const VerificationClientType = Symbol ( 'VerificationClientInterface' ) ; export { VerificationClientType } ;