Skip to content

Commit

Permalink
feat(auth): Implement multi-factor enrollment for iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
fzuellich committed Oct 21, 2022
1 parent b5f2e5a commit 452f57f
Showing 1 changed file with 86 additions and 16 deletions.
102 changes: 86 additions & 16 deletions packages/auth/ios/RNFBAuth/RNFBAuthModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
// Used for caching credentials between method calls.
static __strong NSMutableDictionary<NSString *, FIRAuthCredential *> *credentials;
static __strong NSMutableDictionary<NSString *, FIRMultiFactorResolver *> *cachedResolver;
static __strong NSMutableDictionary<NSString *, FIRMultiFactorSession *> *cachedSessions;

@implementation RNFBAuthModule
#pragma mark -
Expand All @@ -73,6 +74,7 @@ - (id)init {
idTokenHandlers = [[NSMutableDictionary alloc] init];
credentials = [[NSMutableDictionary alloc] init];
cachedResolver = [[NSMutableDictionary alloc] init];
cachedSessions = [[NSMutableDictionary alloc] init];
});
return self;
}
Expand All @@ -99,6 +101,7 @@ - (void)invalidate {

[credentials removeAllObjects];
[cachedResolver removeAllObjects];
[cachedSessions removeAllObjects];
}

#pragma mark -
Expand Down Expand Up @@ -769,6 +772,26 @@ - (void)invalidate {
}
}];
}
RCT_EXPORT_METHOD(verifyPhoneNumberForMultiFactor
: (FIRApp *)firebaseApp
: (NSString *)phoneNumber
: (NSString *)sessionId
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
FIRMultiFactorSession *session = cachedSessions[sessionId];
[FIRPhoneAuthProvider.provider
verifyPhoneNumber:phoneNumber
UIDelegate:nil
multiFactorSession:session
completion:^(NSString *_Nullable verificationID, NSError *_Nullable error) {
if (error != nil) {
[self promiseRejectAuthException:reject error:error];
return;
}

resolve(verificationID);
}];
}

RCT_EXPORT_METHOD(resolveMultiFactorSignIn
: (FIRApp *)firebaseApp
Expand Down Expand Up @@ -797,6 +820,50 @@ - (void)invalidate {
}];
}

RCT_EXPORT_METHOD(getSession
: (FIRApp *)firebaseApp
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
FIRUser *user = [FIRAuth authWithApp:firebaseApp].currentUser;
[[user multiFactor] getSessionWithCompletion:^(FIRMultiFactorSession *_Nullable session,
NSError *_Nullable error) {
if (error != nil) {
[self promiseRejectAuthException:reject error:error];
return;
}

NSString *sessionId = [NSString stringWithFormat:@"%@", @([session hash])];
cachedSessions[sessionId] = session;
resolve(sessionId);
}];
}

RCT_EXPORT_METHOD(finalizeMultiFactorEnrollment
: (FIRApp *)firebaseApp
: (NSString *)verificationId
: (NSString *)verificationCode
: (NSString *_Nullable)displayName
: (RCTPromiseResolveBlock)resolve
: (RCTPromiseRejectBlock)reject) {
FIRPhoneAuthCredential *credential =
[FIRPhoneAuthProvider.provider credentialWithVerificationID:verificationId
verificationCode:verificationCode];
FIRMultiFactorAssertion *assertion =
[FIRPhoneMultiFactorGenerator assertionWithCredential:credential];
FIRUser *user = [FIRAuth authWithApp:firebaseApp].currentUser;
[user.multiFactor enrollWithAssertion:assertion
displayName:displayName
completion:^(NSError *_Nullable error) {
if (error != nil) {
[self promiseRejectAuthException:reject error:error];
return;
}

resolve(nil);
return;
}];
}

RCT_EXPORT_METHOD(verifyPhoneNumber
: (FIRApp *)firebaseApp
: (NSString *)phoneNumber
Expand Down Expand Up @@ -1080,25 +1147,11 @@ - (void)promiseNoUser:(RCTPromiseResolveBlock)resolve
}

- (NSDictionary *)multiFactorResolverToDict:(FIRMultiFactorResolver *)resolver {
NSMutableArray *hintsOutput = [NSMutableArray array];
for (FIRPhoneMultiFactorInfo *hint in resolver.hints) {
NSString *enrollmentDate =
[[[NSISO8601DateFormatter alloc] init] stringFromDate:hint.enrollmentDate];

[hintsOutput addObject:@{
@"uid" : hint.UID,
@"factorId" : [self getJSFactorId:(hint.factorID)],
@"displayName" : hint.displayName,
@"enrollmentDate" : enrollmentDate,
@"phoneNumber" : hint.phoneNumber
}];
}

// Temporarily store the non-serializable session for later
NSString *sessionHash = [NSString stringWithFormat:@"%@", @([resolver.session hash])];

return @{
@"hints" : hintsOutput,
@"hints" : [self convertMultiFactorData:resolver.hints],
@"session" : sessionHash,
};
}
Expand Down Expand Up @@ -1360,10 +1413,27 @@ - (NSDictionary *)firebaseUserToDict:(FIRUser *)user {
@"refreshToken" : user.refreshToken,
@"tenantId" : user.tenantID ? (id)user.tenantID : [NSNull null],
keyUid : user.uid,
@"multiFactor" : user.multiFactor.enrolledFactors
@"multiFactor" :
@{@"enrolledFactors" : [self convertMultiFactorData:user.multiFactor.enrolledFactors]}
};
}

- (NSArray<NSMutableDictionary *> *)convertMultiFactorData:(NSArray<FIRMultiFactorInfo *> *)hints {
NSMutableArray *enrolledFactors = [NSMutableArray array];

for (FIRPhoneMultiFactorInfo *hint in hints) {
NSString *enrollmentDate =
[[[NSISO8601DateFormatter alloc] init] stringFromDate:hint.enrollmentDate];
[enrolledFactors addObject:@{
@"uid" : hint.UID,
@"factorId" : [self getJSFactorId:(hint.factorID)],
@"displayName" : hint.displayName == nil ? [NSNull null] : hint.displayName,
@"enrollmentDate" : enrollmentDate,
}];
}
return enrolledFactors;
}

- (NSDictionary *)authCredentialToDict:(FIRAuthCredential *)authCredential {
NSString *authCredentialHash = [NSString stringWithFormat:@"%@", @([authCredential hash])];

Expand Down

0 comments on commit 452f57f

Please sign in to comment.