@@ -478,6 +478,7 @@ const AUTH_FACTOR_SERVER_TO_CLIENT_TYPE: {[key: string]: AuthFactorType} =
478
478
export interface MultiFactorAuthServerConfig {
479
479
state ?: MultiFactorConfigState ;
480
480
enabledProviders ?: AuthFactorServerType [ ] ;
481
+ providerConfigs ?: MultiFactorProviderConfig [ ] ;
481
482
}
482
483
483
484
/**
@@ -506,16 +507,58 @@ export interface MultiFactorConfig {
506
507
* Currently only ‘phone’ is supported.
507
508
*/
508
509
factorIds ?: AuthFactorType [ ] ;
510
+
511
+ /**
512
+ * A list of multi-factor provider configurations.
513
+ * MFA providers (except phone) indicate whether they're enabled through this field. */
514
+ providerConfigs ?: MultiFactorProviderConfig [ ] ;
515
+ }
516
+
517
+ /**
518
+ * Interface representing a multi-factor auth provider configuration.
519
+ * This interface is used for second factor auth providers other than SMS.
520
+ * Currently, only TOTP is supported.
521
+ */ export interface MultiFactorProviderConfig {
522
+ /**
523
+ * Indicates whether this multi-factor provider is enabled or disabled. */
524
+ state : MultiFactorConfigState ;
525
+ /**
526
+ * TOTP multi-factor provider config. */
527
+ totpProviderConfig ?: TotpMultiFactorProviderConfig ;
528
+ }
529
+
530
+ /**
531
+ * Interface representing configuration settings for TOTP second factor auth.
532
+ */
533
+ export interface TotpMultiFactorProviderConfig {
534
+ /**
535
+ * The allowed number of adjacent intervals that will be used for verification
536
+ * to compensate for clock skew. */
537
+ adjacentIntervals ?: number ;
509
538
}
510
539
511
540
/**
512
541
* Defines the multi-factor config class used to convert client side MultiFactorConfig
513
542
* to a format that is understood by the Auth server.
543
+ *
544
+ * @internal
514
545
*/
515
546
export class MultiFactorAuthConfig implements MultiFactorConfig {
516
547
548
+ /**
549
+ * The multi-factor config state.
550
+ */
517
551
public readonly state : MultiFactorConfigState ;
552
+ /**
553
+ * The list of identifiers for enabled second factors.
554
+ * Currently only ‘phone’ is supported.
555
+ */
518
556
public readonly factorIds : AuthFactorType [ ] ;
557
+ /**
558
+ * A list of multi-factor provider specific config.
559
+ * New MFA providers (except phone) will indicate enablement/disablement through this field.
560
+ */
561
+ public readonly providerConfigs : MultiFactorProviderConfig [ ] ;
519
562
520
563
/**
521
564
* Static method to convert a client side request to a MultiFactorAuthServerConfig.
@@ -543,6 +586,9 @@ export class MultiFactorAuthConfig implements MultiFactorConfig {
543
586
request . enabledProviders = [ ] ;
544
587
}
545
588
}
589
+ if ( Object . prototype . hasOwnProperty . call ( options , 'providerConfigs' ) ) {
590
+ request . providerConfigs = options . providerConfigs ;
591
+ }
546
592
return request ;
547
593
}
548
594
@@ -551,10 +597,11 @@ export class MultiFactorAuthConfig implements MultiFactorConfig {
551
597
*
552
598
* @param options - The options object to validate.
553
599
*/
554
- private static validate ( options : MultiFactorConfig ) : void {
600
+ public static validate ( options : MultiFactorConfig ) : void {
555
601
const validKeys = {
556
602
state : true ,
557
603
factorIds : true ,
604
+ providerConfigs : true ,
558
605
} ;
559
606
if ( ! validator . isNonNullObject ( options ) ) {
560
607
throw new FirebaseAuthError (
@@ -599,6 +646,71 @@ export class MultiFactorAuthConfig implements MultiFactorConfig {
599
646
}
600
647
} ) ;
601
648
}
649
+
650
+ if ( typeof options . providerConfigs !== 'undefined' ) {
651
+ if ( ! validator . isArray ( options . providerConfigs ) ) {
652
+ throw new FirebaseAuthError (
653
+ AuthClientErrorCode . INVALID_CONFIG ,
654
+ '"MultiFactorConfig.providerConfigs" must be an array of valid "MultiFactorProviderConfig."' ,
655
+ ) ;
656
+ }
657
+ //Validate content of array.
658
+ options . providerConfigs . forEach ( ( multiFactorProviderConfig ) => {
659
+ if ( typeof multiFactorProviderConfig === 'undefined' || ! validator . isObject ( multiFactorProviderConfig ) ) {
660
+ throw new FirebaseAuthError (
661
+ AuthClientErrorCode . INVALID_CONFIG ,
662
+ `"${ multiFactorProviderConfig } " is not a valid "MultiFactorProviderConfig" type.`
663
+ )
664
+ }
665
+ const validProviderConfigKeys = {
666
+ state : true ,
667
+ totpProviderConfig : true ,
668
+ } ;
669
+ for ( const key in multiFactorProviderConfig ) {
670
+ if ( ! ( key in validProviderConfigKeys ) ) {
671
+ throw new FirebaseAuthError (
672
+ AuthClientErrorCode . INVALID_CONFIG ,
673
+ `"${ key } " is not a valid ProviderConfig parameter.` ,
674
+ ) ;
675
+ }
676
+ }
677
+ if ( typeof multiFactorProviderConfig . state === 'undefined' ||
678
+ ( multiFactorProviderConfig . state !== 'ENABLED' &&
679
+ multiFactorProviderConfig . state !== 'DISABLED' ) ) {
680
+ throw new FirebaseAuthError (
681
+ AuthClientErrorCode . INVALID_CONFIG ,
682
+ '"MultiFactorConfig.providerConfigs.state" must be either "ENABLED" or "DISABLED".' ,
683
+ )
684
+ }
685
+ // Since TOTP is the only provider config available right now, not defining it will lead into an error
686
+ if ( typeof multiFactorProviderConfig . totpProviderConfig === 'undefined' ) {
687
+ throw new FirebaseAuthError (
688
+ AuthClientErrorCode . INVALID_CONFIG ,
689
+ '"MultiFactorConfig.providerConfigs.totpProviderConfig" must be defined.'
690
+ )
691
+ }
692
+ const validTotpProviderConfigKeys = {
693
+ adjacentIntervals : true ,
694
+ } ;
695
+ for ( const key in multiFactorProviderConfig . totpProviderConfig ) {
696
+ if ( ! ( key in validTotpProviderConfigKeys ) ) {
697
+ throw new FirebaseAuthError (
698
+ AuthClientErrorCode . INVALID_CONFIG ,
699
+ `"${ key } " is not a valid TotpProviderConfig parameter.` ,
700
+ ) ;
701
+ }
702
+ }
703
+ const adjIntervals = multiFactorProviderConfig . totpProviderConfig . adjacentIntervals
704
+ if ( typeof adjIntervals !== 'undefined' &&
705
+ ( ! Number . isInteger ( adjIntervals ) || adjIntervals < 0 || adjIntervals > 10 ) ) {
706
+ throw new FirebaseAuthError (
707
+ AuthClientErrorCode . INVALID_ARGUMENT ,
708
+ '"MultiFactorConfig.providerConfigs.totpProviderConfig.adjacentIntervals" must' +
709
+ ' be a valid number between 0 and 10 (both inclusive).'
710
+ )
711
+ }
712
+ } ) ;
713
+ }
602
714
}
603
715
604
716
/**
@@ -624,13 +736,29 @@ export class MultiFactorAuthConfig implements MultiFactorConfig {
624
736
this . factorIds . push ( AUTH_FACTOR_SERVER_TO_CLIENT_TYPE [ enabledProvider ] ) ;
625
737
}
626
738
} )
739
+ this . providerConfigs = [ ] ;
740
+ ( response . providerConfigs || [ ] ) . forEach ( ( providerConfig ) => {
741
+ if ( typeof providerConfig !== 'undefined' ) {
742
+ if ( typeof providerConfig . state === 'undefined' ||
743
+ typeof providerConfig . totpProviderConfig === 'undefined' ||
744
+ ( typeof providerConfig . totpProviderConfig . adjacentIntervals !== 'undefined' &&
745
+ typeof providerConfig . totpProviderConfig . adjacentIntervals !== 'number' ) ) {
746
+ throw new FirebaseAuthError (
747
+ AuthClientErrorCode . INTERNAL_ERROR ,
748
+ 'INTERNAL ASSERT FAILED: Invalid multi-factor configuration response' ) ;
749
+ }
750
+ this . providerConfigs . push ( providerConfig ) ;
751
+ }
752
+ } )
627
753
}
628
754
629
- /** @returns The plain object representation of the multi-factor config instance. */
755
+ /** Converts MultiFactorConfig to JSON object
756
+ * @returns The plain object representation of the multi-factor config instance. */
630
757
public toJSON ( ) : object {
631
758
return {
632
759
state : this . state ,
633
760
factorIds : this . factorIds ,
761
+ providerConfigs : this . providerConfigs ,
634
762
} ;
635
763
}
636
764
}
0 commit comments