Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Fix link with email link bug
  • Loading branch information
Chuan Ren committed May 17, 2019
commit 2314f93bcac8952c86aabf3a2fec61125cc34bff
2 changes: 0 additions & 2 deletions Example/Auth/Sample/MainViewController+Email.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@

NS_ASSUME_NONNULL_BEGIN

typedef void (^ShowEmailPasswordDialogCompletion)(FIRAuthCredential *credential);

@interface MainViewController (Email)

- (StaticContentTableViewSection *)emailAuthSection;
Expand Down
80 changes: 60 additions & 20 deletions Example/Auth/Sample/MainViewController+Email.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

NS_ASSUME_NONNULL_BEGIN

typedef void (^ShowEmailDialogCompletion)(FIRAuthCredential *credential);

@implementation MainViewController (Email)

- (StaticContentTableViewSection *)emailAuthSection {
Expand All @@ -36,10 +38,12 @@ - (StaticContentTableViewSection *)emailAuthSection {
action:^{ [weakSelf unlinkFromProvider:FIREmailAuthProviderID completion:nil]; }],
[StaticContentTableViewCell cellWithTitle:@"Reauthenticate Email Password"
action:^{ [weakSelf reauthenticateEmailPassword]; }],
[StaticContentTableViewCell cellWithTitle:@"Sign in with Email Link"
action:^{ [weakSelf sendEmailSignInLink]; }],
[StaticContentTableViewCell cellWithTitle:@"Send Email Sign in Link"
action:^{ [weakSelf sendEmailSignInLink]; }],
[StaticContentTableViewCell cellWithTitle:@"Sign in with Email Link"
action:^{ [weakSelf signInWithEmailLink]; }],
[StaticContentTableViewCell cellWithTitle:@"Link with Email Link"
action:^{ [weakSelf linkWithEmailLink]; }],
]];
}

Expand Down Expand Up @@ -173,24 +177,6 @@ - (void)reauthenticateEmailPassword {
}];
}

- (void)showEmailPasswordDialogWithCompletion:(ShowEmailPasswordDialogCompletion)completion {
[self showTextInputPromptWithMessage:@"Email Address:"
completionBlock:^(BOOL userPressedOK, NSString *_Nullable email) {
if (!userPressedOK || !email.length) {
return;
}
[self showTextInputPromptWithMessage:@"Password:"
completionBlock:^(BOOL userPressedOK, NSString *_Nullable password) {
if (!userPressedOK || !password.length) {
return;
}
FIRAuthCredential *credential = [FIREmailAuthProvider credentialWithEmail:email
password:password];
completion(credential);
}];
}];
}

- (void)signInWithEmailLink {
[self showTextInputPromptWithMessage:@"Email Address:"
keyboardType:UIKeyboardTypeEmailAddress
Expand Down Expand Up @@ -254,6 +240,60 @@ - (void)sendEmailSignInLink {
}];
}

- (void)linkWithEmailLink {
[self showEmailLinkDialogWithCompletion:^(FIRAuthCredential *credential) {
[self showSpinner:^{
[[self user] linkWithCredential:credential
completion:^(FIRAuthDataResult *result, NSError *error) {
if (error) {
[self logFailure:@"link Email Link failed." error:error];
} else {
[self logSuccess:@"link Email Link succeeded."];
}
[self hideSpinner:^{
[self showTypicalUIForUserUpdateResultsWithTitle:@"Link with Email Link" error:error];
}];
}];
}];
}];
}

- (void)showEmailPasswordDialogWithCompletion:(ShowEmailDialogCompletion)completion {
[self showTextInputPromptWithMessage:@"Email Address:"
completionBlock:^(BOOL userPressedOK, NSString *_Nullable email) {
if (!userPressedOK || !email.length) {
return;
}
[self showTextInputPromptWithMessage:@"Password:"
completionBlock:^(BOOL userPressedOK, NSString *_Nullable password) {
if (!userPressedOK || !password.length) {
return;
}
FIRAuthCredential *credential = [FIREmailAuthProvider credentialWithEmail:email
password:password];
completion(credential);
}];
}];
}

- (void)showEmailLinkDialogWithCompletion:(ShowEmailDialogCompletion)completion {
[self showTextInputPromptWithMessage:@"Email Address:"
completionBlock:^(BOOL userPressedOK, NSString *_Nullable email) {
if (!userPressedOK || !email.length) {
return;
}
[self showTextInputPromptWithMessage:@"Link:"
completionBlock:^(BOOL userPressedOK, NSString *_Nullable link) {
if (!userPressedOK || !link.length) {
return;
}
FIRAuthCredential *credential = [FIREmailAuthProvider credentialWithEmail:email
link:link];
completion(credential);
}];
}];
}

@end

NS_ASSUME_NONNULL_END
37 changes: 5 additions & 32 deletions Firebase/Auth/Source/Auth/FIRAuth.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#import "FIRAuthOperationType.h"
#import "FIRAuthSettings.h"
#import "FIRAuthStoredUserManager.h"
#import "FIRAuthWebUtils.h"
#import "FIRUser_Internal.h"
#import "FirebaseAuth.h"
#import "FIRAuthBackend.h"
Expand Down Expand Up @@ -678,10 +679,10 @@ - (void)internalSignInAndRetrieveDataWithEmail:(nonnull NSString *)email
kInvalidEmailSignInLinkExceptionMessage];
return;
}
NSDictionary<NSString *, NSString *> *queryItems = FIRAuthParseURL(link);
NSDictionary<NSString *, NSString *> *queryItems = [FIRAuthWebUtils parseURL:link];
if (![queryItems count]) {
NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link];
queryItems = FIRAuthParseURL(urlComponents.query);
queryItems = [FIRAuthWebUtils parseURL:urlComponents.query];
}
NSString *actionCode = queryItems[@"oobCode"];

Expand Down Expand Up @@ -1198,13 +1199,13 @@ - (BOOL)isSignInWithEmailLink:(NSString *)link {
if (link.length == 0) {
return NO;
}
NSDictionary<NSString *, NSString *> *queryItems = FIRAuthParseURL(link);
NSDictionary<NSString *, NSString *> *queryItems = [FIRAuthWebUtils parseURL:link];
if (![queryItems count]) {
NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link];
if (!urlComponents.query) {
return NO;
}
queryItems = FIRAuthParseURL(urlComponents.query);
queryItems = [FIRAuthWebUtils parseURL:urlComponents.query];
}

if (![queryItems count]) {
Expand All @@ -1220,34 +1221,6 @@ - (BOOL)isSignInWithEmailLink:(NSString *)link {
return NO;
}

/** @fn FIRAuthParseURL:NSString
@brief Parses an incoming URL into all available query items.
@param urlString The url to be parsed.
@return A dictionary of available query items in the target URL.
*/
static NSDictionary<NSString *, NSString *> *FIRAuthParseURL(NSString *urlString) {
NSString *linkURL = [NSURLComponents componentsWithString:urlString].query;
if (!linkURL) {
return @{};
}
NSArray<NSString *> *URLComponents = [linkURL componentsSeparatedByString:@"&"];
NSMutableDictionary<NSString *, NSString *> *queryItems =
[[NSMutableDictionary alloc] initWithCapacity:URLComponents.count];
for (NSString *component in URLComponents) {
NSRange equalRange = [component rangeOfString:@"="];
if (equalRange.location != NSNotFound) {
NSString *queryItemKey =
[[component substringToIndex:equalRange.location] stringByRemovingPercentEncoding];
NSString *queryItemValue =
[[component substringFromIndex:equalRange.location + 1] stringByRemovingPercentEncoding];
if (queryItemKey && queryItemValue) {
queryItems[queryItemKey] = queryItemValue;
}
}
}
return queryItems;
}

- (FIRAuthStateDidChangeListenerHandle)addAuthStateDidChangeListener:
(FIRAuthStateDidChangeListenerBlock)listener {
__block BOOL firstInvocation = YES;
Expand Down
73 changes: 64 additions & 9 deletions Firebase/Auth/Source/User/FIRUser.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
#import "FIRAuthBackend.h"
#import "FIRAuthRequestConfiguration.h"
#import "FIRAuthTokenResult_Internal.h"
#import "FIRAuthWebUtils.h"
#import "FIRDeleteAccountRequest.h"
#import "FIRDeleteAccountResponse.h"
#import "FIREmailAuthProvider.h"
#import "FIREmailPasswordAuthCredential.h"
#import "FIREmailLinkSignInRequest.h"
#import "FIRGameCenterAuthCredential.h"
#import "FIRGetAccountInfoRequest.h"
#import "FIRGetAccountInfoResponse.h"
Expand Down Expand Up @@ -1026,15 +1028,68 @@ - (void)linkAndRetrieveDataWithCredential:(FIRAuthCredential *)credential
}
FIREmailPasswordAuthCredential *emailPasswordCredential =
(FIREmailPasswordAuthCredential *)credential;
[self updateEmail:emailPasswordCredential.email
password:emailPasswordCredential.password
callback:^(NSError *error) {
if (error) {
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
} else {
callInMainThreadWithAuthDataResultAndError(completion, result, nil);
}
}];
if (emailPasswordCredential.password) {
[self updateEmail:emailPasswordCredential.email
password:emailPasswordCredential.password
callback:^(NSError *error) {
if (error) {
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
} else {
callInMainThreadWithAuthDataResultAndError(completion, result, nil);
}
}];
} else {
[self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
NSError *_Nullable error) {
NSDictionary<NSString *, NSString *> *queryItems = [FIRAuthWebUtils parseURL:emailPasswordCredential.link];
if (![queryItems count]) {
NSURLComponents *urlComponents = [NSURLComponents componentsWithString:emailPasswordCredential.link];
queryItems = [FIRAuthWebUtils parseURL:urlComponents.query];
}
NSString *actionCode = queryItems[@"oobCode"];
FIRAuthRequestConfiguration *requestConfiguration = self.auth.requestConfiguration;
FIREmailLinkSignInRequest *request =
[[FIREmailLinkSignInRequest alloc] initWithEmail:emailPasswordCredential.email
oobCode:actionCode
requestConfiguration:requestConfiguration];
request.IDToken = accessToken;
[FIRAuthBackend emailLinkSignin:request
callback:^(FIREmailLinkSignInResponse *_Nullable response,
NSError *_Nullable error) {
if (error){
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
} else {
[self internalGetTokenWithCallback:^(NSString *_Nullable accessToken,
NSError *_Nullable error) {
if (error) {
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
return;
}

FIRGetAccountInfoRequest *getAccountInfoRequest =
[[FIRGetAccountInfoRequest alloc] initWithAccessToken:accessToken
requestConfiguration:requestConfiguration];
[FIRAuthBackend getAccountInfo:getAccountInfoRequest
callback:^(FIRGetAccountInfoResponse *_Nullable response,
NSError *_Nullable error) {
if (error) {
[self signOutIfTokenIsInvalidWithError:error];
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
return;
}
self.anonymous = NO;
[self updateWithGetAccountInfoResponse:response];
if (![self updateKeychain:&error]) {
callInMainThreadWithAuthDataResultAndError(completion, nil, error);
return;
}
callInMainThreadWithAuthDataResultAndError(completion, result, nil);
}];
}];
}
}];
}];
}
return;
}

Expand Down
7 changes: 7 additions & 0 deletions Firebase/Auth/Source/Utilities/FIRAuthWebUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ typedef void (^FIRFetchAuthDomainCallback)(NSString *_Nullable authDomain,
*/
+ (NSString *)stringByUnescapingFromURLArgument:(NSString *)argument;

/** @fn parseURL:
@brief Parses an incoming URL into all available query items.
@param urlString The url to be parsed.
@return A dictionary of available query items in the target URL.
*/
+ (NSDictionary<NSString *, NSString *> *)parseURL:(NSString *)urlString;

@end

NS_ASSUME_NONNULL_END
23 changes: 23 additions & 0 deletions Firebase/Auth/Source/Utilities/FIRAuthWebUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,29 @@ + (NSString *)stringByUnescapingFromURLArgument:(NSString *)argument {
return [resultString stringByRemovingPercentEncoding];
}

+ (NSDictionary<NSString *, NSString *> *)parseURL:(NSString *)urlString {
NSString *linkURL = [NSURLComponents componentsWithString:urlString].query;
if (!linkURL) {
return @{};
}
NSArray<NSString *> *URLComponents = [linkURL componentsSeparatedByString:@"&"];
NSMutableDictionary<NSString *, NSString *> *queryItems =
[[NSMutableDictionary alloc] initWithCapacity:URLComponents.count];
for (NSString *component in URLComponents) {
NSRange equalRange = [component rangeOfString:@"="];
if (equalRange.location != NSNotFound) {
NSString *queryItemKey =
[[component substringToIndex:equalRange.location] stringByRemovingPercentEncoding];
NSString *queryItemValue =
[[component substringFromIndex:equalRange.location + 1] stringByRemovingPercentEncoding];
if (queryItemKey && queryItemValue) {
queryItems[queryItemKey] = queryItemValue;
}
}
}
return queryItems;
}

@end

NS_ASSUME_NONNULL_END