diff --git a/FirebaseAuth/Sources/Backend/FIRAuthBackend.m b/FirebaseAuth/Sources/Backend/FIRAuthBackend.m index ccf2c990f38..0ee39aba877 100644 --- a/FirebaseAuth/Sources/Backend/FIRAuthBackend.m +++ b/FirebaseAuth/Sources/Backend/FIRAuthBackend.m @@ -551,6 +551,12 @@ */ static NSString *const kInvalidRecaptchaVersion = @"INVALID_RECAPTCHA_VERSION"; +/** @var kInvalidLoginCredentials + @brief This is the error message the server will respond with if the login credentials is + invalid. in the request. + */ +static NSString *const kInvalidLoginCredentials = @"INVALID_LOGIN_CREDENTIALS"; + /** @var gBackendImplementation @brief The singleton FIRAuthBackendImplementation instance to use. */ @@ -1404,7 +1410,8 @@ + (nullable NSError *)clientErrorWithServerErrorMessage:(NSString *)serverErrorM } if ([shortErrorMessage isEqualToString:kInvalidCredentialErrorMessage] || - [shortErrorMessage isEqualToString:kInvalidPendingToken]) { + [shortErrorMessage isEqualToString:kInvalidPendingToken] || + [shortErrorMessage isEqualToString:kInvalidLoginCredentials]) { return [FIRAuthErrorUtils invalidCredentialErrorWithMessage:serverDetailErrorMessage]; } diff --git a/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h b/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h index 362ed293231..6459badfc93 100644 --- a/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h +++ b/FirebaseAuth/Sources/Public/FirebaseAuth/FIRAuth.h @@ -378,7 +378,9 @@ NS_SWIFT_NAME(Auth) /** @fn fetchSignInMethodsForEmail:completion: @brief Fetches the list of all sign-in methods previously used for the provided email address. - + This method returns an empty list when [Email Enumeration + Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) + is enabled, irrespective of the number of authentication methods available for the given email. @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 @@ -393,10 +395,15 @@ NS_SWIFT_NAME(Auth) - (void)fetchSignInMethodsForEmail:(NSString *)email completion:(nullable void (^)(NSArray *_Nullable, - NSError *_Nullable))completion; + NSError *_Nullable))completion + DEPRECATED_MSG_ATTRIBUTE( + "This method returns an empty list when Email Enumeration Protection is enabled."); /** @fn signInWithEmail:password:completion: - @brief Signs in using an email address and password. + @brief Signs in using an email address and password. When [Email Enumeration + Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) + is enabled, this method fails with FIRAuthErrorCodeInvalidCredentials in case of an invalid + email/password. @param email The user's email address. @param password The user's password. @@ -663,8 +670,10 @@ NS_SWIFT_NAME(Auth) - (void)applyActionCode:(NSString *)code completion:(void (^)(NSError *_Nullable error))completion; /** @fn sendPasswordResetWithEmail:completion: - @brief Initiates a password reset for the given email address. - + @brief Initiates a password reset for the given email address. This method does not throw an + error when there's no user account with the given email address and [Email Enumeration + Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) + is enabled. @param email The email address of the user. @param completion Optionally; a block which is invoked when the request finishes. Invoked asynchronously on the main thread in the future. diff --git a/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h b/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h index 9fb1fbb2701..e78918d68e2 100644 --- a/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h +++ b/FirebaseAuth/Sources/Public/FirebaseAuth/FIRUser.h @@ -132,7 +132,9 @@ NS_SWIFT_NAME(User) /** @fn updateEmail:completion: @brief Updates the email address for the user. On success, the cached user profile data is - updated. + updated. Throws FIRAuthErrorCodeInvalidCredentials error when [Email Enumeration + Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) + is enabled. @remarks May fail if there is already an account with this email address that was created using email and password authentication. @@ -160,7 +162,8 @@ NS_SWIFT_NAME(User) */ - (void)updateEmail:(NSString *)email completion:(nullable void (^)(NSError *_Nullable error))completion - NS_SWIFT_NAME(updateEmail(to:completion:)); + NS_SWIFT_NAME(updateEmail(to:completion:)) + DEPRECATED_MSG_ATTRIBUTE("Use sendEmailVerificationBeforeUpdatingEmail: instead."); /** @fn updatePassword:completion: @brief Updates the password for the user. On success, the cached user profile data is updated. diff --git a/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m b/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m index 1e7cb3ce186..5eb531b749d 100644 --- a/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m +++ b/FirebaseAuth/Sources/Utilities/FIRAuthErrorUtils.m @@ -626,6 +626,10 @@ @"The reCAPTCHA SDK is not linked to your app. See " @"https://cloud.google.com/recaptcha-enterprise/docs/instrument-ios-apps"; +static NSString *const kFIRAuthErrorMessageInvalidLoginCredentials = + @"Login credentials invalid. It is possible that the email/password combination does not " + @"exist."; + /** @var FIRAuthErrorDescription @brief The error descrioption, based on the error code. @remarks No default case so that we get a compiler warning if a new value was added to the enum. diff --git a/FirebaseAuth/Tests/Unit/FIRAuthTests.m b/FirebaseAuth/Tests/Unit/FIRAuthTests.m index 727465551f9..83cf318fc10 100644 --- a/FirebaseAuth/Tests/Unit/FIRAuthTests.m +++ b/FirebaseAuth/Tests/Unit/FIRAuthTests.m @@ -433,6 +433,8 @@ - (void)testFetchSignInMethodsForEmailSuccess { }); }); XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [[FIRAuth auth] fetchSignInMethodsForEmail:kEmail completion:^(NSArray *_Nullable signInMethods, NSError *_Nullable error) { @@ -442,6 +444,7 @@ - (void)testFetchSignInMethodsForEmailSuccess { XCTAssertNil(error); [expectation fulfill]; }]; +#pragma clang diagnostic pop [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; OCMVerifyAll(_mockBackend); } @@ -453,6 +456,8 @@ - (void)testFetchSignInMethodsForEmailFailure { OCMExpect([_mockBackend createAuthURI:[OCMArg any] callback:[OCMArg any]]) .andDispatchError2([FIRAuthErrorUtils tooManyRequestsErrorWithMessage:nil]); XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [[FIRAuth auth] fetchSignInMethodsForEmail:kEmail completion:^(NSArray *_Nullable signInMethods, NSError *_Nullable error) { @@ -462,6 +467,7 @@ - (void)testFetchSignInMethodsForEmailFailure { XCTAssertNotNil(error.userInfo[NSLocalizedDescriptionKey]); [expectation fulfill]; }]; +#pragma clang diagnostic pop [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; OCMVerifyAll(_mockBackend); } diff --git a/FirebaseAuth/Tests/Unit/FIRUserTests.m b/FirebaseAuth/Tests/Unit/FIRUserTests.m index b34a6c8c966..30f421b68f4 100644 --- a/FirebaseAuth/Tests/Unit/FIRUserTests.m +++ b/FirebaseAuth/Tests/Unit/FIRUserTests.m @@ -769,6 +769,8 @@ - (void)testUpdateEmailSuccess { callback(mockSetAccountInfoResponse, nil); }); }); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [user updateEmail:kNewEmail completion:^(NSError *_Nullable error) { XCTAssertNil(error); @@ -777,6 +779,7 @@ - (void)testUpdateEmailSuccess { kNewDisplayName); [expectation fulfill]; }]; +#pragma clang diagnostic pop }]; [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; OCMVerifyAll(_mockBackend); @@ -829,6 +832,8 @@ - (void)testUpdateEmailWithAuthLinkAccountSuccess { callback(mockSetAccountInfoResponse, nil); }); }); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [user updateEmail:kNewEmail completion:^(NSError *_Nullable error) { XCTAssertNil(error); @@ -838,6 +843,7 @@ - (void)testUpdateEmailWithAuthLinkAccountSuccess { XCTAssertFalse(user.isAnonymous); [expectation fulfill]; }]; +#pragma clang diagnostic pop }]; [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; OCMVerifyAll(_mockBackend); @@ -862,6 +868,8 @@ - (void)testUpdateEmailFailure { callback:[OCMArg any]]) .andDispatchError2([FIRAuthErrorUtils invalidEmailErrorWithMessage:nil]); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [user updateEmail:kNewEmail completion:^(NSError *_Nullable error) { @@ -876,6 +884,7 @@ - (void)testUpdateEmailFailure { user); [expectation fulfill]; }]; +#pragma clang diagnostic pop }]; [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; OCMVerifyAll(_mockBackend); @@ -900,6 +909,8 @@ - (void)testUpdateEmailAutoSignOut { callback:[OCMArg any]]) .andDispatchError2([FIRAuthErrorUtils invalidUserTokenErrorWithMessage:nil]); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" [user updateEmail:kNewEmail completion:^(NSError *_Nullable error) { XCTAssertTrue([NSThread isMainThread]); @@ -913,6 +924,7 @@ - (void)testUpdateEmailAutoSignOut { XCTAssertNil([FIRAuth auth].currentUser); [expectation fulfill]; }]; +#pragma clang diagnostic pop }]; [self waitForExpectationsWithTimeout:kExpectationTimeout handler:nil]; OCMVerifyAll(_mockBackend); diff --git a/FirebaseAuth/Tests/Unit/SwiftAPI.swift b/FirebaseAuth/Tests/Unit/SwiftAPI.swift index aed60778d2d..48a165876f8 100644 --- a/FirebaseAuth/Tests/Unit/SwiftAPI.swift +++ b/FirebaseAuth/Tests/Unit/SwiftAPI.swift @@ -96,12 +96,9 @@ class AuthAPI_hOnlyTests: XCTestCase { func FIRAuth_h(credential: AuthCredential) throws { let auth = FirebaseAuth.Auth.auth() - let authApp = FirebaseAuth.Auth.auth(app: FirebaseApp.app()!) let user = auth.currentUser! auth.updateCurrentUser(user) { _ in } - authApp.fetchSignInMethods(forEmail: "abc@abc.com") { string, error in - } auth.signIn(withEmail: "abc@abc.com", password: "password") { result, error in } auth.signIn(withEmail: "abc@abc.com", link: "link") { result, error in @@ -173,7 +170,6 @@ class AuthAPI_hOnlyTests: XCTestCase { let auth = FirebaseAuth.Auth.auth() let user = auth.currentUser! try await auth.updateCurrentUser(user) - _ = try await auth.fetchSignInMethods(forEmail: "abc@abc.com") _ = try await auth.signIn(withEmail: "abc@abc.com", password: "password") _ = try await auth.signIn(withEmail: "abc@abc.com", link: "link") _ = try await auth.signIn(with: credential) @@ -574,8 +570,6 @@ class AuthAPI_hOnlyTests: XCTestCase { let auth = FirebaseAuth.Auth.auth() let user = auth.currentUser! let credential = GoogleAuthProvider.credential(withIDToken: "token", accessToken: "aToken") - user.updateEmail(to: "email") { _ in - } user.updatePassword(to: "password") { _ in } let changeRequest = user.createProfileChangeRequest() @@ -648,7 +642,6 @@ class AuthAPI_hOnlyTests: XCTestCase { let auth = FirebaseAuth.Auth.auth() let user = auth.currentUser! let credential = GoogleAuthProvider.credential(withIDToken: "token", accessToken: "aToken") - try await user.updateEmail(to: "email") try await user.updatePassword(to: "password") let changeRequest = user.createProfileChangeRequest() try await user.reload()