@@ -478,6 +478,7 @@ const AUTH_FACTOR_SERVER_TO_CLIENT_TYPE: {[key: string]: AuthFactorType} =
478478export interface MultiFactorAuthServerConfig {
479479 state ?: MultiFactorConfigState ;
480480 enabledProviders ?: AuthFactorServerType [ ] ;
481+ providerConfigs ?: MultiFactorProviderConfig [ ] ;
481482}
482483
483484/**
@@ -506,16 +507,58 @@ export interface MultiFactorConfig {
506507 * Currently only ‘phone’ is supported.
507508 */
508509 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 ;
509538}
510539
511540/**
512541 * Defines the multi-factor config class used to convert client side MultiFactorConfig
513542 * to a format that is understood by the Auth server.
543+ *
544+ * @internal
514545 */
515546export class MultiFactorAuthConfig implements MultiFactorConfig {
516547
548+ /**
549+ * The multi-factor config state.
550+ */
517551 public readonly state : MultiFactorConfigState ;
552+ /**
553+ * The list of identifiers for enabled second factors.
554+ * Currently only ‘phone’ is supported.
555+ */
518556 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 [ ] ;
519562
520563 /**
521564 * Static method to convert a client side request to a MultiFactorAuthServerConfig.
@@ -543,6 +586,9 @@ export class MultiFactorAuthConfig implements MultiFactorConfig {
543586 request . enabledProviders = [ ] ;
544587 }
545588 }
589+ if ( Object . prototype . hasOwnProperty . call ( options , 'providerConfigs' ) ) {
590+ request . providerConfigs = options . providerConfigs ;
591+ }
546592 return request ;
547593 }
548594
@@ -551,10 +597,11 @@ export class MultiFactorAuthConfig implements MultiFactorConfig {
551597 *
552598 * @param options - The options object to validate.
553599 */
554- private static validate ( options : MultiFactorConfig ) : void {
600+ public static validate ( options : MultiFactorConfig ) : void {
555601 const validKeys = {
556602 state : true ,
557603 factorIds : true ,
604+ providerConfigs : true ,
558605 } ;
559606 if ( ! validator . isNonNullObject ( options ) ) {
560607 throw new FirebaseAuthError (
@@ -599,6 +646,71 @@ export class MultiFactorAuthConfig implements MultiFactorConfig {
599646 }
600647 } ) ;
601648 }
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+ }
602714 }
603715
604716 /**
@@ -624,13 +736,29 @@ export class MultiFactorAuthConfig implements MultiFactorConfig {
624736 this . factorIds . push ( AUTH_FACTOR_SERVER_TO_CLIENT_TYPE [ enabledProvider ] ) ;
625737 }
626738 } )
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+ } )
627753 }
628754
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. */
630757 public toJSON ( ) : object {
631758 return {
632759 state : this . state ,
633760 factorIds : this . factorIds ,
761+ providerConfigs : this . providerConfigs ,
634762 } ;
635763 }
636764}
0 commit comments