diff --git a/FirebaseAuthUI/FUIAuth.m b/FirebaseAuthUI/FUIAuth.m index 77934951316..f84b2314c81 100644 --- a/FirebaseAuthUI/FUIAuth.m +++ b/FirebaseAuthUI/FUIAuth.m @@ -31,6 +31,18 @@ #import "FUIPasswordSignInViewController_Internal.h" #import "FUIPasswordVerificationViewController.h" +/** @typedef EmailHintSignInCallback + @brief The type of block invoked when an emailHint sign-in event completes. + + @param authResult Optionally; Result of sign-in request containing both the user and + the additional user info associated with the user. + @param error Optionally; the error which occurred - or nil if the request was successful. + @param credential Optionally; The credential used to sign-in. + */ +typedef void (^EmailHintSignInCallback)(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error, + FIRAuthCredential *_Nullable credential); + /** @var kAppNameCodingKey @brief The key used to encode the app Name for NSCoding. */ @@ -222,11 +234,25 @@ - (void)signInWithProviderUI:(id)providerUI presentingViewController:presentingViewController originalError:error completion:^(FIRAuthDataResult *_Nullable authResult, - NSError *_Nullable error) { + NSError *_Nullable error, + FIRAuthCredential *_Nullable credential) { if (error) { completeSignInBlock(nil, error); return; } + + if (![authResult.user.email isEqualToString:[providerUI email]] + && credential) { + NSDictionary *userInfo = @{ + FUIAuthCredentialKey : credential, + }; + NSError *mergeError = [NSError errorWithDomain:FUIAuthErrorDomain + code:FUIAuthErrorCodeMergeConflict + userInfo:userInfo]; + completeSignInBlock(nil, mergeError); + return; + } + [authResult.user linkAndRetrieveDataWithCredential:credential completion:^(FIRAuthDataResult *_Nullable authResult, @@ -284,7 +310,7 @@ - (void)signInWithProviderUI:(id)providerUI - (void)signInWithEmailHint:(NSString *)emailHint presentingViewController:(FUIAuthBaseViewController *)presentingViewController originalError:(NSError *)originalError - completion:(FIRAuthDataResultCallback)completion { + completion:(EmailHintSignInCallback)completion { NSString *kTempApp = @"tempApp"; FIROptions *options = [FIROptions defaultOptions]; // Create an new app instance in order to create a new auth instance. @@ -299,7 +325,7 @@ - (void)signInWithEmailHint:(NSString *)emailHint [self.auth fetchProvidersForEmail:emailHint completion:^(NSArray *_Nullable providers, NSError *_Nullable error) { if (error) { - completion(nil, error); + completion(nil, error, nil); return; } NSString *existingFederatedProviderID = [self authProviderFromProviders:providers]; @@ -321,12 +347,16 @@ - (void)signInWithEmailHint:(NSString *)emailHint // Email password sign-in FUIPasswordSignInViewController *controller = [[FUIPasswordSignInViewController alloc] initWithAuthUI:authUI email:emailHint]; - controller.onDismissCallback = completion; + controller.onDismissCallback = ^(FIRAuthDataResult *result, NSError *error) { + if (completion) { + completion(result, error, nil); + } + }; [presentingViewController pushViewController:controller]; } cancelHandler:^{ if (completion) { - completion(nil, originalError); + completion(nil, originalError, nil); } }]; } else { @@ -351,16 +381,49 @@ - (void)signInWithEmailHint:(NSString *)emailHint FIRAuthResultCallback _Nullable result) { if (error) { if (completion) { - completion(nil, error); + completion(nil, error, nil); } return; } - [tempAuth signInAndRetrieveDataWithCredential:credential completion:completion]; + + [tempAuth signInAndRetrieveDataWithCredential:credential + completion:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + if (error) { + if (completion) { + completion(nil, error, nil); + } + } + + // Handle potential email mismatch. + if (![emailHint isEqualToString:authResult.user.email]) { + NSString *signedInEmail = authResult.user.email; + NSString *title = + [NSString stringWithFormat:@"Continue sign in with %@?", signedInEmail]; + NSString *message = + [NSString stringWithFormat:@"You originally wanted to sign in with %@", + emailHint]; + [FUIAuthBaseViewController showAlertWithTitle:title + message:message + actionTitle:@"Continue" + presentingViewController:presentingViewController + actionHandler:^{ + if (completion) { + completion(authResult, nil, credential); + } + } + cancelHandler:^{ + if (completion) { + completion(nil, error, credential); + } + }]; + } + }]; }]; } cancelHandler:^{ if (completion) { - completion(nil, originalError); + completion(nil, originalError, nil); } }]; } diff --git a/FirebaseAuthUI/FUIAuthBaseViewController.m b/FirebaseAuthUI/FUIAuthBaseViewController.m index a413a4272c5..dde0799b635 100644 --- a/FirebaseAuthUI/FUIAuthBaseViewController.m +++ b/FirebaseAuthUI/FUIAuthBaseViewController.m @@ -242,6 +242,33 @@ + (void)showAlertWithTitle:(nullable NSString *)title [presentingViewController presentViewController:alertController animated:YES completion:nil]; } ++ (void)showAlertWithTitle:(nullable NSString *)title + message:(NSString *)message + actionTitle:(NSString *)actionTitle + presentingViewController:(UIViewController *)presentingViewController + actionHandler:(FUIAuthAlertActionHandler)actionHandler + cancelHandler:(FUIAuthAlertActionHandler)cancelHandler { + UIAlertController *alertController = + [UIAlertController alertControllerWithTitle:title + message:message + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *okAction = + [UIAlertAction actionWithTitle:actionTitle + style:UIAlertActionStyleDefault + handler:^(UIAlertAction *_Nonnull action) { + actionHandler(); + }]; + [alertController addAction:okAction]; + UIAlertAction *cancelAction = + [UIAlertAction actionWithTitle:FUILocalizedString(kStr_Cancel) + style:UIAlertActionStyleCancel + handler:^(UIAlertAction * _Nonnull action) { + cancelHandler(); + }]; + [alertController addAction:cancelAction]; + [presentingViewController presentViewController:alertController animated:YES completion:nil]; +} + + (void)showSignInAlertWithEmail:(NSString *)email provider:(id)provider presentingViewController:(UIViewController *)presentingViewController diff --git a/FirebaseAuthUI/FUIAuthBaseViewController_Internal.h b/FirebaseAuthUI/FUIAuthBaseViewController_Internal.h index 33a9a807b20..2e679bbf144 100644 --- a/FirebaseAuthUI/FUIAuthBaseViewController_Internal.h +++ b/FirebaseAuthUI/FUIAuthBaseViewController_Internal.h @@ -61,6 +61,23 @@ typedef void (^FUIAuthAlertActionHandler)(void); actionTitle:(NSString *)actionTitle presentingViewController:(UIViewController *)presentingViewController; +/** @fn showAlertWithTitle:message:actionTitle:presentingViewController: + @brief Displays an alert view with given title, message and action title on top of the + specified view controller. + @param title The title of the alert. + @param message The message of the alert. + @param actionTitle The title of the action button. + @param actionHandler The block to execute if the action button is tapped. + @param cancelHandler The block to execute if the cancel button is tapped. + @param presentingViewController The controller which shows alert. + */ ++ (void)showAlertWithTitle:(nullable NSString *)title + message:(NSString *)message + actionTitle:(NSString *)actionTitle + presentingViewController:(UIViewController *)presentingViewController + actionHandler:(FUIAuthAlertActionHandler)actionHandler + cancelHandler:(FUIAuthAlertActionHandler)cancelHandler; + /** @fn showSignInAlertWithEmail:provider:handler: @brief Displays an alert to conform with user whether she wants to proceed with the provider. @param email The email address to sign in with.