import { Component , Input , NgZone , OnDestroy , OnInit } from "@angular/core" ; import { Vibration } from "@ionic-native/vibration/ngx" ; import { AlertController , ModalController , NavController , NavParams , Platform , } from "@ionic/angular" ; import { TranslateService } from "@ngx-translate/core" ; import lodash from "lodash" ; import moment from "moment" ; import { Subscription , timer } from "rxjs" ; import { finalize , map , takeWhile } from "rxjs/operators" ; import * as constants from "@/app/app.constants" ; import { AuthProvider } from "@/services/auth/auth" ; @ Component ( { selector : "modal-pin-code" , templateUrl : "pin-code.html" , styleUrls : [ "pin-code.pcss" ] , providers : [ Vibration ] , } ) export class PinCodeModal implements OnInit , OnDestroy { public password : string ; public isWrong = false ; public unlockDiff = 0 ; public unlockCountdown$ : Subscription ; @ Input ( ) public message : string ; @ Input ( ) private expectedPassword : string ; @ Input ( ) private outputPassword = false ; @ Input ( ) private validatePassword = false ; private length = 6 ; private attempts = 0 ; constructor ( public platform , public navCtrl , public navParams , public modalCtrl , private authProvider , private zone , private vibration , private alertCtrl , private translateService ) { this . password = "" ; } add ( value ) { if ( this . unlockDiff > 0 ) { return ; } if ( this . password . length < this . length ) { this . zone . run ( ( ) => { this . password = this . password + value ; } ) ; if ( this . password . length === this . length ) { if ( ! this . expectedPassword && ! this . validatePassword ) { if ( this . authProvider . isWeakPassword ( this . password ) ) { this . translateService . get ( [ "PIN_CODE.WEAK_PIN" , "PIN_CODE.WEAK_PIN_DETAIL" , "NO" , "YES" , ] ) . subscribe ( async ( translation ) => { const alert = await this . alertCtrl . create ( { header : translation [ "PIN_CODE.WEAK_PIN" ] , message : translation [ "PIN_CODE.WEAK_PIN_DETAIL" ] , buttons : [ { text : translation . NO , handler : ( ) => { this . password = "" ; } , } , { text : translation . YES , handler : ( ) => { this . dismiss ( true ) ; } , } , ] , } ) ; alert . present ( ) ; } ) ; } else { return this . dismiss ( true ) ; } } if ( this . expectedPassword ) { if ( this . expectedPassword !== this . password ) { this . setWrong ( ) ; } else { this . dismiss ( true ) ; } } if ( this . validatePassword ) { this . authProvider . validateMasterPassword ( this . password ) . subscribe ( ( result ) => { if ( ! result ) { this . setWrong ( ) ; } else { this . dismiss ( true ) ; } } ) ; } } } } verifyAttempts ( ) { if ( this . attempts >= constants . PIN_ATTEMPTS_LIMIT ) { this . authProvider . increaseUnlockTimestamp ( ) . then ( ( ) => this . loadUnlockTime ( ) ) ; } } setWrong ( ) { this . vibration . vibrate ( constants . VIBRATION_TIME_LONG_MS ) ; this . authProvider . increaseAttempts ( ) . subscribe ( ( newAttempts ) => { this . attempts = newAttempts ; this . verifyAttempts ( ) ; this . zone . run ( ( ) => { this . isWrong = true ; this . password = "" ; this . message = "PIN_CODE.WRONG" ; setTimeout ( ( ) => ( this . isWrong = false ) , 500 ) ; } ) ; } ) ; } delete ( ) { if ( this . password . length > 0 ) { this . zone . run ( ( ) => { this . password = this . password . substring ( 0 , this . password . length - 1 ) ; } ) ; } } dismiss ( status = true ) { if ( ! status ) { return this . modalCtrl . dismiss ( ) ; } if ( status ) { this . authProvider . clearAttempts ( ) . subscribe ( ) ; } if ( this . outputPassword ) { this . modalCtrl . dismiss ( this . password ) ; return ; } this . modalCtrl . dismiss ( status ) ; } ngOnInit ( ) { this . authProvider . getAttempts ( ) . subscribe ( ( attempts ) => ( this . attempts = attempts ) ) ; this . loadUnlockTime ( ) ; } ngOnDestroy ( ) { if ( this . unlockCountdown$ ) { this . unlockCountdown$ . unsubscribe ( ) ; } } private loadUnlockTime ( ) { this . authProvider . getUnlockTimestamp ( ) . subscribe ( ( timestamp ) => { if ( ! timestamp || lodash . isEmpty ( timestamp ) ) { return ; } const now = moment . now ( ) ; const diff = moment ( timestamp ) . diff ( now , "seconds" ) ; if ( diff <= 0 ) { this . authProvider . clearAttempts ( ) . subscribe ( ) ; this . attempts = 0 ; return this . loadUnlockTime ( ) ; } this . unlockDiff = diff ; this . password = "" ; this . message = "PIN_CODE.WRONG_PIN_MANY_TIMES" ; this . unlockCountdown$ = timer ( 0 , 1000 ) . pipe ( map ( ( x ) => this . zone . run ( ( ) => this . unlockDiff -- ) ) , takeWhile ( ( ) => this . unlockDiff > 0 ) , finalize ( ( ) => this . zone . run ( ( ) => ( this . message = "PIN_CODE.DEFAULT_MESSAGE" ) ) ) ) . subscribe ( ) ; } ) ; } }