5959#if TARGET_OS_IOS
6060static __strong NSMutableDictionary <NSString *, FIRMultiFactorResolver *> *cachedResolver;
6161static __strong NSMutableDictionary <NSString *, FIRMultiFactorSession *> *cachedSessions;
62+ static __strong NSMutableDictionary <NSString *, FIRTOTPSecret *> *cachedTotpSecrets;
6263#endif
6364
6465@implementation RNFBAuthModule
@@ -82,6 +83,7 @@ - (id)init {
8283#if TARGET_OS_IOS
8384 cachedResolver = [[NSMutableDictionary alloc ] init ];
8485 cachedSessions = [[NSMutableDictionary alloc ] init ];
86+ cachedTotpSecrets = [[NSMutableDictionary alloc ] init ];
8587#endif
8688 });
8789 return self;
@@ -111,6 +113,7 @@ - (void)invalidate {
111113#if TARGET_OS_IOS
112114 [cachedResolver removeAllObjects ];
113115 [cachedSessions removeAllObjects ];
116+ [cachedTotpSecrets removeAllObjects ];
114117#endif
115118}
116119
@@ -968,6 +971,61 @@ - (void)invalidate {
968971 }];
969972}
970973
974+ RCT_EXPORT_METHOD (resolveTotpSignIn
975+ : (FIRApp *)firebaseApp
976+ : (NSString *)sessionKey
977+ : (NSString *)uid
978+ : (NSString *)oneTimePassword
979+ : (RCTPromiseResolveBlock)resolve
980+ : (RCTPromiseRejectBlock)reject) {
981+ DLog (@" using instance resolve TotpSignIn: %@ " , firebaseApp.name );
982+
983+ FIRMultiFactorAssertion *assertion =
984+ [FIRTOTPMultiFactorGenerator assertionForSignInWithEnrollmentID: uid oneTimePassword: oneTimePassword];
985+ [cachedResolver[sessionKey] resolveSignInWithAssertion: assertion
986+ completion: ^(FIRAuthDataResult *_Nullable authResult,
987+ NSError *_Nullable error) {
988+ DLog (@" authError: %@ " , error) if (error) {
989+ [self promiseRejectAuthException: reject
990+ error: error];
991+ }
992+ else {
993+ [self promiseWithAuthResult: resolve
994+ rejecter: reject
995+ authResult: authResult];
996+ }
997+ }];
998+ }
999+
1000+ RCT_EXPORT_METHOD (generateTotpSecret
1001+ : (FIRApp *)firebaseApp
1002+ : (NSString *)sessionKey
1003+ : (RCTPromiseResolveBlock)resolve
1004+ : (RCTPromiseRejectBlock)reject) {
1005+ DLog (@" using instance resolve generateTotpSecret: %@ " , firebaseApp.name );
1006+
1007+ FIRMultiFactorSession *session = cachedSessions[sessionKey];
1008+ DLog (@" using sessionKey: %@ " , sessionKey);
1009+ DLog (@" using session: %@ " , session);
1010+ [FIRTOTPMultiFactorGenerator generateSecretWithMultiFactorSession: session
1011+ completion: ^(FIRTOTPSecret * _Nullable totpSecret, NSError * _Nullable error) {
1012+ DLog (@" authError: %@ " , error) if (error) {
1013+ [self promiseRejectAuthException: reject
1014+ error: error];
1015+ }
1016+ else {
1017+ NSString *secretKey = totpSecret.sharedSecretKey ;
1018+ DLog (@" secretKey generated: %@ " , secretKey);
1019+ cachedTotpSecrets[secretKey] = totpSecret;
1020+ DLog (@" cachedSecret: %@ " , cachedTotpSecrets[secretKey]);
1021+ resolve (@{
1022+ @" secretKey" : secretKey,
1023+ });
1024+ }
1025+ }];
1026+
1027+ }
1028+
9711029RCT_EXPORT_METHOD (getSession
9721030 : (FIRApp *)firebaseApp
9731031 : (RCTPromiseResolveBlock)resolve
@@ -986,6 +1044,26 @@ - (void)invalidate {
9861044 }];
9871045}
9881046
1047+ RCT_EXPORT_METHOD (unenrollMultiFactor
1048+ : (FIRApp *)firebaseApp
1049+ : (NSString *)factorUID
1050+ : (RCTPromiseResolveBlock)resolve
1051+ : (RCTPromiseRejectBlock)reject) {
1052+ DLog (@" using instance unenrollMultiFactor: %@ " , firebaseApp.name );
1053+
1054+ FIRUser *user = [FIRAuth authWithApp: firebaseApp].currentUser ;
1055+ [user.multiFactor unenrollWithFactorUID: factorUID completion: ^(NSError * _Nullable error) {
1056+ if (error != nil ) {
1057+ [self promiseRejectAuthException: reject error: error];
1058+ return ;
1059+ }
1060+
1061+ resolve (nil );
1062+ return ;
1063+ }];
1064+
1065+ }
1066+
9891067RCT_EXPORT_METHOD (finalizeMultiFactorEnrollment
9901068 : (FIRApp *)firebaseApp
9911069 : (NSString *)verificationId
@@ -1015,6 +1093,35 @@ - (void)invalidate {
10151093 }];
10161094}
10171095
1096+ RCT_EXPORT_METHOD (finalizeTotpEnrollment
1097+ : (FIRApp *)firebaseApp
1098+ : (NSString *)totpSecret
1099+ : (NSString *)verificationCode
1100+ : (NSString *_Nullable)displayName
1101+ : (RCTPromiseResolveBlock)resolve
1102+ : (RCTPromiseRejectBlock)reject) {
1103+ DLog (@" using instance finalizeTotpEnrollment: %@ " , firebaseApp.name );
1104+
1105+ FIRTOTPSecret *cachedTotpSecret = cachedTotpSecrets[totpSecret];
1106+ DLog (@" using totpSecretKey: %@ " , totpSecret);
1107+ DLog (@" using cachedSecret: %@ " , cachedTotpSecret);
1108+ FIRTOTPMultiFactorAssertion *assertion =
1109+ [FIRTOTPMultiFactorGenerator assertionForEnrollmentWithSecret: cachedTotpSecret oneTimePassword: verificationCode];
1110+
1111+ FIRUser *user = [FIRAuth authWithApp: firebaseApp].currentUser ;
1112+
1113+ [user.multiFactor enrollWithAssertion: assertion displayName: displayName completion: ^(NSError * _Nullable error) {
1114+ if (error != nil ) {
1115+ [self promiseRejectAuthException: reject error: error];
1116+ return ;
1117+ }
1118+
1119+ resolve (nil );
1120+ return ;
1121+ }];
1122+
1123+ }
1124+
10181125RCT_EXPORT_METHOD (verifyPhoneNumber
10191126 : (FIRApp *)firebaseApp
10201127 : (NSString *)phoneNumber
@@ -1739,18 +1846,29 @@ - (NSDictionary *)firebaseUserToDict:(FIRUser *)user {
17391846 NSMutableArray *enrolledFactors = [NSMutableArray array ];
17401847
17411848 for (FIRPhoneMultiFactorInfo *hint in hints) {
1742- NSString *enrollmentTime =
1743- [[[NSISO8601DateFormatter alloc ] init ] stringFromDate: hint.enrollmentDate];
1744- [enrolledFactors addObject: @{
1745- @" uid" : hint.UID ,
1746- @" factorId" : [self getJSFactorId: (hint.factorID)],
1747- @" displayName" : hint.displayName == nil ? [NSNull null ] : hint.displayName ,
1748- @" enrollmentTime" : enrollmentTime,
1749- // @deprecated enrollmentDate kept for backwards compatibility, please use enrollmentTime
1750- @" enrollmentDate" : enrollmentTime,
1751- // phoneNumber only present on FIRPhoneMultiFactorInfo
1752- @" phoneNumber" : hint.phoneNumber == nil ? [NSNull null ] : hint.phoneNumber ,
1753- }];
1849+ NSString *enrollmentTime =
1850+ [[[NSISO8601DateFormatter alloc ] init ] stringFromDate: hint.enrollmentDate];
1851+ if ([hint.factorID isEqualToString: @" phone" ]) {
1852+ [enrolledFactors addObject: @{
1853+ @" uid" : hint.UID ,
1854+ @" factorId" : [self getJSFactorId: (hint.factorID)],
1855+ @" displayName" : hint.displayName == nil ? [NSNull null ] : hint.displayName ,
1856+ @" enrollmentTime" : enrollmentTime,
1857+ // @deprecated enrollmentDate kept for backwards compatibility, please use enrollmentTime
1858+ @" enrollmentDate" : enrollmentTime,
1859+ // phoneNumber only present on FIRPhoneMultiFactorInfo
1860+ @" phoneNumber" : hint.phoneNumber == nil ? [NSNull null ] : hint.phoneNumber ,
1861+ }];
1862+ } else if ([hint.factorID isEqualToString: @" totp" ]) {
1863+ [enrolledFactors addObject: @{
1864+ @" uid" : hint.UID ,
1865+ @" factorId" : @" totp" ,
1866+ @" displayName" : hint.displayName == nil ? [NSNull null ] : hint.displayName ,
1867+ @" enrollmentTime" : enrollmentTime,
1868+ // @deprecated enrollmentDate kept for backwards compatibility, please use enrollmentTime
1869+ @" enrollmentDate" : enrollmentTime,
1870+ }];
1871+ }
17541872 }
17551873 return enrolledFactors;
17561874}
0 commit comments