diff options
Diffstat (limited to 'Firebase')
16 files changed, 604 insertions, 13 deletions
diff --git a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.m b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.m index d27611e..7a871e2 100644 --- a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.m +++ b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailAuthProvider.m @@ -32,4 +32,8 @@ return [[FIREmailPasswordAuthCredential alloc] initWithEmail:email password:password]; } ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email link:(NSString *)link { + return [[FIREmailPasswordAuthCredential alloc] initWithEmail:email link:link]; +} + @end diff --git a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h index d50bf17..7625685 100644 --- a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h +++ b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.h @@ -35,6 +35,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, readonly) NSString *password; +/** @property link + @brief The email sign-in link. + */ +@property(nonatomic, readonly) NSString *link; + /** @fn initWithEmail:password: @brief Designated initializer. @param email The user's email address. @@ -43,6 +48,14 @@ NS_ASSUME_NONNULL_BEGIN - (nullable instancetype)initWithEmail:(NSString *)email password:(NSString *)password NS_DESIGNATED_INITIALIZER; +/** @fn initWithEmail:link: + @brief Designated initializer. + @param email The user's email address. + @param link The email sign-in link. + */ +- (nullable instancetype)initWithEmail:(NSString *)email link:(NSString *)link + NS_DESIGNATED_INITIALIZER; + @end NS_ASSUME_NONNULL_END diff --git a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.m b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.m index 4361366..71cc330 100644 --- a/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.m +++ b/Firebase/Auth/Source/AuthProviders/EmailPassword/FIREmailPasswordAuthCredential.m @@ -43,6 +43,15 @@ return self; } +- (nullable instancetype)initWithEmail:(NSString *)email link:(NSString *)link { + self = [super initWithProvider:FIREmailAuthProviderID]; + if (self) { + _email = [email copy]; + _link = [link copy]; + } + return self; +} + - (void)prepareVerifyAssertionRequest:(FIRVerifyAssertionRequest *)request { [FIRAuthExceptionUtils raiseMethodNotImplementedExceptionWithReason: @"Attempt to call prepareVerifyAssertionRequest: on a FIREmailPasswordAuthCredential."]; diff --git a/Firebase/Auth/Source/FIRAuth.m b/Firebase/Auth/Source/FIRAuth.m index 0f3705f..387fab7 100644 --- a/Firebase/Auth/Source/FIRAuth.m +++ b/Firebase/Auth/Source/FIRAuth.m @@ -39,6 +39,8 @@ #import "FIRAuthRequestConfiguration.h" #import "FIRCreateAuthURIRequest.h" #import "FIRCreateAuthURIResponse.h" +#import "FIREmailLinkSignInRequest.h" +#import "FIREmailLinkSignInResponse.h" #import "FIRGetOOBConfirmationCodeRequest.h" #import "FIRGetOOBConfirmationCodeResponse.h" #import "FIRResetPasswordRequest.h" @@ -117,6 +119,11 @@ static NSString *const kVerifyEmailRequestType = @"VERIFY_EMAIL"; */ static NSString *const kRecoverEmailRequestType = @"RECOVER_EMAIL"; +/** @var kEmailLinkSignInRequestType + @brief The action code type value for an email sign-in link in the check action code response. +*/ +static NSString *const kEmailLinkSignInRequestType = @"EMAIL_SIGNIN"; + /** @var kMissingPasswordReason @brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown. @remarks This error message will be localized in the future. @@ -186,6 +193,9 @@ static NSMutableDictionary *gKeychainServiceNameForAppName; if ([requestType isEqualToString:kRecoverEmailRequestType]) { return FIRActionCodeOperationRecoverEmail; } + if ([requestType isEqualToString:kEmailLinkSignInRequestType]) { + return FIRActionCodeOperationEmailLink; + } return FIRActionCodeOperationUnknown; } @@ -509,6 +519,24 @@ static NSMutableDictionary *gKeychainServiceNameForAppName; }); } +- (void)fetchSignInMethodsForEmail:(nonnull NSString *)email + completion:(nullable FIRSignInMethodQueryCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRCreateAuthURIRequest *request = + [[FIRCreateAuthURIRequest alloc] initWithIdentifier:email + continueURI:@"http://www.google.com/" + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend createAuthURI:request callback:^(FIRCreateAuthURIResponse *_Nullable response, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(response.signinMethods, error); + }); + } + }]; + }); +} + - (void)signInWithEmail:(NSString *)email password:(NSString *)password completion:(FIRAuthResultCallback)completion { @@ -524,6 +552,23 @@ static NSMutableDictionary *gKeychainServiceNameForAppName; }); } +- (void)signInWithEmail:(NSString *)email + link:(NSString *)link + completion:(FIRAuthDataResultCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + FIRAuthDataResultCallback decoratedCallback = + [self signInFlowAuthDataResultCallbackByDecoratingCallback:completion]; + FIREmailPasswordAuthCredential *credential = + [[FIREmailPasswordAuthCredential alloc] initWithEmail:email link:link]; + [self internalSignInAndRetrieveDataWithCredential:credential + isReauthentication:NO + callback:^(FIRAuthDataResult *_Nullable authResult, + NSError *_Nullable error) { + decoratedCallback(authResult, error); + }]; + }); +} + /** @fn signInWithEmail:password:callback: @brief Signs in using an email address and password. @param email The user's email address. @@ -536,6 +581,7 @@ static NSMutableDictionary *gKeychainServiceNameForAppName; - (void)signInWithEmail:(NSString *)email password:(NSString *)password callback:(FIRAuthResultCallback)callback { + FIRVerifyPasswordRequest *request = [[FIRVerifyPasswordRequest alloc] initWithEmail:email password:password @@ -591,6 +637,40 @@ static NSMutableDictionary *gKeychainServiceNameForAppName; callback:completion]; } +/** @fn internalSignInWithEmail:link:completion: + @brief Signs in using an email and email sign-in link. + @param email The user's email address. + @param link The email sign-in link. + @param callback A block which is invoked when the sign in finishes (or is cancelled.) Invoked + asynchronously on the global auth work queue in the future. + */ +- (void)internalSignInWithEmail:(nonnull NSString *)email + link:(nonnull NSString *)link + callback:(nullable FIRAuthResultCallback)callback { + NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link]; + NSDictionary<NSString *, NSString *> *queryItems = FIRAuthParseURL(urlComponents.query); + NSString *actionCode = queryItems[@"oobCode"]; + + FIREmailLinkSignInRequest *request = + [[FIREmailLinkSignInRequest alloc] initWithEmail:email + oobCode:actionCode + requestConfiguration:_requestConfiguration]; + + [FIRAuthBackend emailLinkSignin:request + callback:^(FIREmailLinkSignInResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + callback(nil, error); + return; + } + [self completeSignInWithAccessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken + anonymous:NO + callback:callback]; + }]; +} + - (void)signInWithCredential:(FIRAuthCredential *)credential completion:(FIRAuthResultCallback)completion { dispatch_async(FIRAuthGlobalWorkQueue(), ^{ @@ -628,24 +708,31 @@ static NSMutableDictionary *gKeychainServiceNameForAppName; // Special case for email/password credentials FIREmailPasswordAuthCredential *emailPasswordCredential = (FIREmailPasswordAuthCredential *)credential; - [self signInWithEmail:emailPasswordCredential.email - password:emailPasswordCredential.password - callback:^(FIRUser *_Nullable user, NSError *_Nullable error) { + FIRAuthResultCallback completeEmailSignIn = ^(FIRUser *user, NSError *error) { if (callback) { if (error) { callback(nil, error); return; } - FIRAdditionalUserInfo *additionalUserInfo = - [[FIRAdditionalUserInfo alloc] initWithProviderID:FIREmailAuthProviderID - profile:nil - username:nil - isNewUser:NO]; + FIRAdditionalUserInfo *additionalUserInfo = + [[FIRAdditionalUserInfo alloc] initWithProviderID:FIREmailAuthProviderID + profile:nil + username:nil + isNewUser:NO]; FIRAuthDataResult *result = [[FIRAuthDataResult alloc] initWithUser:user additionalUserInfo:additionalUserInfo]; - callback(result, nil); + callback(result, error); } - }]; + }; + if (emailPasswordCredential.link) { + [self internalSignInWithEmail:emailPasswordCredential.email + link:emailPasswordCredential.link + callback:completeEmailSignIn]; + } else { + [self signInWithEmail:emailPasswordCredential.email + password:emailPasswordCredential.password + callback:completeEmailSignIn]; + } return; } @@ -1013,6 +1100,31 @@ static NSMutableDictionary *gKeychainServiceNameForAppName; }); } +- (void)sendSignInLinkToEmail:(nonnull NSString *)email + actionCodeSettings:(nonnull FIRActionCodeSettings *)actionCodeSettings + completion:(nullable FIRSendSignInLinkToEmailCallback)completion { + dispatch_async(FIRAuthGlobalWorkQueue(), ^{ + if (!email) { + [FIRAuthExceptionUtils raiseInvalidParameterExceptionWithReason: + kMissingEmailInvalidParameterExceptionReason]; + } + FIRGetOOBConfirmationCodeRequest *request = + [FIRGetOOBConfirmationCodeRequest signInWithEmailLinkRequest:email + actionCodeSettings:actionCodeSettings + requestConfiguration:_requestConfiguration]; + [FIRAuthBackend getOOBConfirmationCode:request + callback:^(FIRGetOOBConfirmationCodeResponse *_Nullable response, + NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_main_queue(), ^{ + completion(error); + }); + } + }]; + }); +} + + - (BOOL)signOut:(NSError *_Nullable __autoreleasing *_Nullable)error { __block BOOL result = YES; dispatch_sync(FIRAuthGlobalWorkQueue(), ^{ @@ -1031,6 +1143,50 @@ static NSMutableDictionary *gKeychainServiceNameForAppName; return [self updateCurrentUser:nil byForce:YES savingToDisk:YES error:error]; } +- (BOOL)isSignInWithEmailLink:(NSString *)link { + if (link.length == 0) { + return NO; + } + NSURLComponents *urlComponents = [NSURLComponents componentsWithString:link]; + if (!urlComponents.query) { + return NO; + } + NSDictionary<NSString *, NSString *> *queryItems = FIRAuthParseURL(urlComponents.query); + + NSString *actionCode = queryItems[@"oobCode"]; + NSString *mode = queryItems[@"mode"]; + + if (actionCode && [mode isEqualToString:@"signIn"]) { + return YES; + } + 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; + 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; diff --git a/Firebase/Auth/Source/Public/FIRAuth.h b/Firebase/Auth/Source/Public/FIRAuth.h index f18a3d0..c985658 100644 --- a/Firebase/Auth/Source/Public/FIRAuth.h +++ b/Firebase/Auth/Source/Public/FIRAuth.h @@ -114,6 +114,14 @@ typedef void (^FIRProviderQueryCallback)(NSArray<NSString *> *_Nullable provider NSError *_Nullable error) NS_SWIFT_NAME(ProviderQueryCallback); +/** @typedef FIRSignInMethodQueryCallback + @brief The type of block invoked when a list of sign-in methods for a given email address is + requested. + */ +typedef void (^FIRSignInMethodQueryCallback)(NSArray<NSString *> *_Nullable, + NSError *_Nullable) + NS_SWIFT_NAME(SignInMethodQueryCallback); + /** @typedef FIRSendPasswordResetCallback @brief The type of block invoked when sending a password reset email. @@ -123,6 +131,12 @@ typedef void (^FIRProviderQueryCallback)(NSArray<NSString *> *_Nullable provider typedef void (^FIRSendPasswordResetCallback)(NSError *_Nullable error) NS_SWIFT_NAME(SendPasswordResetCallback); +/** @typedef FIRSendSignInLinkToEmailCallback + @brief The type of block invoked when sending an email sign-in link email. + */ +typedef void (^FIRSendSignInLinkToEmailCallback)(NSError *_Nullable error) + NS_SWIFT_NAME(SendSignInLinkToEmailCallback); + /** @typedef FIRConfirmPasswordResetCallback @brief The type of block invoked when performing a password reset. @@ -190,6 +204,10 @@ typedef NS_ENUM(NSInteger, FIRActionCodeOperation) { /** Action code for recover email operation. */ FIRActionCodeOperationRecoverEmail = 3, + /** Action code for email link operation. */ + FIRActionCodeOperationEmailLink = 4, + + } NS_SWIFT_NAME(ActionCodeOperation); /** @@ -297,6 +315,24 @@ NS_SWIFT_NAME(Auth) - (void)fetchProvidersForEmail:(NSString *)email completion:(nullable FIRProviderQueryCallback)completion; +/** @fn fetchSignInMethodsForEmail:completion: + @brief Fetches the list of all sign-in methods previously used for the provided email address. + + @param email The email address for which to obtain a list of sign-in methods. + @param completion Optionally; a block which is invoked when the list of sign in methods for the + specified email address is ready or an error was encountered. Invoked asynchronously on the + main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is malformed. + + @remarks See @c FIRAuthErrors for a list of error codes that are common to all API methods. + */ + +- (void)fetchSignInMethodsForEmail:(NSString *)email + completion:(nullable FIRSignInMethodQueryCallback)completion; + /** @fn signInWithEmail:password:completion: @brief Signs in using an email address and password. @@ -322,6 +358,30 @@ NS_SWIFT_NAME(Auth) password:(NSString *)password completion:(nullable FIRAuthResultCallback)completion; +/** @fn signInWithEmail:link:completion: + @brief Signs in using an email address and email sign-in link. + + @param email The user's email address. + @param link The email sign-in link. + @param completion Optionally; a block which is invoked when the sign in flow finishes, or is + canceled. Invoked asynchronously on the main thread in the future. + + @remarks Possible error codes: + + + `FIRAuthErrorCodeOperationNotAllowed` - Indicates that email and email sign-in link + accounts are not enabled. Enable them in the Auth section of the + Firebase console. + + `FIRAuthErrorCodeUserDisabled` - Indicates the user's account is disabled. + + `FIRAuthErrorCodeInvalidEmail` - Indicates the email address is invalid. + + + @remarks See `FIRAuthErrors` for a list of error codes that are common to all API methods. + */ + +- (void)signInWithEmail:(NSString *)email + link:(NSString *)link + completion:(nullable FIRAuthDataResultCallback)completion; + /** @fn signInAndRetrieveDataWithEmail:password:completion: @brief Signs in using an email address and password. @@ -654,6 +714,19 @@ NS_SWIFT_NAME(Auth) actionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings completion:(nullable FIRSendPasswordResetCallback)completion; +/** @fn sendSignInLinkToEmail:actionCodeSettings:completion: + @brief Sends a sign in with email link to provided email address. + + @param email The email address of the user. + @param actionCodeSettings An @c FIRActionCodeSettings object containing settings related to + handling action codes. + @param completion Optionally; a block which is invoked when the request finishes. Invoked + asynchronously on the main thread in the future. + */ +- (void)sendSignInLinkToEmail:(NSString *)email + actionCodeSettings:(FIRActionCodeSettings *)actionCodeSettings + completion:(nullable FIRSendSignInLinkToEmailCallback)completion; + /** @fn signOut: @brief Signs out the current user. @@ -672,6 +745,14 @@ NS_SWIFT_NAME(Auth) */ - (BOOL)signOut:(NSError *_Nullable *_Nullable)error; +/** @fn isSignInWithEmailLink + @brief Checks if link is an email sign-in link. + + @param link The email sign-in link. + @return @YES when the link passed matches the expected format of an email sign-in link. + */ +- (BOOL)isSignInWithEmailLink:(NSString *)link; + /** @fn addAuthStateDidChangeListener: @brief Registers a block as an "auth state did change" listener. To be invoked when: diff --git a/Firebase/Auth/Source/Public/FIREmailAuthProvider.h b/Firebase/Auth/Source/Public/FIREmailAuthProvider.h index 99cd018..5823911 100644 --- a/Firebase/Auth/Source/Public/FIREmailAuthProvider.h +++ b/Firebase/Auth/Source/Public/FIREmailAuthProvider.h @@ -51,6 +51,15 @@ typedef FIREmailAuthProvider FIREmailPasswordAuthProvider __attribute__((depreca */ + (FIRAuthCredential *)credentialWithEmail:(NSString *)email password:(NSString *)password; +/** @fn credentialWithEmail:Link: + @brief Creates an `FIRAuthCredential` for an email & link sign in. + + @param email The user's email address. + @param link The email sign-in link. + @return A FIRAuthCredential containing the email & link credential. + */ ++ (FIRAuthCredential *)credentialWithEmail:(NSString *)email link:(NSString *)link; + /** @fn init @brief This class is not meant to be initialized. */ diff --git a/Firebase/Auth/Source/RPCs/FIRAuthBackend.h b/Firebase/Auth/Source/RPCs/FIRAuthBackend.h index a82c3a7..5928e71 100644 --- a/Firebase/Auth/Source/RPCs/FIRAuthBackend.h +++ b/Firebase/Auth/Source/RPCs/FIRAuthBackend.h @@ -19,6 +19,8 @@ @class FIRAuthRequestConfiguration; @class FIRCreateAuthURIRequest; @class FIRCreateAuthURIResponse; +@class FIREmailLinkSignInRequest; +@class FIREmailLinkSignInResponse; @class FIRGetAccountInfoRequest; @class FIRGetAccountInfoResponse; @class FIRGetProjectConfigRequest; @@ -130,6 +132,16 @@ typedef void (^FIRVerifyAssertionResponseCallback) typedef void (^FIRVerifyPasswordResponseCallback) (FIRVerifyPasswordResponse *_Nullable response, NSError *_Nullable error); +/** @typedef FIREmailLinkSigninResponseCallback + @brief The type of block used to return the result of a call to the emailLinkSignin + endpoint. + @param response The received response, if any. + @param error The error which occurred, if any. + @remarks One of response or error will be non-nil. + */ +typedef void (^FIREmailLinkSigninResponseCallback) + (FIREmailLinkSignInResponse *_Nullable response, NSError *_Nullable error); + /** @typedef FIRVerifyCustomTokenResponseCallback @brief The type of block used to return the result of a call to the verifyCustomToken endpoint. @@ -296,6 +308,15 @@ typedef void (^FIRVerifyClientResponseCallback) + (void)verifyPassword:(FIRVerifyPasswordRequest *)request callback:(FIRVerifyPasswordResponseCallback)callback; +/** @fn emailLinkSignin:callback: + @brief Calls the emailLinkSignin endpoint, which is responsible for authenticating a + user through passwordless sign-in. + @param request The request parameters. + @param callback The callback. + */ ++ (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback; + /** @fn secureToken:callback: @brief Calls the token endpoint, which is responsible for performing STS token exchanges and token refreshes. @@ -461,6 +482,15 @@ typedef void (^FIRVerifyClientResponseCallback) - (void)verifyPassword:(FIRVerifyPasswordRequest *)request callback:(FIRVerifyPasswordResponseCallback)callback; +/** @fn emailLinkSignin:callback: + @brief Calls the emailLinkSignin endpoint, which is responsible for authenticating a + user through passwordless sign-in. + @param request The request parameters. + @param callback The callback. + */ +- (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback; + /** @fn secureToken:callback: @brief Calls the token endpoint, which is responsible for performing STS token exchanges and token refreshes. @@ -472,7 +502,7 @@ typedef void (^FIRVerifyClientResponseCallback) /** @fn getOOBConfirmationCode:callback: @brief Calls the getOOBConfirmationCode endpoint, which is responsible for sending email change - request emails, and password reset emails. + request emails, email sign-in link emails, and password reset emails. @param request The request parameters. @param callback The callback. */ diff --git a/Firebase/Auth/Source/RPCs/FIRAuthBackend.m b/Firebase/Auth/Source/RPCs/FIRAuthBackend.m index 6b5232b..e380e34 100644 --- a/Firebase/Auth/Source/RPCs/FIRAuthBackend.m +++ b/Firebase/Auth/Source/RPCs/FIRAuthBackend.m @@ -51,6 +51,8 @@ #import "FIRVerifyCustomTokenResponse.h" #import "FIRVerifyPasswordRequest.h" #import "FIRVerifyPasswordResponse.h" +#import "FIREmailLinkSignInRequest.h" +#import "FIREmailLinkSignInResponse.h" #import "FIRVerifyPhoneNumberRequest.h" #import "FIRVerifyPhoneNumberResponse.h" #import <GTMSessionFetcher/GTMSessionFetcher.h> @@ -430,6 +432,11 @@ static id<FIRAuthBackendImplementation> gBackendImplementation; [[self implementation] verifyPassword:request callback:callback]; } ++ (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback { + [[self implementation] emailLinkSignin:request callback:callback]; +} + + (void)secureToken:(FIRSecureTokenRequest *)request callback:(FIRSecureTokenResponseCallback)callback { [[self implementation] secureToken:request callback:callback]; @@ -623,6 +630,18 @@ static id<FIRAuthBackendImplementation> gBackendImplementation; }]; } +- (void)emailLinkSignin:(FIREmailLinkSignInRequest *)request + callback:(FIREmailLinkSigninResponseCallback)callback { + FIREmailLinkSignInResponse *response = [[FIREmailLinkSignInResponse alloc] init]; + [self postWithRequest:request response:response callback:^(NSError *error) { + if (error) { + callback(nil, error); + } else { + callback(response, nil); + } + }]; +} + - (void)secureToken:(FIRSecureTokenRequest *)request callback:(FIRSecureTokenResponseCallback)callback { FIRSecureTokenResponse *response = [[FIRSecureTokenResponse alloc] init]; diff --git a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.h b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.h index 9f6cbae..8e8f7b0 100644 --- a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.h +++ b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.h @@ -51,6 +51,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, copy, readonly, nullable) NSArray<NSString *> *allProviders; +/** @property signinMethods + @brief A list of sign-in methods available for the passed @c identifier. + */ +@property(nonatomic, copy, readonly, nullable) NSArray<NSString *> *signinMethods; + @end NS_ASSUME_NONNULL_END diff --git a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m index 12ef97c..6f2937f 100644 --- a/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m +++ b/Firebase/Auth/Source/RPCs/FIRCreateAuthURIResponse.m @@ -25,6 +25,7 @@ _registered = [dictionary[@"registered"] boolValue]; _forExistingProvider = [dictionary[@"forExistingProvider"] boolValue]; _allProviders = [dictionary[@"allProviders"] copy]; + _signinMethods = [dictionary[@"signinMethods"] copy]; return YES; } diff --git a/Firebase/Auth/Source/RPCs/FIREmailLinkSignInRequest.h b/Firebase/Auth/Source/RPCs/FIREmailLinkSignInRequest.h new file mode 100644 index 0000000..e1b10d8 --- /dev/null +++ b/Firebase/Auth/Source/RPCs/FIREmailLinkSignInRequest.h @@ -0,0 +1,66 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import <Foundation/Foundation.h> + +#import "FIRAuthRPCRequest.h" +#import "FIRIdentityToolkitRequest.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIREmailLinkSignInRequest + @brief Represents the parameters for the emailLinkSignin endpoint. + */ +@interface FIREmailLinkSignInRequest : FIRIdentityToolkitRequest <FIRAuthRPCRequest> + +#pragma mark - Components of "postBody" + +/** @property email + @brief The email identifier used to complete the email link sign-in. + */ +@property(nonatomic, copy, readonly) NSString *email; + +/** @property oobCode + @brief The OOB code used to complete the email link sign-in flow. + */ +@property(nonatomic, copy, readonly) NSString *oobCode; + +/** @property idToken + @brief The ID Token code potentially used to complete the email link sign-in flow. + */ +@property(nonatomic, copy) NSString *IDToken; + +/** @fn initWithEndpoint:requestConfiguration: + @brief Please use initWithProviderID:requestConfifuration instead. + */ +- (instancetype)initWithEndpoint:(NSString *)endpoint + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration NS_UNAVAILABLE; + +/** @fn initWithProviderID:requestConfifuration + @brief Designated initializer. + @param email The email identifier used to complete hte email link sign-in flow. + @param oobCode The OOB code used to complete the email link sign-in flow. + @param requestConfiguration An object containing configurations to be added to the request. + + */ +- (instancetype)initWithEmail:(NSString *)email + oobCode:(NSString *)oobCode + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration + NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firebase/Auth/Source/RPCs/FIREmailLinkSignInRequest.m b/Firebase/Auth/Source/RPCs/FIREmailLinkSignInRequest.m new file mode 100644 index 0000000..9787e8e --- /dev/null +++ b/Firebase/Auth/Source/RPCs/FIREmailLinkSignInRequest.m @@ -0,0 +1,70 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIREmailLinkSignInRequest.h" + +/** @var kEmailLinkSigninEndpoint + @brief The "EmailLinkSignin" endpoint. + */ +static NSString *const kEmailLinkSigninEndpoint = @"emailLinkSignin"; + +/** @var kEmailKey + @brief The key for the "identifier" value in the request. + */ +static NSString *const kEmailKey = @"email"; + +/** @var kEmailLinkKey + @brief The key for the "emailLink" value in the request. + */ +static NSString *const kOOBCodeKey = @"oobCode"; + +/** @var kIDTokenKey + @brief The key for the "IDToken" value in the request. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kPostBodyKey + @brief The key for the "postBody" value in the request. + */ +static NSString *const kPostBodyKey = @"postBody"; + +@implementation FIREmailLinkSignInRequest + +- (instancetype)initWithEmail:(NSString *)email + oobCode:(NSString *)oobCode + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + self = [super initWithEndpoint:kEmailLinkSigninEndpoint + requestConfiguration:requestConfiguration]; + if (self) { + _email = email; + _oobCode = oobCode; + } + return self; +} + +- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error { + NSMutableDictionary *postBody = [@{ + kEmailKey : _email, + kOOBCodeKey : _oobCode, + } mutableCopy]; + + if (_IDToken) { + postBody[kIDTokenKey] = _IDToken; + } + return postBody; +} + +@end diff --git a/Firebase/Auth/Source/RPCs/FIREmailLinkSignInResponse.h b/Firebase/Auth/Source/RPCs/FIREmailLinkSignInResponse.h new file mode 100644 index 0000000..df0a127 --- /dev/null +++ b/Firebase/Auth/Source/RPCs/FIREmailLinkSignInResponse.h @@ -0,0 +1,54 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import <Foundation/Foundation.h> + +#import "FIRAuthRPCResponse.h" + +NS_ASSUME_NONNULL_BEGIN + +/** @class FIRVerifyAssertionResponse + @brief Represents the response from the emailLinkSignin endpoint. + */ +@interface FIREmailLinkSignInResponse : NSObject<FIRAuthRPCResponse> + +/** @property IDToken + @brief The ID token in the email link sign-in response. + */ +@property(nonatomic, copy, readonly) NSString *IDToken; + +/** @property email + @brief The email returned by the IdP. + */ +@property(nonatomic, strong, readonly, nullable) NSString *email; + +/** @property refreshToken + @brief The refreshToken returned by the server. + */ +@property(nonatomic, strong, readonly, nullable) NSString *refreshToken; + +/** @property approximateExpirationDate + @brief The approximate expiration date of the access token. + */ +@property(nonatomic, copy, readonly, nullable) NSDate *approximateExpirationDate; + +/** @property isNewUser + @brief Flag indicating that the user signing in is a new user and not a returning user. + */ +@property(nonatomic, assign) BOOL isNewUser; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Firebase/Auth/Source/RPCs/FIREmailLinkSignInResponse.m b/Firebase/Auth/Source/RPCs/FIREmailLinkSignInResponse.m new file mode 100644 index 0000000..cd36d41 --- /dev/null +++ b/Firebase/Auth/Source/RPCs/FIREmailLinkSignInResponse.m @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIREmailLinkSignInResponse.h" + +@implementation FIREmailLinkSignInResponse + +- (BOOL)setWithDictionary:(NSDictionary *)dictionary + error:(NSError *_Nullable *_Nullable)error { + _email = [dictionary[@"email"] copy]; + _IDToken = [dictionary[@"idToken"] copy]; + _isNewUser = [dictionary[@"isNewUser"] boolValue]; + _refreshToken = [dictionary[@"refreshToken"] copy]; + _approximateExpirationDate = [dictionary[@"expiresIn"] isKindOfClass:[NSString class]] ? + [NSDate dateWithTimeIntervalSinceNow:[dictionary[@"expiresIn"] doubleValue]] : nil; + return YES; +} + +@end diff --git a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.h b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.h index abd59b4..751cfe7 100644 --- a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.h +++ b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.h @@ -36,6 +36,11 @@ typedef NS_ENUM(NSInteger, FIRGetOOBConfirmationCodeRequestType) { @brief Requests an email verification code. */ FIRGetOOBConfirmationCodeRequestTypeVerifyEmail, + + /** @var FIRGetOOBConfirmationCodeRequestTypeEmailLink + @brief Requests an email sign-in link. + */ + FIRGetOOBConfirmationCodeRequestTypeEmailLink, }; /** @enum FIRGetOOBConfirmationCodeRequest @@ -91,7 +96,7 @@ typedef NS_ENUM(NSInteger, FIRGetOOBConfirmationCodeRequestType) { */ @property(assign, nonatomic) BOOL handleCodeInApp; -/** @fn passwordResetRequestWithEmail:APIKey: +/** @fn passwordResetRequestWithEmail:actionCodeSettings:requestConfiguration: @brief Creates a password reset request. @param email The user's email address. @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code @@ -104,7 +109,7 @@ typedef NS_ENUM(NSInteger, FIRGetOOBConfirmationCodeRequestType) { actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; -/** @fn verifyEmailRequestWithAccessToken:APIKey: +/** @fn verifyEmailRequestWithAccessToken:actionCodeSettings:requestConfiguration: @brief Creates a password reset request. @param accessToken The user's STS Access Token. @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code @@ -117,6 +122,19 @@ typedef NS_ENUM(NSInteger, FIRGetOOBConfirmationCodeRequestType) { actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; +/** @fn signInWithEmailLinkRequest:actionCodeSettings:requestConfiguration: + @brief Creates a sign-in with email link. + @param email The user's email address. + @param actionCodeSettings An object of FIRActionCodeSettings which specifies action code + settings to be applied to the email sign-in link. + @param requestConfiguration An object containing configurations to be added to the request. + @return An email sign-in link request. + */ ++ (nullable FIRGetOOBConfirmationCodeRequest *) + signInWithEmailLinkRequest:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration; + /** @fn init @brief Please use a factory method. */ diff --git a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.m b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.m index 653eddd..438f24b 100644 --- a/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.m +++ b/Firebase/Auth/Source/RPCs/FIRGetOOBConfirmationCodeRequest.m @@ -79,6 +79,11 @@ static NSString *const kCanHandleCodeInAppKey = @"canHandleCodeInApp"; */ static NSString *const kPasswordResetRequestTypeValue = @"PASSWORD_RESET"; +/** @var kEmailLinkSignInTypeValue + @brief The value for the "EMAIL_SIGNIN" request type. + */ +static NSString *const kEmailLinkSignInTypeValue= @"EMAIL_SIGNIN"; + /** @var kVerifyEmailRequestTypeValue @brief The value for the "VERIFY_EMAIL" request type. */ @@ -116,6 +121,8 @@ static NSString *const kVerifyEmailRequestTypeValue = @"VERIFY_EMAIL"; return kPasswordResetRequestTypeValue; case FIRGetOOBConfirmationCodeRequestTypeVerifyEmail: return kVerifyEmailRequestTypeValue; + case FIRGetOOBConfirmationCodeRequestTypeEmailLink: + return kEmailLinkSignInTypeValue; // No default case so that we get a compiler warning if a new value was added to the enum. } } @@ -142,6 +149,17 @@ static NSString *const kVerifyEmailRequestTypeValue = @"VERIFY_EMAIL"; requestConfiguration:requestConfiguration]; } ++ (FIRGetOOBConfirmationCodeRequest *) + signInWithEmailLinkRequest:(NSString *)email + actionCodeSettings:(nullable FIRActionCodeSettings *)actionCodeSettings + requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { + return [[self alloc] initWithRequestType:FIRGetOOBConfirmationCodeRequestTypeEmailLink + email:email + accessToken:nil + actionCodeSettings:actionCodeSettings + requestConfiguration:requestConfiguration]; +} + - (nullable instancetype)initWithRequestType:(FIRGetOOBConfirmationCodeRequestType)requestType email:(nullable NSString *)email accessToken:(nullable NSString *)accessToken @@ -180,6 +198,12 @@ static NSString *const kVerifyEmailRequestTypeValue = @"VERIFY_EMAIL"; body[kIDTokenKey] = _accessToken; } + // For email sign-in link requests, we only need an email address in addition to the already + // required fields. + if (_requestType == FIRGetOOBConfirmationCodeRequestTypeEmailLink) { + body[kEmailKey] = _email; + } + if (_continueURL) { body[kContinueURLKey] = _continueURL; } |