From b7fd1697dd96650ff1d050f60b8808a85c3d55b1 Mon Sep 17 00:00:00 2001 From: renkelvin Date: Fri, 13 Oct 2023 16:56:34 -0700 Subject: [PATCH] Use sign up endpoint for link with email password (#11925) --- FirebaseAuth/CHANGELOG.md | 3 + FirebaseAuth/Sources/Auth/FIRAuth.m | 7 +- FirebaseAuth/Sources/Auth/FIRAuth_Internal.h | 1 + .../Backend/RPC/FIRSignUpNewUserRequest.h | 6 + .../Backend/RPC/FIRSignUpNewUserRequest.m | 11 ++ FirebaseAuth/Sources/User/FIRUser.m | 122 +++++++++++++++-- .../Sources/Utilities/FIRAuthErrorUtils.h | 5 + FirebaseAuth/Tests/Unit/FIRAuthTests.m | 7 + .../Tests/Unit/FIRSignUpNewUserRequestTests.m | 12 ++ .../Unit/FIRSignUpNewUserResponseTests.m | 1 + FirebaseAuth/Tests/Unit/FIRUserTests.m | 125 +++++++++--------- 11 files changed, 223 insertions(+), 77 deletions(-) diff --git a/FirebaseAuth/CHANGELOG.md b/FirebaseAuth/CHANGELOG.md index 9c1c55cfbf4..3c7447e8e47 100644 --- a/FirebaseAuth/CHANGELOG.md +++ b/FirebaseAuth/CHANGELOG.md @@ -1,3 +1,6 @@ +# 10.17.0 +- [fixed] Fix a bug where anonymous account can't be linked with email password credential. (#11911) + # 10.16.0 - [added] Added custom auth domain support in recaptcha v2 authentication flows. (#7553) diff --git a/FirebaseAuth/Sources/Auth/FIRAuth.m b/FirebaseAuth/Sources/Auth/FIRAuth.m index 03c56b780de..d1c84c173e8 100644 --- a/FirebaseAuth/Sources/Auth/FIRAuth.m +++ b/FirebaseAuth/Sources/Auth/FIRAuth.m @@ -35,7 +35,6 @@ #import "FirebaseAuth/Sources/AuthProvider/FIRAuthCredential_Internal.h" #import "FirebaseAuth/Sources/AuthProvider/GameCenter/FIRGameCenterAuthCredential.h" #import "FirebaseAuth/Sources/AuthProvider/OAuth/FIROAuthCredential_Internal.h" -#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" #import "FirebaseAuth/Sources/Backend/FIRAuthRequestConfiguration.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIRequest.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRCreateAuthURIResponse.h" @@ -165,11 +164,6 @@ */ static NSString *const kRevertSecondFactorAdditionRequestType = @"REVERT_SECOND_FACTOR_ADDITION"; -/** @var kMissingRecaptchaTokenErrorPrefix - @brief The prefix of the error message of missing recaptcha token during authenticating. - */ -static NSString *const kMissingRecaptchaTokenErrorPrefix = @"MISSING_RECAPTCHA_TOKEN"; - /** @var kMissingPasswordReason @brief The reason why the @c FIRAuthErrorCodeWeakPassword error is thrown. @remarks This error message will be localized in the future. @@ -1994,6 +1988,7 @@ - (void)internalCreateUserWithEmail:(NSString *)email [[FIRSignUpNewUserRequest alloc] initWithEmail:email password:password displayName:nil + idToken:nil requestConfiguration:_requestConfiguration]; if (![request.password length]) { completion( diff --git a/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h b/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h index cdb1e33d9f6..d259458f4f7 100644 --- a/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h +++ b/FirebaseAuth/Sources/Auth/FIRAuth_Internal.h @@ -16,6 +16,7 @@ #import #import "FirebaseAuth/Interop/FIRAuthInterop.h" +#import "FirebaseAuth/Sources/Backend/FIRAuthBackend.h" #import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h" #import "FirebaseCore/Extension/FIRLogger.h" diff --git a/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h b/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h index e8b3196fe34..f8baf5df4ba 100644 --- a/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h +++ b/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h @@ -38,6 +38,11 @@ NS_ASSUME_NONNULL_BEGIN */ @property(nonatomic, copy, nullable) NSString *displayName; +/** @property idToken + @brief The idToken of the user. + */ +@property(nonatomic, copy, nullable) NSString *idToken; + /** @property captchaResponse @brief Response to the captcha. */ @@ -74,6 +79,7 @@ NS_ASSUME_NONNULL_BEGIN - (nullable instancetype)initWithEmail:(nullable NSString *)email password:(nullable NSString *)password displayName:(nullable NSString *)displayName + idToken:(nullable NSString *)idToken requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration NS_DESIGNATED_INITIALIZER; diff --git a/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m b/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m index e61bcfc0597..2a31249601c 100644 --- a/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m +++ b/FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.m @@ -38,6 +38,11 @@ */ static NSString *const kDisplayNameKey = @"displayName"; +/** @var kIDToken + @brief The key for the "kIDToken" value in the request. + */ +static NSString *const kIDToken = @"idToken"; + /** @var kCaptchaResponseKey @brief The key for the "captchaResponse" value in the request. */ @@ -68,12 +73,14 @@ @implementation FIRSignUpNewUserRequest - (nullable instancetype)initWithEmail:(nullable NSString *)email password:(nullable NSString *)password displayName:(nullable NSString *)displayName + idToken:(nullable NSString *)idToken requestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration { self = [super initWithEndpoint:kSignupNewUserEndpoint requestConfiguration:requestConfiguration]; if (self) { _email = [email copy]; _password = [password copy]; _displayName = [displayName copy]; + _idToken = [idToken copy]; _returnSecureToken = YES; } return self; @@ -84,6 +91,7 @@ - (nullable instancetype)initWithRequestConfiguration: self = [self initWithEmail:nil password:nil displayName:nil + idToken:nil requestConfiguration:requestConfiguration]; return self; } @@ -99,6 +107,9 @@ - (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable) if (_displayName) { postBody[kDisplayNameKey] = _displayName; } + if (_idToken) { + postBody[kIDToken] = _idToken; + } if (_captchaResponse) { postBody[kCaptchaResponseKey] = _captchaResponse; } diff --git a/FirebaseAuth/Sources/User/FIRUser.m b/FirebaseAuth/Sources/User/FIRUser.m index e40dade55af..c3a161eff75 100644 --- a/FirebaseAuth/Sources/User/FIRUser.m +++ b/FirebaseAuth/Sources/User/FIRUser.m @@ -43,6 +43,8 @@ #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterRequest.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRSignInWithGameCenterResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyCustomTokenRequest.h" @@ -61,9 +63,9 @@ #import "FirebaseAuth/Sources/Utilities/FIRAuthWebUtils.h" #if TARGET_OS_IOS -#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h" - #import "FirebaseAuth/Sources/AuthProvider/Phone/FIRPhoneAuthCredential_Internal.h" +#import "FirebaseAuth/Sources/Public/FirebaseAuth/FIRPhoneAuthProvider.h" +#import "FirebaseAuth/Sources/Utilities/FIRAuthRecaptchaVerifier.h" #endif NS_ASSUME_NONNULL_BEGIN @@ -582,7 +584,6 @@ - (void)setTokenService:(FIRSecureTokenService *)tokenService } #pragma mark - - /** @fn updateEmail:password:callback: @brief Updates email address and/or password for the current user. @remarks May fail if there is already an email/password-based account for the same email @@ -1079,6 +1080,109 @@ - (void)internalVerifyBeforeUpdateEmailWithNewEmail:(NSString *)newEmail }); } +- (void)linkWithEmailPassword:(FIREmailPasswordAuthCredential *)credential + authResult:(FIRAuthDataResult *)authResult + completion:(nullable FIRAuthDataResultCallback)completion { + [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { + FIRAuthRequestConfiguration *requestConfiguration = self.auth.requestConfiguration; + FIRSignUpNewUserRequest *request = + [[FIRSignUpNewUserRequest alloc] initWithEmail:credential.email + password:credential.password + displayName:nil + idToken:accessToken + requestConfiguration:requestConfiguration]; + FIRSignupNewUserCallback signUpNewUserCallback = ^(FIRSignUpNewUserResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + [self signOutIfTokenIsInvalidWithError:error]; + callInMainThreadWithAuthDataResultAndError(completion, nil, error); + } else { + // Update the new token and refresh user info again. + self->_tokenService = [[FIRSecureTokenService alloc] + initWithRequestConfiguration:requestConfiguration + accessToken:response.IDToken + accessTokenExpirationDate:response.approximateExpirationDate + refreshToken:response.refreshToken]; + + [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]; + NSError *keychainError; + if (![self updateKeychain:&keychainError]) { + callInMainThreadWithAuthDataResultAndError(completion, nil, keychainError); + return; + } + [self signOutIfTokenIsInvalidWithError:error]; + callInMainThreadWithAuthDataResultAndError(completion, authResult, nil); + }]; + }]; + } + }; + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION) + if ([[FIRAuthRecaptchaVerifier sharedRecaptchaVerifier:self.auth] + enablementStatusForProvider:FIRAuthRecaptchaProviderPassword]) { + [[FIRAuthRecaptchaVerifier sharedRecaptchaVerifier:self.auth] + injectRecaptchaFields:request + provider:FIRAuthRecaptchaProviderPassword + action:FIRAuthRecaptchaActionSignUpPassword + completion:^( + FIRIdentityToolkitRequest *requestWithRecaptchaToken) { + [FIRAuthBackend + signUpNewUser:(FIRSignUpNewUserRequest *)requestWithRecaptchaToken + callback:signUpNewUserCallback]; + }]; + } else { + [FIRAuthBackend + signUpNewUser:request + callback:^(FIRSignUpNewUserResponse *_Nullable response, NSError *_Nullable error) { + if (!error) { + signUpNewUserCallback(response, nil); + return; + } + NSError *underlyingError = [error.userInfo objectForKey:NSUnderlyingErrorKey]; + if (error.code == FIRAuthErrorCodeInternalError && + [[underlyingError.userInfo + objectForKey:FIRAuthErrorUserInfoDeserializedResponseKey][@"message"] + hasPrefix:kMissingRecaptchaTokenErrorPrefix]) { + [[FIRAuthRecaptchaVerifier sharedRecaptchaVerifier:self.auth] + injectRecaptchaFields:request + provider:FIRAuthRecaptchaProviderPassword + action:FIRAuthRecaptchaActionSignUpPassword + completion:^(FIRIdentityToolkitRequest + *requestWithRecaptchaToken) { + [FIRAuthBackend signUpNewUser:(FIRSignUpNewUserRequest *) + requestWithRecaptchaToken + callback:signUpNewUserCallback]; + }]; + } else { + signUpNewUserCallback(nil, error); + } + }]; + } +#else +[FIRAuthBackend signUpNewUser:request callback:signUpNewUserCallback]; +#endif + }]; +} + - (void)linkWithCredential:(FIRAuthCredential *)credential completion:(nullable FIRAuthDataResultCallback)completion { dispatch_async(FIRAuthGlobalWorkQueue(), ^{ @@ -1098,15 +1202,9 @@ - (void)linkWithCredential:(FIRAuthCredential *)credential FIREmailPasswordAuthCredential *emailPasswordCredential = (FIREmailPasswordAuthCredential *)credential; if (emailPasswordCredential.password) { - [self updateEmail:emailPasswordCredential.email - password:emailPasswordCredential.password - callback:^(NSError *error) { - if (error) { - callInMainThreadWithAuthDataResultAndError(completion, nil, error); - } else { - callInMainThreadWithAuthDataResultAndError(completion, result, nil); - } - }]; + [self linkWithEmailPassword:emailPasswordCredential + authResult:result + completion:completion]; } else { [self internalGetTokenWithCallback:^(NSString *_Nullable accessToken, NSError *_Nullable error) { diff --git a/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h b/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h index a066fc9e1e6..0e5e4b4c072 100644 --- a/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h +++ b/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.h @@ -23,6 +23,11 @@ NS_ASSUME_NONNULL_BEGIN +/** @var kMissingRecaptchaTokenErrorPrefix + @brief The prefix of the error message of missing recaptcha token during authenticating. + */ +static NSString *const kMissingRecaptchaTokenErrorPrefix = @"MISSING_RECAPTCHA_TOKEN"; + /** @class FIRAuthErrorUtils @brief Utility class used to construct @c NSError instances. */ diff --git a/FirebaseAuth/Tests/Unit/FIRAuthTests.m b/FirebaseAuth/Tests/Unit/FIRAuthTests.m index edb777d061a..727465551f9 100644 --- a/FirebaseAuth/Tests/Unit/FIRAuthTests.m +++ b/FirebaseAuth/Tests/Unit/FIRAuthTests.m @@ -138,6 +138,11 @@ */ static NSString *const kDisplayName = @"User Doe"; +/** @var kIDToken + @brief The fake id token. + */ +static NSString *const kIDToken = @"IDToken"; + /** @var kFakeGivenName @brief The fake user given name. */ @@ -1818,6 +1823,7 @@ - (void)testCreateUserWithEmailPasswordWithRecaptchaVerificationSuccess { [[FIRSignUpNewUserRequest alloc] initWithEmail:kEmail password:kFakePassword displayName:kDisplayName + idToken:kIDToken requestConfiguration:[FIRAuth auth].requestConfiguration]; [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse recaptchaVersion:kFakeRecaptchaVersion]; @@ -1867,6 +1873,7 @@ - (void)testCreateUserWithEmailPasswordWithRecaptchaFallbackSuccess { [[FIRSignUpNewUserRequest alloc] initWithEmail:kEmail password:kFakePassword displayName:kDisplayName + idToken:kIDToken requestConfiguration:[FIRAuth auth].requestConfiguration]; [constRequestWithRecaptchaToken injectRecaptchaFields:kFakeRecaptchaResponse recaptchaVersion:kFakeRecaptchaVersion]; diff --git a/FirebaseAuth/Tests/Unit/FIRSignUpNewUserRequestTests.m b/FirebaseAuth/Tests/Unit/FIRSignUpNewUserRequestTests.m index 5016e921068..627d2c769ea 100644 --- a/FirebaseAuth/Tests/Unit/FIRSignUpNewUserRequestTests.m +++ b/FirebaseAuth/Tests/Unit/FIRSignUpNewUserRequestTests.m @@ -60,6 +60,16 @@ */ static NSString *const kTestDisplayName = @"DisplayName"; +/** @var kIDTokenKey + @brief the name of the "kIDTokenKey" property in the request. + */ +static NSString *const kIDTokenKey = @"idToken"; + +/** @var kTestIDToken + @brief Testing id token. + */ +static NSString *const kTestIDToken = @"testIDToken"; + /** @var kPasswordKey @brief the name of the "password" property in the request. */ @@ -167,6 +177,7 @@ - (void)testSignUpNewUserRequestNotAnonymous { [[FIRSignUpNewUserRequest alloc] initWithEmail:kTestEmail password:kTestPassword displayName:kTestDisplayName + idToken:kTestIDToken requestConfiguration:_requestConfiguration]; [FIRAuthBackend signUpNewUser:request @@ -190,6 +201,7 @@ - (void)testSignUpNewUserRequestOptionalFields { [[FIRSignUpNewUserRequest alloc] initWithEmail:kTestEmail password:kTestPassword displayName:kTestDisplayName + idToken:kTestIDToken requestConfiguration:_requestConfiguration]; request.captchaResponse = kTestCaptchaResponse; request.clientType = kTestClientType; diff --git a/FirebaseAuth/Tests/Unit/FIRSignUpNewUserResponseTests.m b/FirebaseAuth/Tests/Unit/FIRSignUpNewUserResponseTests.m index 16e747b2443..295a264fc56 100644 --- a/FirebaseAuth/Tests/Unit/FIRSignUpNewUserResponseTests.m +++ b/FirebaseAuth/Tests/Unit/FIRSignUpNewUserResponseTests.m @@ -159,6 +159,7 @@ - (void)testSuccessfulSignUp { [[FIRSignUpNewUserRequest alloc] initWithEmail:kTestEmail password:kTestPassword displayName:kTestDisplayName + idToken:kTestIDToken requestConfiguration:_requestConfiguration]; __block BOOL callbackInvoked; diff --git a/FirebaseAuth/Tests/Unit/FIRUserTests.m b/FirebaseAuth/Tests/Unit/FIRUserTests.m index dee408722d4..3e8d92b7243 100644 --- a/FirebaseAuth/Tests/Unit/FIRUserTests.m +++ b/FirebaseAuth/Tests/Unit/FIRUserTests.m @@ -39,6 +39,7 @@ #import "FirebaseAuth/Sources/Backend/RPC/FIRSecureTokenResponse.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoRequest.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRSetAccountInfoResponse.h" +#import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserRequest.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRSignUpNewUserResponse.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionRequest.h" #import "FirebaseAuth/Sources/Backend/RPC/FIRVerifyAssertionResponse.h" @@ -2251,7 +2252,6 @@ - (void)testlinkEmailAndRetrieveDataSuccess { profile:[[self class] googleProfile] providerIDToken:kFacebookIDToken providerAccessToken:kFacebookAccessToken]; - XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; [[FIRAuth auth] signOut:NULL]; FIRAuthCredential *facebookCredential = @@ -2268,31 +2268,38 @@ - (void)testlinkEmailAndRetrieveDataSuccess { FIRFacebookAuthProviderID); XCTAssertNil(error); - id mockGetAccountInfoResponseUser = - OCMClassMock([FIRGetAccountInfoResponseUser class]); - OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID); - OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail); - OCMStub([mockGetAccountInfoResponseUser displayName]) - .andReturn(kEmailDisplayName); - OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash); - // Get account info is expected to be invoked twice. - [self - expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser]; - [self - expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser]; - - OCMExpect([self->_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]]) - .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request, - FIRSetAccountInfoResponseCallback callback) { - XCTAssertEqualObjects(request.APIKey, kAPIKey); - XCTAssertEqualObjects(request.accessToken, kAccessToken); + OCMExpect([self->_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]]) + .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request, + FIRSignupNewUserCallback callback) { + XCTAssertEqualObjects(request.email, kEmail); XCTAssertEqualObjects(request.password, kFakePassword); - XCTAssertNil(request.localID); XCTAssertNil(request.displayName); dispatch_async(FIRAuthGlobalWorkQueue(), ^() { - id mockSetAccountInfoResponse = - OCMClassMock([FIRSetAccountInfoResponse class]); - callback(mockSetAccountInfoResponse, nil); + id mockSignUpNewUserResponse = + OCMClassMock([FIRSignUpNewUserResponse class]); + [self stubTokensWithMockResponse:mockSignUpNewUserResponse]; + callback(mockSignUpNewUserResponse, nil); + }); + }); + + OCMExpect([self->_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]]) + .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request, + FIRGetAccountInfoResponseCallback callback) { + dispatch_async(FIRAuthGlobalWorkQueue(), ^() { + id mockGetAccountInfoResponseUser = + OCMClassMock([FIRGetAccountInfoResponseUser class]); + OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID); + OCMStub([mockGetAccountInfoResponseUser displayName]) + .andReturn(kEmailDisplayName); + OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail); + OCMStub([mockGetAccountInfoResponseUser passwordHash]) + .andReturn(kPasswordHash); + id mockGetAccountInfoResponse = + OCMClassMock([FIRGetAccountInfoResponse class]); + OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ + mockGetAccountInfoResponseUser + ]); + callback(mockGetAccountInfoResponse, nil); }); }); @@ -2343,31 +2350,38 @@ - (void)testlinkEmailProviderAlreadyLinkedError { FIRFacebookAuthProviderID); XCTAssertNil(error); - id mockGetAccountInfoResponseUser = - OCMClassMock([FIRGetAccountInfoResponseUser class]); - OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID); - OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail); - OCMStub([mockGetAccountInfoResponseUser displayName]) - .andReturn(kEmailDisplayName); - OCMStub([mockGetAccountInfoResponseUser passwordHash]).andReturn(kPasswordHash); - // Get account info is expected to be invoked twice. - [self - expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser]; - [self - expectGetAccountInfoWithMockUserInfoResponse:mockGetAccountInfoResponseUser]; - - OCMExpect([self->_mockBackend setAccountInfo:[OCMArg any] callback:[OCMArg any]]) - .andCallBlock2(^(FIRSetAccountInfoRequest *_Nullable request, - FIRSetAccountInfoResponseCallback callback) { - XCTAssertEqualObjects(request.APIKey, kAPIKey); - XCTAssertEqualObjects(request.accessToken, kAccessToken); + OCMExpect([self->_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]]) + .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request, + FIRSignupNewUserCallback callback) { + XCTAssertEqualObjects(request.email, kEmail); XCTAssertEqualObjects(request.password, kFakePassword); - XCTAssertNil(request.localID); XCTAssertNil(request.displayName); dispatch_async(FIRAuthGlobalWorkQueue(), ^() { - id mockSetAccountInfoResponse = - OCMClassMock([FIRSetAccountInfoResponse class]); - callback(mockSetAccountInfoResponse, nil); + id mockSignUpNewUserResponse = + OCMClassMock([FIRSignUpNewUserResponse class]); + [self stubTokensWithMockResponse:mockSignUpNewUserResponse]; + callback(mockSignUpNewUserResponse, nil); + }); + }); + + OCMExpect([self->_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]]) + .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request, + FIRGetAccountInfoResponseCallback callback) { + dispatch_async(FIRAuthGlobalWorkQueue(), ^() { + id mockGetAccountInfoResponseUser = + OCMClassMock([FIRGetAccountInfoResponseUser class]); + OCMStub([mockGetAccountInfoResponseUser localID]).andReturn(kLocalID); + OCMStub([mockGetAccountInfoResponseUser displayName]) + .andReturn(kEmailDisplayName); + OCMStub([mockGetAccountInfoResponseUser email]).andReturn(kEmail); + OCMStub([mockGetAccountInfoResponseUser passwordHash]) + .andReturn(kPasswordHash); + id mockGetAccountInfoResponse = + OCMClassMock([FIRGetAccountInfoResponse class]); + OCMStub([mockGetAccountInfoResponse users]).andReturn(@[ + mockGetAccountInfoResponseUser + ]); + callback(mockGetAccountInfoResponse, nil); }); }); @@ -2429,11 +2443,11 @@ - (void)testlinkEmailAndRetrieveDataError { FIRFacebookAuthProviderID); XCTAssertNil(error); - OCMExpect([self->_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]]) - .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request, - FIRGetAccountInfoResponseCallback callback) { - XCTAssertEqualObjects(request.APIKey, kAPIKey); - XCTAssertEqualObjects(request.accessToken, kAccessToken); + OCMExpect([self->_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]]) + .andCallBlock2(^(FIRSignUpNewUserRequest *_Nullable request, + FIRSignupNewUserCallback callback) { + XCTAssertEqualObjects(request.email, kEmail); + XCTAssertEqualObjects(request.password, kFakePassword); dispatch_async(FIRAuthGlobalWorkQueue(), ^() { callback(nil, [FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]); }); @@ -2484,15 +2498,8 @@ - (void)testlinkEmailAndRetrieveDataErrorAutoSignOut { FIRFacebookAuthProviderID); XCTAssertNil(error); - OCMExpect([self->_mockBackend getAccountInfo:[OCMArg any] callback:[OCMArg any]]) - .andCallBlock2(^(FIRGetAccountInfoRequest *_Nullable request, - FIRGetAccountInfoResponseCallback callback) { - XCTAssertEqualObjects(request.APIKey, kAPIKey); - XCTAssertEqualObjects(request.accessToken, kAccessToken); - dispatch_async(FIRAuthGlobalWorkQueue(), ^() { - callback(nil, [FIRAuthErrorUtils userTokenExpiredErrorWithMessage:nil]); - }); - }); + OCMExpect([self->_mockBackend signUpNewUser:[OCMArg any] callback:[OCMArg any]]) + .andDispatchError2([FIRAuthErrorUtils userTokenExpiredErrorWithMessage:nil]); FIRAuthCredential *linkEmailCredential = [FIREmailAuthProvider credentialWithEmail:kEmail password:kFakePassword];