diff --git a/app_check/integration_test/src/integration_test.cc b/app_check/integration_test/src/integration_test.cc index 4220b79967..9f20d02ac4 100644 --- a/app_check/integration_test/src/integration_test.cc +++ b/app_check/integration_test/src/integration_test.cc @@ -391,13 +391,13 @@ void FirebaseAppCheckTest::TerminateFunctions() { } void FirebaseAppCheckTest::SignIn() { - if (auth_->current_user() != nullptr) { + if (auth_->current_user_DEPRECATED() != nullptr) { // Already signed in. return; } LogDebug("Signing in."); firebase::Future sign_in_future = - auth_->SignInAnonymously(); + auth_->SignInAnonymously_DEPRECATED(); WaitForCompletion(sign_in_future, "SignInAnonymously"); if (sign_in_future.error() != 0) { FAIL() << "Ensure your application has the Anonymous sign-in provider " @@ -411,15 +411,15 @@ void FirebaseAppCheckTest::SignOut() { // Auth is not set up. return; } - if (auth_->current_user() == nullptr) { + if (auth_->current_user_DEPRECATED() == nullptr) { // Already signed out. return; } - if (auth_->current_user()->is_anonymous()) { + if (auth_->current_user_DEPRECATED()->is_anonymous()) { // If signed in anonymously, delete the anonymous user. - WaitForCompletion(auth_->current_user()->Delete(), "DeleteAnonymousUser"); + WaitForCompletion(auth_->current_user_DEPRECATED()->Delete(), "DeleteAnonymousUser"); // If there was a problem deleting the user, try to sign out at least. - if (auth_->current_user()) { + if (auth_->current_user_DEPRECATED()) { auth_->SignOut(); } } else { @@ -428,11 +428,11 @@ void FirebaseAppCheckTest::SignOut() { auth_->SignOut(); // Wait for the sign-out to finish. - while (auth_->current_user() != nullptr) { + while (auth_->current_user_DEPRECATED() != nullptr) { if (ProcessEvents(100)) break; } } - EXPECT_EQ(auth_->current_user(), nullptr); + EXPECT_EQ(auth_->current_user_DEPRECATED(), nullptr); } firebase::database::DatabaseReference FirebaseAppCheckTest::CreateWorkingPath( @@ -544,7 +544,7 @@ TEST_F(FirebaseAppCheckTest, TestSignIn) { InitializeAppCheckWithDebug(); InitializeApp(); InitializeAuth(); - EXPECT_NE(auth_->current_user(), nullptr); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); } TEST_F(FirebaseAppCheckTest, TestDebugProviderValidToken) { diff --git a/auth/integration_test/src/integration_test.cc b/auth/integration_test/src/integration_test.cc index 940382a68b..0de7405094 100644 --- a/auth/integration_test/src/integration_test.cc +++ b/auth/integration_test/src/integration_test.cc @@ -99,7 +99,7 @@ class FirebaseAuthTest : public FirebaseTest { void SignOut(); // Delete the current user if it's currently signed in. - void DeleteUser(); + void DeleteUser(firebase::auth::User* user = nullptr); // Passthrough method to the base class's WaitForCompletion. bool WaitForCompletion(firebase::Future future, const char* fn, @@ -162,7 +162,6 @@ void FirebaseAuthTest::Initialize() { ::firebase::ModuleInitializer initializer; initializer.Initialize(app_, &auth_, [](::firebase::App* app, void* target) { - LogDebug("Try to initialize Firebase Auth"); firebase::InitResult result; firebase::auth::Auth** auth_ptr = reinterpret_cast(target); @@ -176,8 +175,6 @@ void FirebaseAuthTest::Initialize() { ASSERT_EQ(initializer.InitializeLastResult().error(), 0) << initializer.InitializeLastResult().error_message(); - LogDebug("Successfully initialized Firebase Auth."); - initialized_ = true; } @@ -206,7 +203,7 @@ bool FirebaseAuthTest::WaitForCompletion( if (expected_error == ::firebase::auth::kAuthErrorNone) { const firebase::auth::User* future_result_user = future.result() ? *future.result() : nullptr; - const firebase::auth::User* auth_user = auth_->current_user(); + const firebase::auth::User* auth_user = auth_->current_user_DEPRECATED(); EXPECT_EQ(future_result_user, auth_user) << "User returned by Future doesn't match User in Auth"; return (future_result_user == auth_user); @@ -225,7 +222,7 @@ bool FirebaseAuthTest::WaitForCompletion( const firebase::auth::User* future_result_user = (future.result() && future.result()->user) ? future.result()->user : nullptr; - const firebase::auth::User* auth_user = auth_->current_user(); + const firebase::auth::User* auth_user = auth_->current_user_DEPRECATED(); EXPECT_EQ(future_result_user, auth_user) << "User returned by Future doesn't match User in Auth"; return (future_result_user == auth_user); @@ -251,24 +248,28 @@ void FirebaseAuthTest::SignOut() { // Auth is not set up. return; } - if (auth_->current_user() == nullptr) { + if (auth_->current_user_DEPRECATED() == nullptr) { // Already signed out. return; } auth_->SignOut(); // Wait for the sign-out to finish. - while (auth_->current_user() != nullptr) { + while (auth_->current_user_DEPRECATED() != nullptr) { if (ProcessEvents(100)) break; } ProcessEvents(100); - EXPECT_EQ(auth_->current_user(), nullptr); + EXPECT_EQ(auth_->current_user_DEPRECATED(), nullptr); } -void FirebaseAuthTest::DeleteUser() { - if (auth_ != nullptr && auth_->current_user() != nullptr) { - FirebaseTest::WaitForCompletion(auth_->current_user()->Delete(), - "Delete User"); - ProcessEvents(100); +void FirebaseAuthTest::DeleteUser(firebase::auth::User* user) { + if (auth_ != nullptr) { + if (user == nullptr) { + user = auth_->current_user_DEPRECATED(); + } + if (user != nullptr) { + FirebaseTest::WaitForCompletion(user->Delete(), "Delete User"); + ProcessEvents(100); + } } } @@ -280,9 +281,9 @@ TEST_F(FirebaseAuthTest, TestInitialization) { TEST_F(FirebaseAuthTest, TestAnonymousSignin) { // Test notification on SignIn(). - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - EXPECT_NE(auth_->current_user(), nullptr); - EXPECT_TRUE(auth_->current_user()->is_anonymous()); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); + EXPECT_TRUE(auth_->current_user_DEPRECATED()->is_anonymous()); DeleteUser(); } @@ -312,8 +313,9 @@ class TestAuthStateListener : public firebase::auth::AuthStateListener { public: virtual void OnAuthStateChanged(firebase::auth::Auth* auth) { // NOLINT // Log the provider ID. - std::string provider = - auth->current_user() ? auth->current_user()->provider_id() : ""; + std::string provider = auth->current_user_DEPRECATED() + ? auth->current_user_DEPRECATED()->provider_id() + : ""; LogDebug("OnAuthStateChanged called, provider=%s", provider.c_str()); if (auth_states_.empty() || auth_states_.back() != provider) { // Only log unique events. @@ -331,9 +333,9 @@ class TestIdTokenListener : public firebase::auth::IdTokenListener { virtual void OnIdTokenChanged(firebase::auth::Auth* auth) { // NOLINT // Log the auth token (if available). std::string token = ""; - if (auth->current_user()) { + if (auth->current_user_DEPRECATED()) { firebase::Future token_future = - auth->current_user()->GetToken(false); + auth->current_user_DEPRECATED()->GetToken(false); if (token_future.status() == firebase::kFutureStatusComplete) { if (token_future.error() == 0) { token = *token_future.result(); @@ -366,15 +368,15 @@ TEST_F(FirebaseAuthTest, TestTokensAndAuthStateListeners) { TestIdTokenListener token_listener; auth_->AddAuthStateListener(&listener); auth_->AddIdTokenListener(&token_listener); - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); // Get an initial token. firebase::Future token_future = - auth_->current_user()->GetToken(false); + auth_->current_user_DEPRECATED()->GetToken(false); WaitForCompletion(token_future, "GetToken(false)"); std::string first_token = *token_future.result(); // Force a token refresh. ProcessEvents(1000); - token_future = auth_->current_user()->GetToken(true); + token_future = auth_->current_user_DEPRECATED()->GetToken(true); WaitForCompletion(token_future, "GetToken(true)"); EXPECT_NE(*token_future.result(), ""); std::string second_token = *token_future.result(); @@ -409,55 +411,91 @@ TEST_F(FirebaseAuthTest, TestEmailAndPasswordSignin) { // Register a random email and password. This signs us in as that user. std::string password = kTestPassword; firebase::Future create_user = - auth_->CreateUserWithEmailAndPassword(email.c_str(), password.c_str()); - WaitForCompletion(create_user, "CreateUserWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); - // Sign out and log in using SignInWithCredential(EmailCredential). + auth_->CreateUserWithEmailAndPassword_DEPRECATED(email.c_str(), + password.c_str()); + WaitForCompletion(create_user, "CreateUserWithEmailAndPassword_DEPRECATED"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); + // Sign out and log in using SignInWithCredential_DEPRECATED(EmailCredential). SignOut(); { firebase::auth::Credential email_credential = firebase::auth::EmailAuthProvider::GetCredential(email.c_str(), password.c_str()); - WaitForCompletion(auth_->SignInWithCredential(email_credential), + WaitForCompletion(auth_->SignInWithCredential_DEPRECATED(email_credential), "SignInWithCredential"); - EXPECT_NE(auth_->current_user(), nullptr); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); } // Sign out and log in using - // SignInAndRetrieveDataWithCredential(EmailCredential). + // SignInAndRetrieveDataWithCredential_DEPRECATED(EmailCredential). SignOut(); { firebase::auth::Credential email_credential = firebase::auth::EmailAuthProvider::GetCredential(email.c_str(), password.c_str()); WaitForCompletion( - auth_->SignInAndRetrieveDataWithCredential(email_credential), + auth_->SignInAndRetrieveDataWithCredential_DEPRECATED(email_credential), "SignAndRetrieveDataInWithCredential"); - EXPECT_NE(auth_->current_user(), nullptr); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); } SignOut(); // Sign in with SignInWithEmailAndPassword values. firebase::Future sign_in_user = - auth_->SignInWithEmailAndPassword(email.c_str(), password.c_str()); + auth_->SignInWithEmailAndPassword_DEPRECATED(email.c_str(), + password.c_str()); WaitForCompletion(sign_in_user, "SignInWithEmailAndPassword"); - ASSERT_NE(auth_->current_user(), nullptr); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); // Then delete the account. - firebase::Future delete_user = auth_->current_user()->Delete(); + firebase::Future delete_user = + auth_->current_user_DEPRECATED()->Delete(); WaitForCompletion(delete_user, "Delete"); firebase::Future invalid_sign_in_user = - auth_->SignInWithEmailAndPassword(email.c_str(), password.c_str()); + auth_->SignInWithEmailAndPassword_DEPRECATED(email.c_str(), + password.c_str()); WaitForCompletion(invalid_sign_in_user, "SignInWithEmailAndPassword (invalid user)", firebase::auth::kAuthErrorUserNotFound); - EXPECT_EQ(auth_->current_user(), nullptr); + EXPECT_EQ(auth_->current_user_DEPRECATED(), nullptr); +} + +TEST_F(FirebaseAuthTest, TestRetainUser) { + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); + firebase::auth::User anonymous_user = *auth_->current_user_DEPRECATED(); + EXPECT_EQ(anonymous_user.is_anonymous(), true); + EXPECT_EQ(anonymous_user.email().size(), 0); + + SignOut(); + + std::string email = GenerateEmailAddress(); + // Register a random email and password. This signs us in as that user. + std::string password = kTestPassword; + firebase::Future create_user_future = + auth_->CreateUserWithEmailAndPassword_DEPRECATED(email.c_str(), + password.c_str()); + WaitForCompletion(create_user_future, + "CreateUserWithEmailAndPassword_DEPRECATED"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); + firebase::auth::User* email_user = auth_->current_user_DEPRECATED(); + + // Ensure the users are distinct objects. + EXPECT_EQ(anonymous_user.is_anonymous(), true); + EXPECT_EQ(email_user->is_anonymous(), false); + + EXPECT_EQ(anonymous_user.email().size(), 0); + EXPECT_NE(email_user->email().size(), 0); + + DeleteUser(); + DeleteUser(&anonymous_user); } TEST_F(FirebaseAuthTest, TestUpdateUserProfile) { std::string email = GenerateEmailAddress(); firebase::Future create_user = - auth_->CreateUserWithEmailAndPassword(email.c_str(), kTestPassword); - WaitForCompletion(create_user, "CreateUserWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); + auth_->CreateUserWithEmailAndPassword_DEPRECATED(email.c_str(), + kTestPassword); + WaitForCompletion(create_user, "CreateUserWithEmailAndPassword_DEPRECATED"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); // Set some user profile properties. firebase::auth::User* user = *create_user.result(); const char kDisplayName[] = "Hello World"; @@ -470,9 +508,9 @@ TEST_F(FirebaseAuthTest, TestUpdateUserProfile) { EXPECT_EQ(user->display_name(), kDisplayName); EXPECT_EQ(user->photo_url(), kPhotoUrl); SignOut(); - WaitForCompletion( - auth_->SignInWithEmailAndPassword(email.c_str(), kTestPassword), - "SignInWithEmailAndPassword"); + WaitForCompletion(auth_->SignInWithEmailAndPassword_DEPRECATED(email.c_str(), + kTestPassword), + "SignInWithEmailAndPassword"); EXPECT_EQ(user->display_name(), kDisplayName); EXPECT_EQ(user->photo_url(), kPhotoUrl); DeleteUser(); @@ -480,11 +518,11 @@ TEST_F(FirebaseAuthTest, TestUpdateUserProfile) { TEST_F(FirebaseAuthTest, TestUpdateEmailAndPassword) { std::string email = GenerateEmailAddress(); - WaitForCompletion( - auth_->CreateUserWithEmailAndPassword(email.c_str(), kTestPassword), - "CreateUserWithEmailAndPassword"); - ASSERT_NE(auth_->current_user(), nullptr); - firebase::auth::User* user = auth_->current_user(); + WaitForCompletion(auth_->CreateUserWithEmailAndPassword_DEPRECATED( + email.c_str(), kTestPassword), + "CreateUserWithEmailAndPassword_DEPRECATED"); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); + firebase::auth::User* user = auth_->current_user_DEPRECATED(); // Update the user's email and password. const std::string new_email = "new_" + email; @@ -496,164 +534,170 @@ TEST_F(FirebaseAuthTest, TestUpdateEmailAndPassword) { firebase::auth::EmailAuthProvider::GetCredential(new_email.c_str(), kTestPasswordUpdated); WaitForCompletion(user->Reauthenticate(new_email_cred), "Reauthenticate"); - EXPECT_NE(auth_->current_user(), nullptr); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); WaitForCompletion(user->SendEmailVerification(), "SendEmailVerification"); DeleteUser(); } TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential) { - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - ASSERT_NE(auth_->current_user(), nullptr); - firebase::auth::User* user = auth_->current_user(); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); + firebase::auth::User* user = auth_->current_user_DEPRECATED(); std::string email = GenerateEmailAddress(); firebase::auth::Credential credential = firebase::auth::EmailAuthProvider::GetCredential(email.c_str(), kTestPassword); - WaitForCompletion(user->LinkAndRetrieveDataWithCredential(credential), - "LinkAndRetrieveDataWithCredential"); - WaitForCompletion(user->Unlink(credential.provider().c_str()), "Unlink"); + WaitForCompletion( + user->LinkAndRetrieveDataWithCredential_DEPRECATED(credential), + "LinkAndRetrieveDataWithCredential_DEPRECATED"); + WaitForCompletion(user->Unlink_DEPRECATED(credential.provider().c_str()), + "Unlink"); SignOut(); - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - EXPECT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); std::string email1 = GenerateEmailAddress(); firebase::auth::Credential credential1 = firebase::auth::EmailAuthProvider::GetCredential(email1.c_str(), kTestPassword); - WaitForCompletion(user->LinkWithCredential(credential1), + WaitForCompletion(user->LinkWithCredential_DEPRECATED(credential1), "LinkWithCredential 1"); std::string email2 = GenerateEmailAddress(); firebase::auth::Credential credential2 = firebase::auth::EmailAuthProvider::GetCredential(email2.c_str(), kTestPassword); - WaitForCompletion(user->LinkWithCredential(credential2), + WaitForCompletion(user->LinkWithCredential_DEPRECATED(credential2), "LinkWithCredential 2", firebase::auth::kAuthErrorProviderAlreadyLinked); - WaitForCompletion(user->Unlink(credential.provider().c_str()), "Unlink 2"); + WaitForCompletion(user->Unlink_DEPRECATED(credential.provider().c_str()), + "Unlink 2"); DeleteUser(); } TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithBadCredential) { - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - ASSERT_NE(auth_->current_user(), nullptr); - firebase::auth::User* pre_link_user = auth_->current_user(); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); + firebase::auth::User* pre_link_user = auth_->current_user_DEPRECATED(); firebase::auth::Credential twitter_cred = firebase::auth::TwitterAuthProvider::GetCredential(kTestIdTokenBad, kTestAccessTokenBad); - WaitForCompletion(pre_link_user->LinkWithCredential(twitter_cred), + WaitForCompletion(pre_link_user->LinkWithCredential_DEPRECATED(twitter_cred), "LinkWithCredential", firebase::auth::kAuthErrorInvalidCredential); // Ensure that user stays the same. - EXPECT_EQ(auth_->current_user(), pre_link_user); + EXPECT_EQ(auth_->current_user_DEPRECATED(), pre_link_user); DeleteUser(); } TEST_F(FirebaseAuthTest, TestSignInWithBadEmailFails) { - WaitForCompletion( - auth_->SignInWithEmailAndPassword(kTestEmailBad, kTestPassword), - "SignInWithEmailAndPassword", firebase::auth::kAuthErrorUserNotFound); - EXPECT_EQ(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInWithEmailAndPassword_DEPRECATED(kTestEmailBad, + kTestPassword), + "SignInWithEmailAndPassword", + firebase::auth::kAuthErrorUserNotFound); + EXPECT_EQ(auth_->current_user_DEPRECATED(), nullptr); } TEST_F(FirebaseAuthTest, TestSignInWithBadPasswordFails) { std::string email = GenerateEmailAddress(); - WaitForCompletion( - auth_->CreateUserWithEmailAndPassword(email.c_str(), kTestPassword), - "CreateUserWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->CreateUserWithEmailAndPassword_DEPRECATED( + email.c_str(), kTestPassword), + "CreateUserWithEmailAndPassword_DEPRECATED"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); SignOut(); - WaitForCompletion( - auth_->SignInWithEmailAndPassword(email.c_str(), kTestPasswordBad), - "SignInWithEmailAndPassword", firebase::auth::kAuthErrorWrongPassword); - EXPECT_EQ(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInWithEmailAndPassword_DEPRECATED( + email.c_str(), kTestPasswordBad), + "SignInWithEmailAndPassword", + firebase::auth::kAuthErrorWrongPassword); + EXPECT_EQ(auth_->current_user_DEPRECATED(), nullptr); SignOut(); // Sign back in and delete the user. - WaitForCompletion( - auth_->SignInWithEmailAndPassword(email.c_str(), kTestPassword), - "SignInWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInWithEmailAndPassword_DEPRECATED(email.c_str(), + kTestPassword), + "SignInWithEmailAndPassword"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); DeleteUser(); } TEST_F(FirebaseAuthTest, TestCreateUserWithExistingEmailFails) { std::string email = GenerateEmailAddress(); - WaitForCompletion( - auth_->CreateUserWithEmailAndPassword(email.c_str(), kTestPassword), - "CreateUserWithEmailAndPassword 1"); - EXPECT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->CreateUserWithEmailAndPassword_DEPRECATED( + email.c_str(), kTestPassword), + "CreateUserWithEmailAndPassword_DEPRECATED 1"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); SignOut(); - WaitForCompletion( - auth_->CreateUserWithEmailAndPassword(email.c_str(), kTestPassword), - "CreateUserWithEmailAndPassword 2", - firebase::auth::kAuthErrorEmailAlreadyInUse); - EXPECT_EQ(auth_->current_user(), nullptr); + WaitForCompletion(auth_->CreateUserWithEmailAndPassword_DEPRECATED( + email.c_str(), kTestPassword), + "CreateUserWithEmailAndPassword_DEPRECATED 2", + firebase::auth::kAuthErrorEmailAlreadyInUse); + EXPECT_EQ(auth_->current_user_DEPRECATED(), nullptr); SignOut(); // Try again with a different password. - WaitForCompletion( - auth_->CreateUserWithEmailAndPassword(email.c_str(), kTestPasswordBad), - "CreateUserWithEmailAndPassword 3", - firebase::auth::kAuthErrorEmailAlreadyInUse); - EXPECT_EQ(auth_->current_user(), nullptr); + WaitForCompletion(auth_->CreateUserWithEmailAndPassword_DEPRECATED( + email.c_str(), kTestPasswordBad), + "CreateUserWithEmailAndPassword_DEPRECATED 3", + firebase::auth::kAuthErrorEmailAlreadyInUse); + EXPECT_EQ(auth_->current_user_DEPRECATED(), nullptr); SignOut(); - WaitForCompletion( - auth_->SignInWithEmailAndPassword(email.c_str(), kTestPassword), - "SignInWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInWithEmailAndPassword_DEPRECATED(email.c_str(), + kTestPassword), + "SignInWithEmailAndPassword"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); DeleteUser(); } TEST_F(FirebaseAuthTest, TestSignInWithBadCredentials) { // Get an anonymous user first. - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - ASSERT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); // Hold on to the existing user, to make sure it is unchanged by bad signins. - firebase::auth::User* existing_user = auth_->current_user(); + firebase::auth::User* existing_user = auth_->current_user_DEPRECATED(); // Test signing in with a variety of bad credentials. - WaitForCompletion(auth_->SignInWithCredential( + WaitForCompletion(auth_->SignInWithCredential_DEPRECATED( firebase::auth::FacebookAuthProvider::GetCredential( kTestAccessTokenBad)), "SignInWithCredential (Facebook)", firebase::auth::kAuthErrorInvalidCredential); // Ensure that failing to sign in with a credential doesn't modify the user. - EXPECT_EQ(auth_->current_user(), existing_user); - WaitForCompletion(auth_->SignInWithCredential( + EXPECT_EQ(auth_->current_user_DEPRECATED(), existing_user); + WaitForCompletion(auth_->SignInWithCredential_DEPRECATED( firebase::auth::TwitterAuthProvider::GetCredential( kTestIdTokenBad, kTestAccessTokenBad)), "SignInWithCredential (Twitter)", firebase::auth::kAuthErrorInvalidCredential); - EXPECT_EQ(auth_->current_user(), existing_user); - WaitForCompletion(auth_->SignInWithCredential( + EXPECT_EQ(auth_->current_user_DEPRECATED(), existing_user); + WaitForCompletion(auth_->SignInWithCredential_DEPRECATED( firebase::auth::GitHubAuthProvider::GetCredential( kTestAccessTokenBad)), "SignInWithCredential (GitHub)", firebase::auth::kAuthErrorInvalidCredential); - EXPECT_EQ(auth_->current_user(), existing_user); - WaitForCompletion(auth_->SignInWithCredential( + EXPECT_EQ(auth_->current_user_DEPRECATED(), existing_user); + WaitForCompletion(auth_->SignInWithCredential_DEPRECATED( firebase::auth::GoogleAuthProvider::GetCredential( kTestIdTokenBad, kTestAccessTokenBad)), "SignInWithCredential (Google 1)", firebase::auth::kAuthErrorInvalidCredential); - EXPECT_EQ(auth_->current_user(), existing_user); - WaitForCompletion(auth_->SignInWithCredential( + EXPECT_EQ(auth_->current_user_DEPRECATED(), existing_user); + WaitForCompletion(auth_->SignInWithCredential_DEPRECATED( firebase::auth::GoogleAuthProvider::GetCredential( kTestIdTokenBad, nullptr)), "SignInWithCredential (Google 2)", firebase::auth::kAuthErrorInvalidCredential); - EXPECT_EQ(auth_->current_user(), existing_user); + EXPECT_EQ(auth_->current_user_DEPRECATED(), existing_user); WaitForCompletion( - auth_->SignInWithCredential(firebase::auth::OAuthProvider::GetCredential( - kTestIdProviderIdBad, kTestIdTokenBad, kTestAccessTokenBad)), + auth_->SignInWithCredential_DEPRECATED( + firebase::auth::OAuthProvider::GetCredential( + kTestIdProviderIdBad, kTestIdTokenBad, kTestAccessTokenBad)), "SignInWithCredential (OAuth)", firebase::auth::kAuthErrorFailure); - EXPECT_EQ(auth_->current_user(), existing_user); + EXPECT_EQ(auth_->current_user_DEPRECATED(), existing_user); #if defined(__ANDROID__) // Test Play Games sign-in on Android only. - WaitForCompletion(auth_->SignInWithCredential( + WaitForCompletion(auth_->SignInWithCredential_DEPRECATED( firebase::auth::PlayGamesAuthProvider::GetCredential( kTestServerAuthCodeBad)), "SignInWithCredential (Play Games)", firebase::auth::kAuthErrorInvalidCredential); - EXPECT_EQ(auth_->current_user(), existing_user); + EXPECT_EQ(auth_->current_user_DEPRECATED(), existing_user); #endif // defined(__ANDROID__) DeleteUser(); } @@ -674,8 +718,9 @@ TEST_F(FirebaseAuthTest, TestGameCenterSignIn) { EXPECT_NE(credential_future.result(), nullptr); if (credential_future.result()) { - WaitForCompletion(auth_->SignInWithCredential(*credential_future.result()), - "SignInWithCredential (Game Center)"); + WaitForCompletion( + auth_->SignInWithCredential_DEPRECATED(*credential_future.result()), + "SignInWithCredential (Game Center)"); } DeleteUser(); } @@ -684,10 +729,10 @@ TEST_F(FirebaseAuthTest, TestGameCenterSignIn) { TEST_F(FirebaseAuthTest, TestSendPasswordResetEmail) { // Test Auth::SendPasswordResetEmail(). std::string email = GenerateEmailAddress(); - WaitForCompletion( - auth_->CreateUserWithEmailAndPassword(email.c_str(), kTestPassword), - "CreateUserWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->CreateUserWithEmailAndPassword_DEPRECATED( + email.c_str(), kTestPassword), + "CreateUserWithEmailAndPassword_DEPRECATED"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); SignOut(); // Send to correct email. WaitForCompletion(auth_->SendPasswordResetEmail(email.c_str()), @@ -697,10 +742,10 @@ TEST_F(FirebaseAuthTest, TestSendPasswordResetEmail) { "SendPasswordResetEmail (bad)", firebase::auth::kAuthErrorUserNotFound); // Delete user now that we are done with it. - WaitForCompletion( - auth_->SignInWithEmailAndPassword(email.c_str(), kTestPassword), - "SignInWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInWithEmailAndPassword_DEPRECATED(email.c_str(), + kTestPassword), + "SignInWithEmailAndPassword"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); DeleteUser(); } @@ -714,9 +759,10 @@ TEST_F(FirebaseAuthTest, TestWithCustomEmailAndPassword) { return; } firebase::Future sign_in_user = - auth_->SignInWithEmailAndPassword(kCustomTestEmail, kCustomTestPassword); + auth_->SignInWithEmailAndPassword_DEPRECATED(kCustomTestEmail, + kCustomTestPassword); WaitForCompletion(sign_in_user, "SignInWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); } TEST_F(FirebaseAuthTest, TestAuthPersistenceWithAnonymousSignin) { @@ -725,15 +771,15 @@ TEST_F(FirebaseAuthTest, TestAuthPersistenceWithAnonymousSignin) { FLAKY_TEST_SECTION_BEGIN(); - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - EXPECT_NE(auth_->current_user(), nullptr); - EXPECT_TRUE(auth_->current_user()->is_anonymous()); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); + EXPECT_TRUE(auth_->current_user_DEPRECATED()->is_anonymous()); Terminate(); ProcessEvents(2000); Initialize(); EXPECT_NE(auth_, nullptr); - EXPECT_NE(auth_->current_user(), nullptr); - EXPECT_TRUE(auth_->current_user()->is_anonymous()); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); + EXPECT_TRUE(auth_->current_user_DEPRECATED()->is_anonymous()); DeleteUser(); FLAKY_TEST_SECTION_END(); @@ -745,39 +791,46 @@ TEST_F(FirebaseAuthTest, TestAuthPersistenceWithEmailSignin) { FLAKY_TEST_SECTION_BEGIN(); std::string email = GenerateEmailAddress(); - WaitForCompletion( - auth_->CreateUserWithEmailAndPassword(email.c_str(), kTestPassword), - "CreateUserWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); - EXPECT_FALSE(auth_->current_user()->is_anonymous()); - std::string prev_provider_id = auth_->current_user()->provider_id(); + WaitForCompletion(auth_->CreateUserWithEmailAndPassword_DEPRECATED( + email.c_str(), kTestPassword), + "CreateUserWithEmailAndPassword_DEPRECATED"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); + EXPECT_FALSE(auth_->current_user_DEPRECATED()->is_anonymous()); + std::string prev_provider_id = + auth_->current_user_DEPRECATED()->provider_id(); // Save the old provider ID list so we can make sure it's the same once // it's loaded again. std::vector prev_provider_data_ids; - for (int i = 0; i < auth_->current_user()->provider_data().size(); i++) { - prev_provider_data_ids.push_back( - auth_->current_user()->provider_data()[i]->provider_id()); + for (int i = 0; + i < auth_->current_user_DEPRECATED()->provider_data_DEPRECATED().size(); + i++) { + prev_provider_data_ids.push_back(auth_->current_user_DEPRECATED() + ->provider_data_DEPRECATED()[i] + ->provider_id()); } Terminate(); ProcessEvents(2000); Initialize(); EXPECT_NE(auth_, nullptr); - EXPECT_NE(auth_->current_user(), nullptr); - EXPECT_FALSE(auth_->current_user()->is_anonymous()); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); + EXPECT_FALSE(auth_->current_user_DEPRECATED()->is_anonymous()); // Make sure the provider IDs are the same as they were before. - EXPECT_EQ(auth_->current_user()->provider_id(), prev_provider_id); + EXPECT_EQ(auth_->current_user_DEPRECATED()->provider_id(), prev_provider_id); std::vector loaded_provider_data_ids; - for (int i = 0; i < auth_->current_user()->provider_data().size(); i++) { - loaded_provider_data_ids.push_back( - auth_->current_user()->provider_data()[i]->provider_id()); + for (int i = 0; + i < auth_->current_user_DEPRECATED()->provider_data_DEPRECATED().size(); + i++) { + loaded_provider_data_ids.push_back(auth_->current_user_DEPRECATED() + ->provider_data_DEPRECATED()[i] + ->provider_id()); } EXPECT_TRUE(loaded_provider_data_ids == prev_provider_data_ids); // Cleanup, ensure we are signed in as the user so we can delete it. - WaitForCompletion( - auth_->SignInWithEmailAndPassword(email.c_str(), kTestPassword), - "SignInWithEmailAndPassword"); - EXPECT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInWithEmailAndPassword_DEPRECATED(email.c_str(), + kTestPassword), + "SignInWithEmailAndPassword"); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); DeleteUser(); FLAKY_TEST_SECTION_END(); @@ -904,8 +957,9 @@ TEST_F(FirebaseAuthTest, TestPhoneAuth) { } if (listener.on_verification_complete_count() > 0) { LogDebug("Signing in with automatic verification code."); - WaitForCompletion(auth_->SignInWithCredential(listener.credential()), - "SignInWithCredential(PhoneCredential) automatic"); + WaitForCompletion( + auth_->SignInWithCredential_DEPRECATED(listener.credential()), + "SignInWithCredential_DEPRECATED(PhoneCredential) automatic"); } else if (listener.on_verification_failed_count() > 0) { FAIL() << "Automatic verification failed."; } else { @@ -917,8 +971,8 @@ TEST_F(FirebaseAuthTest, TestPhoneAuth) { phone_provider.GetCredential(listener.verification_id().c_str(), kPhoneAuthTestVerificationCode); - WaitForCompletion(auth_->SignInWithCredential(phone_credential), - "SignInWithCredential(PhoneCredential)"); + WaitForCompletion(auth_->SignInWithCredential_DEPRECATED(phone_credential), + "SignInWithCredential_DEPRECATED(PhoneCredential)"); } ProcessEvents(1000); @@ -939,7 +993,7 @@ TEST_F(FirebaseAuthTest, TestSuccessfulSignInFederatedProviderNoScopes) { provider_id, /*scopes=*/{}, /*custom_parameters=*/{{"req_id", "1234"}}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->SignInWithProvider(&provider); + auth_->SignInWithProvider_DEPRECATED(&provider); WaitForCompletion(sign_in_future, "SignInWithProvider", provider_id); DeleteUser(); } @@ -955,7 +1009,7 @@ TEST_F(FirebaseAuthTest, provider_id, /*scopes=*/{}, /*custom_parameters=*/{}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->SignInWithProvider(&provider); + auth_->SignInWithProvider_DEPRECATED(&provider); WaitForCompletion(sign_in_future, "SignInWithProvider", provider_id); DeleteUser(); } @@ -972,7 +1026,7 @@ TEST_F(FirebaseAuthTest, TestSuccessfulSignInFederatedProvider) { /*custom_parameters=*/{{"req_id", "1234"}}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->SignInWithProvider(&provider); + auth_->SignInWithProvider_DEPRECATED(&provider); WaitForCompletion(sign_in_future, "SignInWithProvider", provider_id); DeleteUser(); } @@ -987,7 +1041,7 @@ TEST_F(FirebaseAuthTest, TestSignInFederatedProviderBadProviderIdFails) { /*custom_parameters=*/{{"req_id", "5321"}}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->SignInWithProvider(&provider); + auth_->SignInWithProvider_DEPRECATED(&provider); WaitForCompletion(sign_in_future, "SignInWithProvider", firebase::auth::kAuthErrorInvalidProviderId); } @@ -1005,10 +1059,11 @@ TEST_F(FirebaseAuthTest, TestSuccessfulReauthenticateWithProvider) { /*custom_parameters=*/{{"req_id", "1234"}}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->SignInWithProvider(&provider); + auth_->SignInWithProvider_DEPRECATED(&provider); if (WaitForCompletion(sign_in_future, "SignInWithProvider", provider_id)) { WaitForCompletion( - sign_in_future.result()->user->ReauthenticateWithProvider(&provider), + sign_in_future.result()->user->ReauthenticateWithProvider_DEPRECATED( + &provider), "ReauthenticateWithProvider", provider_id); } DeleteUser(); @@ -1024,10 +1079,11 @@ TEST_F(FirebaseAuthTest, TestSuccessfulReauthenticateWithProviderNoScopes) { provider_id, /*scopes=*/{}, /*custom_parameters=*/{{"req_id", "1234"}}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->SignInWithProvider(&provider); + auth_->SignInWithProvider_DEPRECATED(&provider); if (WaitForCompletion(sign_in_future, "SignInWithProvider", provider_id)) { WaitForCompletion( - sign_in_future.result()->user->ReauthenticateWithProvider(&provider), + sign_in_future.result()->user->ReauthenticateWithProvider_DEPRECATED( + &provider), "ReauthenticateWithProvider", provider_id); } DeleteUser(); @@ -1044,10 +1100,11 @@ TEST_F(FirebaseAuthTest, provider_id, /*scopes=*/{}, /*custom_parameters=*/{}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->SignInWithProvider(&provider); + auth_->SignInWithProvider_DEPRECATED(&provider); if (WaitForCompletion(sign_in_future, "SignInWithProvider", provider_id)) { WaitForCompletion( - sign_in_future.result()->user->ReauthenticateWithProvider(&provider), + sign_in_future.result()->user->ReauthenticateWithProvider_DEPRECATED( + &provider), "ReauthenticateWithProvider", provider_id); } DeleteUser(); @@ -1062,12 +1119,13 @@ TEST_F(FirebaseAuthTest, TestReauthenticateWithProviderBadProviderIdFails) { firebase::auth::FederatedOAuthProviderData provider_data(provider_id); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->SignInWithProvider(&provider); + auth_->SignInWithProvider_DEPRECATED(&provider); if (WaitForCompletion(sign_in_future, "SignInWithProvider", provider_id)) { provider_data.provider_id = "MadeUpProvider"; firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future reauth_future = - auth_->current_user()->ReauthenticateWithProvider(&provider); + auth_->current_user_DEPRECATED()->ReauthenticateWithProvider_DEPRECATED( + &provider); WaitForCompletion(reauth_future, "ReauthenticateWithProvider", firebase::auth::kAuthErrorInvalidProviderId); } @@ -1078,15 +1136,15 @@ TEST_F(FirebaseAuthTest, TestReauthenticateWithProviderBadProviderIdFails) { TEST_F(FirebaseAuthTest, TestSuccessfulLinkFederatedProviderNoScopes) { SKIP_TEST_ON_DESKTOP; TEST_REQUIRES_USER_INTERACTION; - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - ASSERT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); const std::string provider_id = firebase::auth::GoogleAuthProvider::kProviderId; firebase::auth::FederatedOAuthProviderData provider_data( provider_id, /*scopes=*/{}, /*custom_parameters=*/{{"req_id", "1234"}}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->current_user()->LinkWithProvider(&provider); + auth_->current_user_DEPRECATED()->LinkWithProvider_DEPRECATED(&provider); WaitForCompletion(sign_in_future, "LinkWithProvider", provider_id); DeleteUser(); } @@ -1096,15 +1154,15 @@ TEST_F(FirebaseAuthTest, SKIP_TEST_ON_DESKTOP; TEST_REQUIRES_USER_INTERACTION; - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - ASSERT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); const std::string provider_id = firebase::auth::GoogleAuthProvider::kProviderId; firebase::auth::FederatedOAuthProviderData provider_data( provider_id, /*scopes=*/{}, /*custom_parameters=*/{}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->current_user()->LinkWithProvider(&provider); + auth_->current_user_DEPRECATED()->LinkWithProvider_DEPRECATED(&provider); WaitForCompletion(sign_in_future, "LinkWithProvider", provider_id); DeleteUser(); } @@ -1113,8 +1171,8 @@ TEST_F(FirebaseAuthTest, TestSuccessfulLinkFederatedProvider) { SKIP_TEST_ON_DESKTOP; TEST_REQUIRES_USER_INTERACTION; - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - ASSERT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); const std::string provider_id = firebase::auth::GoogleAuthProvider::kProviderId; firebase::auth::FederatedOAuthProviderData provider_data( @@ -1123,7 +1181,7 @@ TEST_F(FirebaseAuthTest, TestSuccessfulLinkFederatedProvider) { /*custom_parameters=*/{{"req_id", "1234"}}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->current_user()->LinkWithProvider(&provider); + auth_->current_user_DEPRECATED()->LinkWithProvider_DEPRECATED(&provider); WaitForCompletion(sign_in_future, "LinkWithProvider", provider_id); DeleteUser(); } @@ -1132,15 +1190,15 @@ TEST_F(FirebaseAuthTest, TestLinkFederatedProviderBadProviderIdFails) { SKIP_TEST_ON_DESKTOP; TEST_REQUIRES_USER_INTERACTION; - WaitForCompletion(auth_->SignInAnonymously(), "SignInAnonymously"); - ASSERT_NE(auth_->current_user(), nullptr); + WaitForCompletion(auth_->SignInAnonymously_DEPRECATED(), "SignInAnonymously"); + ASSERT_NE(auth_->current_user_DEPRECATED(), nullptr); firebase::auth::FederatedOAuthProviderData provider_data( /*provider=*/"MadeUpProvider", /*scopes=*/{"https://www.googleapis.com/auth/fitness.activity.read"}, /*custom_parameters=*/{{"req_id", "1234"}}); firebase::auth::FederatedOAuthProvider provider(provider_data); firebase::Future sign_in_future = - auth_->current_user()->LinkWithProvider(&provider); + auth_->current_user_DEPRECATED()->LinkWithProvider_DEPRECATED(&provider); WaitForCompletion(sign_in_future, "LinkWithProvider", firebase::auth::kAuthErrorInvalidProviderId); DeleteUser(); diff --git a/auth/samples/src/doc_samples.cc b/auth/samples/src/doc_samples.cc index bcde0eaae8..3a49f27506 100644 --- a/auth/samples/src/doc_samples.cc +++ b/auth/samples/src/doc_samples.cc @@ -119,7 +119,7 @@ void VariousSignIns(firebase::auth::Auth* auth) { { // [START auth_create_user] firebase::Future result = - auth->CreateUserWithEmailAndPassword(email, password); + auth->CreateUserWithEmailAndPassword_DEPRECATED(email, password); // [END auth_create_user] (void)result; } @@ -129,14 +129,14 @@ void VariousSignIns(firebase::auth::Auth* auth) { firebase::auth::OAuthProvider::GetCredential( "apple.com", apple_id_token, raw_nonce, nullptr); firebase::Future result = - auth->SignInWithCredential(credential); + auth->SignInWithCredential_DEPRECATED(credential); // [END auth_sign_in_apple] (void)result; } { // [START auth_sign_in_email] firebase::Future result = - auth->SignInWithEmailAndPassword(email, password); + auth->SignInWithEmailAndPassword_DEPRECATED(email, password); // [END auth_sign_in_email] (void)result; } @@ -146,7 +146,7 @@ void VariousSignIns(firebase::auth::Auth* auth) { firebase::auth::GoogleAuthProvider::GetCredential(google_id_token, nullptr); firebase::Future result = - auth->SignInWithCredential(credential); + auth->SignInWithCredential_DEPRECATED(credential); // [END auth_sign_in_google] (void)result; } @@ -156,7 +156,7 @@ void VariousSignIns(firebase::auth::Auth* auth) { firebase::auth::PlayGamesAuthProvider::GetCredential(server_auth_code); firebase::Future result = - auth->SignInWithCredential(credential); + auth->SignInWithCredential_DEPRECATED(credential); // [END auth_sign_in_play_games] (void)result; } @@ -165,7 +165,7 @@ void VariousSignIns(firebase::auth::Auth* auth) { firebase::auth::Credential credential = firebase::auth::FacebookAuthProvider::GetCredential(access_token); firebase::Future result = - auth->SignInWithCredential(credential); + auth->SignInWithCredential_DEPRECATED(credential); // [END auth_sign_in_facebook] (void)result; } @@ -174,7 +174,7 @@ void VariousSignIns(firebase::auth::Auth* auth) { firebase::auth::Credential credential = firebase::auth::GitHubAuthProvider::GetCredential(token); firebase::Future result = - auth->SignInWithCredential(credential); + auth->SignInWithCredential_DEPRECATED(credential); // [END auth_sign_in_github] (void)result; } @@ -183,20 +183,21 @@ void VariousSignIns(firebase::auth::Auth* auth) { firebase::auth::Credential credential = firebase::auth::TwitterAuthProvider::GetCredential(token, secret); firebase::Future result = - auth->SignInWithCredential(credential); + auth->SignInWithCredential_DEPRECATED(credential); // [END auth_sign_in_twitter] (void)result; } { // [START auth_sign_in_custom_token] firebase::Future result = - auth->SignInWithCustomToken(custom_token); + auth->SignInWithCustomToken_DEPRECATED(custom_token); // [END auth_sign_in_custom_token] (void)result; } { // [START auth_sign_in_anonymously] - firebase::Future result = auth->SignInAnonymously(); + firebase::Future result = + auth->SignInAnonymously_DEPRECATED(); // [END auth_sign_in_anonymously] (void)result; } @@ -220,7 +221,7 @@ void VariousSignInChecks(firebase::auth::Auth* auth) { { // [START auth_sign_in_email_check] firebase::Future result = - auth->SignInWithEmailAndPasswordLastResult(); + auth->SignInWithEmailAndPasswordLastResult_DEPRECATED(); if (result.status() == firebase::kFutureStatusComplete) { if (result.error() == firebase::auth::kAuthErrorNone) { firebase::auth::User* user = *result.result(); @@ -234,7 +235,7 @@ void VariousSignInChecks(firebase::auth::Auth* auth) { { // [START auth_sign_in_credential_check] firebase::Future result = - auth->SignInWithCredentialLastResult(); + auth->SignInWithCredentialLastResult_DEPRECATED(); if (result.status() == firebase::kFutureStatusComplete) { if (result.error() == firebase::auth::kAuthErrorNone) { firebase::auth::User* user = *result.result(); @@ -262,7 +263,7 @@ void VariousSignInChecks(firebase::auth::Auth* auth) { { // [START auth_sign_in_anonymously_check] firebase::Future result = - auth->SignInAnonymouslyLastResult(); + auth->SignInAnonymouslyLastResult_DEPRECATED(); if (result.status() == firebase::kFutureStatusComplete) { if (result.error() == firebase::auth::kAuthErrorNone) { firebase::auth::User* user = *result.result(); @@ -279,7 +280,7 @@ void VariousSignInChecks(firebase::auth::Auth* auth) { class MyAuthStateListener : public firebase::auth::AuthStateListener { public: void OnAuthStateChanged(firebase::auth::Auth* auth) override { - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); if (user != nullptr) { // User is signed in printf("OnAuthStateChanged: signed_in %s\n", user->uid().c_str()); @@ -303,7 +304,7 @@ void VariousUserManagementChecks(firebase::auth::Auth* auth) { } { // [START auth_user_info_check] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); if (user != nullptr) { std::string name = user->display_name(); std::string email = user->email(); @@ -317,7 +318,7 @@ void VariousUserManagementChecks(firebase::auth::Auth* auth) { } { // [START auth_user_profile_data_check] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); if (user != nullptr) { for (auto it = user->provider_data().begin(); it != user->provider_data().end(); ++it) { @@ -338,7 +339,7 @@ void VariousUserManagementChecks(firebase::auth::Auth* auth) { } { // [START auth_profile_edit_check] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); if (user != nullptr) { firebase::auth::User::UserProfile profile; profile.display_name = "Jane Q. User"; @@ -356,7 +357,7 @@ void VariousUserManagementChecks(firebase::auth::Auth* auth) { } { // [START auth_set_email_check] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); if (user != nullptr) { user->UpdateEmail("user@example.com") .OnCompletion( @@ -373,7 +374,7 @@ void VariousUserManagementChecks(firebase::auth::Auth* auth) { } { // [START auth_user_verify_email_check] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); if (user != nullptr) { user->SendEmailVerification().OnCompletion( [](const firebase::Future& completed_future, void* user_data) { @@ -388,7 +389,7 @@ void VariousUserManagementChecks(firebase::auth::Auth* auth) { } { // [START auth_user_update_password_check] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); std::string newPassword = "SOME-SECURE-PASSWORD"; if (user != nullptr) { @@ -427,7 +428,7 @@ void VariousUserManagementChecks(firebase::auth::Auth* auth) { } { // [START auth_user_delete_check] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); if (user != nullptr) { user->Delete().OnCompletion( [](const firebase::Future& completed_future, void* user_data) { @@ -445,7 +446,7 @@ void VariousUserManagementChecks(firebase::auth::Auth* auth) { } { // [START auth_user_reauthenticate_check] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); // Get auth credentials from the user for re-authentication. The example // below shows email and password credentials but there are multiple @@ -530,18 +531,18 @@ void LinkCredential(const firebase::auth::Credential& credential, firebase::auth::Auth* auth) { // [START user_link] // Link the new credential to the currently active user. - firebase::auth::User* current_user = auth->current_user(); + firebase::auth::User* current_user = auth->current_user_DEPRECATED(); firebase::Future result = - current_user->LinkWithCredential(credential); + current_user->LinkWithCredential_DEPRECATED(credential); // [END user_link] } void UnLinkCredential(const char* providerId, firebase::auth::Auth* auth) { // [START user_unlink] // Unlink the sign-in provider from the currently active user. - firebase::auth::User* current_user = auth->current_user(); + firebase::auth::User* current_user = auth->current_user_DEPRECATED(); firebase::Future result = - current_user->Unlink(providerId); + current_user->Unlink_DEPRECATED(providerId); // [END user_unlink] } @@ -549,7 +550,8 @@ void LinkCredentialFailAppleSignIn(const firebase::auth::Credential& credential, firebase::auth::Auth* auth) { // [START link_credential_apple_signin] firebase::Future link_result = - auth->current_user()->LinkAndRetrieveDataWithCredential(credential); + auth->current_user_DEPRECATED()->LinkAndRetrieveDataWithCredential( + credential); // To keep example simple, wait on the current thread until call completes. while (link_result.status() == firebase::kFutureStatusPending) { @@ -563,8 +565,9 @@ void LinkCredentialFailAppleSignIn(const firebase::auth::Credential& credential, firebase::auth::kAuthErrorCredentialAlreadyInUse && link_result.result()->info.updated_credential.is_valid()) { // Sign In with the new credential - firebase::Future result = auth->SignInWithCredential( - link_result.result()->info.updated_credential); + firebase::Future result = + auth->SignInWithCredential_DEPRECATED( + link_result.result()->info.updated_credential); } else { // Another link error occurred. } @@ -575,7 +578,7 @@ void MergeCredentials(const firebase::auth::Credential& credential, firebase::auth::Auth* auth) { // [START user_merge] // Gather data for the currently signed in User. - firebase::auth::User* current_user = auth->current_user(); + firebase::auth::User* current_user = auth->current_user_DEPRECATED(); std::string current_email = current_user->email(); std::string current_provider_id = current_user->provider_id(); std::string current_display_name = current_user->display_name(); @@ -583,7 +586,7 @@ void MergeCredentials(const firebase::auth::Credential& credential, // Sign in with the new credentials. firebase::Future result = - auth->SignInWithCredential(credential); + auth->SignInWithCredential_DEPRECATED(credential); // To keep example simple, wait on the current thread until call completes. while (result.status() == firebase::kFutureStatusPending) { @@ -608,7 +611,7 @@ void MergeCredentials(const firebase::auth::Credential& credential, void NextSteps(firebase::auth::Auth* auth) { // [START next_steps] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); if (user != nullptr) { std::string name = user->display_name(); std::string email = user->email(); @@ -623,7 +626,7 @@ void NextSteps(firebase::auth::Auth* auth) { void SendIdTokenToBackend(firebase::auth::Auth* auth) { // [START send_id_token_to_backend] - firebase::auth::User* user = auth->current_user(); + firebase::auth::User* user = auth->current_user_DEPRECATED(); if (user != nullptr) { firebase::Future idToken = user->GetToken(true); @@ -640,7 +643,7 @@ firebase::auth::Auth* AuthOverview(firebase::App* app) { // Request anonymous sign-in and wait until asynchronous call completes. firebase::Future sign_in_future = - auth->SignInAnonymously(); + auth->SignInAnonymously_DEPRECATED(); while (sign_in_future.status() == firebase::kFutureStatusPending) { Wait(100); printf("Signing in...\n"); @@ -709,13 +712,13 @@ const char* DisplayIdentityProviders(const char* email, bool SignIn(firebase::auth::Auth* auth) { // Grab the result of the latest sign-in attempt. firebase::Future future = - auth->SignInAnonymouslyLastResult(); + auth->SignInAnonymouslyLastResult_DEPRECATED(); // If we're in a state where we can try to sign in, do so. if (future.status() == firebase::kFutureStatusInvalid || (future.status() == firebase::kFutureStatusComplete && future.error() != firebase::auth::kAuthErrorNone)) { - auth->SignInAnonymously(); + auth->SignInAnonymously_DEPRECATED(); } // We're signed in if the most recent result was successful. diff --git a/auth/src/android/auth_android.cc b/auth/src/android/auth_android.cc index 3f71e4a60e..2309152475 100644 --- a/auth/src/android/auth_android.cc +++ b/auth/src/android/auth_android.cc @@ -114,8 +114,6 @@ METHOD_LOOKUP_DEFINITION( JNI_ID_TOKEN_LISTENER_CALLBACK_METHODS) static int g_initialized_count = 0; -static const char* kErrorEmptyEmailPassword = - "Empty email or password are not allowed."; JNIEXPORT void JNICALL JniAuthStateListener_nativeOnAuthStateChanged( JNIEnv* env, jobject clazz, jlong callback_data); @@ -162,27 +160,20 @@ void ReleaseAuthClasses(JNIEnv* env) { jni_id_token_listener::ReleaseClass(env); } -void UpdateCurrentUser(AuthData* auth_data) { - JNIEnv* env = Env(auth_data); - +// Grab the user value from the Android SDK and remember it locally. +void UpdateCurrentUser(JNIEnv* env, AuthData* auth_data) { MutexLock lock(auth_data->future_impl.mutex()); - - const void* original_user_impl = auth_data->user_impl; - // Update our pointer to the Android FirebaseUser that we're wrapping. jobject j_user = env->CallObjectMethod( AuthImpl(auth_data), auth::GetMethodId(auth::kGetCurrentUser)); if (firebase::util::CheckAndClearJniExceptions(env)) { j_user = nullptr; } - SetImplFromLocalRef(env, j_user, &auth_data->user_impl); - - // Log debug message when user sign-in status has changed. - if (original_user_impl != auth_data->user_impl) { - LogDebug("CurrentUser changed from %X to %X", - reinterpret_cast(original_user_impl), - reinterpret_cast(auth_data->user_impl)); - } + SetImplFromLocalRef(env, j_user, + &auth_data->deprecated_fields.android_user_impl); + SetUserImpl( + env, auth_data, + static_cast(auth_data->deprecated_fields.android_user_impl)); } // Release cached Java classes. @@ -237,6 +228,15 @@ void* CreatePlatformAuth(App* app) { void Auth::InitPlatformAuth(AuthData* auth_data) { JNIEnv* env = Env(auth_data); + // Create persistent User data to continue to facilitate deprecated aysnc + // methods which return a pointer to a User. Remove this structure when those + // deprecated methods are removed. + auth_data->deprecated_fields.android_user_impl = (jobject) nullptr; + auth_data->deprecated_fields.user_internal_deprecated = + new UserInternal(auth_data, (jobject) nullptr); + auth_data->deprecated_fields.user_deprecated = new User( + auth_data, auth_data->deprecated_fields.user_internal_deprecated); + // Create the JniAuthStateListener class to redirect the state-change // from Java to C++. jobject j_listener = @@ -268,10 +268,12 @@ void Auth::InitPlatformAuth(AuthData* auth_data) { // Ensure our User is in-line with underlying API's user. // It's possible for a user to already be logged-in on start-up. - UpdateCurrentUser(auth_data); + UpdateCurrentUser(env, auth_data); } void Auth::DestroyPlatformAuth(AuthData* auth_data) { + // Note: auth_data->auth_mutex is already locked by Auth::DeleteInternal(). + // Remove references from listener blocks. JNIEnv* env = Env(auth_data); util::CancelCallbacks(env, auth_data->future_api_id.c_str()); @@ -294,11 +296,23 @@ void Auth::DestroyPlatformAuth(AuthData* auth_data) { static_cast(auth_data->id_token_listener_impl)); assert(env->ExceptionCheck() == false); - // Deleting our global references should trigger the FirebaseAuth class and - // FirebaseUser Java objects to be deleted. + // Clear the retained User object, which is used to support those deprecated + // Auth methods which return User pointer. + SetImplFromLocalRef(env, nullptr, + &auth_data->deprecated_fields.android_user_impl); + SetUserImpl(auth_data, nullptr); + + auth_data->deprecated_fields.user_internal_deprecated = nullptr; + + // This also deletes auth_data->deprecated_fields.user_internal_deprecated + // since User has ownership of the UserInternal allocation. + delete auth_data->deprecated_fields.user_deprecated; + auth_data->deprecated_fields.user_deprecated = nullptr; + + // Deleting our global references should trigger the FirebaseAuth class to be + // deleted. SetImplFromLocalRef(env, nullptr, &auth_data->listener_impl); SetImplFromLocalRef(env, nullptr, &auth_data->id_token_listener_impl); - SetImplFromLocalRef(env, nullptr, &auth_data->user_impl); SetImplFromLocalRef(env, nullptr, &auth_data->auth_impl); FIREBASE_ASSERT(g_initialized_count); @@ -324,7 +338,7 @@ JNIEXPORT void JNICALL JniAuthStateListener_nativeOnAuthStateChanged( JNIEnv* env, jobject clazz, jlong callback_data) { AuthData* auth_data = reinterpret_cast(callback_data); // Update our pointer to the Android FirebaseUser that we're wrapping. - UpdateCurrentUser(auth_data); + UpdateCurrentUser(env, auth_data); NotifyAuthStateListeners(auth_data); } @@ -333,7 +347,7 @@ JNIEXPORT void JNICALL JniIdTokenListener_nativeOnIdTokenChanged( AuthData* auth_data = reinterpret_cast(callback_data); auth_data->SetExpectIdTokenListenerCallback(false); // Update our pointer to the Android FirebaseUser that we're wrapping. - UpdateCurrentUser(auth_data); + UpdateCurrentUser(env, auth_data); NotifyIdTokenListeners(auth_data); } @@ -375,6 +389,8 @@ static void ReadProviderResult( Future Auth::FetchProvidersForEmail( const char* email) { + FIREBASE_ASSERT_RETURN(Future(), auth_data_); + MutexLock(auth_data_->auth_mutex); ReferenceCountedFutureImpl& futures = auth_data_->future_impl; const auto handle = futures.SafeAlloc( kAuthFn_FetchProvidersForEmail); @@ -387,34 +403,45 @@ Future Auth::FetchProvidersForEmail( env->DeleteLocalRef(j_email); if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, ReadProviderResult); + RegisterCallback(auth_data_, pending_result, handle, + auth_data_->future_api_id, &futures, ReadProviderResult); env->DeleteLocalRef(pending_result); } return MakeFuture(&futures, handle); } -Future Auth::SignInWithCustomToken(const char* token) { +Future Auth::SignInWithCustomToken_DEPRECATED(const char* token) { + FIREBASE_ASSERT_RETURN(Future(), auth_data_); + MutexLock(auth_data_->auth_mutex); ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kAuthFn_SignInWithCustomToken); - JNIEnv* env = Env(auth_data_); + SafeFutureHandle future_handle = + auth_data_->future_impl.SafeAlloc( + kAuthFn_SignInWithCustomToken_DEPRECATED); + Future future = MakeFuture(&auth_data_->future_impl, future_handle); + JNIEnv* env = Env(auth_data_); jstring j_token = env->NewStringUTF(token); jobject pending_result = env->CallObjectMethod( AuthImpl(auth_data_), auth::GetMethodId(auth::kSignInWithCustomToken), j_token); env->DeleteLocalRef(j_token); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, + if (!CheckAndCompleteFutureOnError(env, &futures, future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, + auth_data_->future_api_id, &auth_data_->future_impl, ReadUserFromSignInResult); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; } -Future Auth::SignInWithCredential(const Credential& credential) { +Future Auth::SignInWithCredential_DEPRECATED( + const Credential& credential) { + FIREBASE_ASSERT_RETURN(Future(), auth_data_); + MutexLock(auth_data_->auth_mutex); ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kAuthFn_SignInWithCredential); + const auto handle = + futures.SafeAlloc(kAuthFn_SignInWithCredential_DEPRECATED); JNIEnv* env = Env(auth_data_); // If the credential itself is in an error state, don't try signing in. @@ -427,7 +454,8 @@ Future Auth::SignInWithCredential(const Credential& credential) { CredentialFromImpl(credential.impl_)); if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, + RegisterCallback(auth_data_, pending_result, handle, + auth_data_->future_api_id, &futures, ReadUserFromSignInResult); env->DeleteLocalRef(pending_result); } @@ -435,63 +463,74 @@ Future Auth::SignInWithCredential(const Credential& credential) { return MakeFuture(&futures, handle); } -Future Auth::SignInAndRetrieveDataWithCredential( +Future Auth::SignInAndRetrieveDataWithCredential_DEPRECATED( const Credential& credential) { - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc( - kAuthFn_SignInAndRetrieveDataWithCredential); + FIREBASE_ASSERT_RETURN(Future(), auth_data_); + MutexLock(auth_data_->auth_mutex); + const auto future_handle = auth_data_->future_impl.SafeAlloc( + kAuthFn_SignInAndRetrieveDataWithCredential_DEPRECATED); JNIEnv* env = Env(auth_data_); // If the credential itself is in an error state, don't try signing in. if (credential.error_code_ != kAuthErrorNone) { - futures.Complete(handle, credential.error_code_, - credential.error_message_.c_str()); + auth_data_->future_impl.Complete(future_handle, credential.error_code_, + credential.error_message_.c_str()); } else { jobject pending_result = env->CallObjectMethod( AuthImpl(auth_data_), auth::GetMethodId(auth::kSignInWithCredential), CredentialFromImpl(credential.impl_)); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, ReadSignInResult); + if (!CheckAndCompleteFutureOnError(env, &auth_data_->future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, + auth_data_->future_api_id, &auth_data_->future_impl, + ReadSignInResult); env->DeleteLocalRef(pending_result); } } - return MakeFuture(&futures, handle); + return MakeFuture(&auth_data_->future_impl, future_handle); } -Future Auth::SignInWithProvider(FederatedAuthProvider* provider) { +Future Auth::SignInWithProvider_DEPRECATED( + FederatedAuthProvider* provider) { + FIREBASE_ASSERT_RETURN(Future(), auth_data_); FIREBASE_ASSERT_RETURN(Future(), provider); + MutexLock(auth_data_->auth_mutex); return provider->SignIn(auth_data_); } -Future Auth::SignInAnonymously() { - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kAuthFn_SignInAnonymously); +Future Auth::SignInAnonymously_DEPRECATED() { + const auto handle = auth_data_->future_impl.SafeAlloc( + kAuthFn_SignInAnonymously_DEPRECATED); + FIREBASE_ASSERT_RETURN(Future(), auth_data_); + MutexLock(auth_data_->auth_mutex); JNIEnv* env = Env(auth_data_); - jobject pending_result = env->CallObjectMethod( AuthImpl(auth_data_), auth::GetMethodId(auth::kSignInAnonymously)); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, + if (!CheckAndCompleteFutureOnError(env, &auth_data_->future_impl, handle)) { + RegisterCallback(auth_data_, pending_result, handle, + auth_data_->future_api_id, &auth_data_->future_impl, ReadUserFromSignInResult); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return MakeFuture(&auth_data_->future_impl, handle); } -Future Auth::SignInWithEmailAndPassword(const char* email, - const char* password) { +Future Auth::SignInWithEmailAndPassword_DEPRECATED( + const char* email, const char* password) { + FIREBASE_ASSERT_RETURN(Future(), auth_data_); + MutexLock(auth_data_->auth_mutex); ReferenceCountedFutureImpl& futures = auth_data_->future_impl; const auto handle = - futures.SafeAlloc(kAuthFn_SignInWithEmailAndPassword); + futures.SafeAlloc(kAuthFn_SignInWithEmailAndPassword_DEPRECATED); if (!email || strlen(email) == 0 || !password || strlen(password) == 0) { futures.Complete(handle, (!email || strlen(email) == 0) ? kAuthErrorMissingEmail : kAuthErrorMissingPassword, - kErrorEmptyEmailPassword); + kErrorEmptyEmailPasswordErrorMessage); return MakeFuture(&futures, handle); } JNIEnv* env = Env(auth_data_); @@ -506,7 +545,8 @@ Future Auth::SignInWithEmailAndPassword(const char* email, env->DeleteLocalRef(j_password); if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, + RegisterCallback(auth_data_, pending_result, handle, + auth_data_->future_api_id, &futures, ReadUserFromSignInResult); env->DeleteLocalRef(pending_result); } @@ -514,18 +554,20 @@ Future Auth::SignInWithEmailAndPassword(const char* email, return MakeFuture(&futures, handle); } -Future Auth::CreateUserWithEmailAndPassword(const char* email, - const char* password) { - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = - futures.SafeAlloc(kAuthFn_CreateUserWithEmailAndPassword); +Future Auth::CreateUserWithEmailAndPassword_DEPRECATED( + const char* email, const char* password) { + FIREBASE_ASSERT_RETURN(Future(), auth_data_); + MutexLock(auth_data_->auth_mutex); + const auto future_handle = auth_data_->future_impl.SafeAlloc( + kAuthFn_CreateUserWithEmailAndPassword_DEPRECATED); if (!email || strlen(email) == 0 || !password || strlen(password) == 0) { - futures.Complete(handle, - (!email || strlen(email) == 0) ? kAuthErrorMissingEmail - : kAuthErrorMissingPassword, - kErrorEmptyEmailPassword); - return MakeFuture(&futures, handle); + auth_data_->future_impl.Complete(future_handle, + (!email || strlen(email) == 0) + ? kAuthErrorMissingEmail + : kAuthErrorMissingPassword, + kErrorEmptyEmailPasswordErrorMessage); + return MakeFuture(&auth_data_->future_impl, future_handle); } JNIEnv* env = Env(auth_data_); @@ -538,34 +580,33 @@ Future Auth::CreateUserWithEmailAndPassword(const char* email, env->DeleteLocalRef(j_email); env->DeleteLocalRef(j_password); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, + if (!CheckAndCompleteFutureOnError(env, &auth_data_->future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, + auth_data_->future_api_id, &auth_data_->future_impl, ReadUserFromSignInResult); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return MakeFuture(&auth_data_->future_impl, future_handle); } // It's safe to return a direct pointer to `current_user` because that class // holds nothing but a pointer to AuthData, which never changes. // All User functions that require synchronization go through AuthData's mutex. -User* Auth::current_user() { - if (!auth_data_) return nullptr; - MutexLock lock(auth_data_->future_impl.mutex()); - - // auth_data_->current_user should be available after Auth is created because - // persistent is loaded during the constructor of Android FirebaseAuth. - // This may change to make FirebaseAuth.getCurrentUser() to block and wait for - // persistent loading. However, it is safe to access auth_data_->current_user - // here since FirebaseAuth.getCurrentUser() (Android) is called in - // InitPlatformAuth(). - User* user = - auth_data_->user_impl == nullptr ? nullptr : &auth_data_->current_user; - return user; +User* Auth::current_user_DEPRECATED() { + FIREBASE_ASSERT_RETURN(nullptr, auth_data_); + MutexLock lock(auth_data_->auth_mutex); + if (auth_data_->deprecated_fields.user_deprecated == nullptr || + !auth_data_->deprecated_fields.user_deprecated->is_valid()) { + return nullptr; + } else { + return auth_data_->deprecated_fields.user_deprecated; + } } std::string Auth::language_code() const { - if (!auth_data_) return std::string(); + FIREBASE_ASSERT_RETURN(std::string(), auth_data_); + MutexLock(auth_data_->auth_mutex); JNIEnv* env = Env(auth_data_); jobject j_pending_result = env->CallObjectMethod( AuthImpl(auth_data_), auth::GetMethodId(auth::kGetLanguageCode)); @@ -577,7 +618,8 @@ std::string Auth::language_code() const { } void Auth::set_language_code(const char* language_code) { - if (!auth_data_) return; + FIREBASE_ASSERT_RETURN_VOID(auth_data_); + MutexLock(auth_data_->auth_mutex); JNIEnv* env = Env(auth_data_); jstring j_language_code = nullptr; if (language_code != nullptr) { @@ -593,7 +635,7 @@ void Auth::set_language_code(const char* language_code) { } void Auth::UseAppLanguage() { - if (!auth_data_) return; + FIREBASE_ASSERT_RETURN_VOID(auth_data_); JNIEnv* env = Env(auth_data_); env->CallVoidMethod(AuthImpl(auth_data_), auth::GetMethodId(auth::kUseAppLanguage)); @@ -601,16 +643,22 @@ void Auth::UseAppLanguage() { } void Auth::SignOut() { + FIREBASE_ASSERT_RETURN_VOID(auth_data_); + MutexLock(auth_data_->auth_mutex); JNIEnv* env = Env(auth_data_); env->CallVoidMethod(AuthImpl(auth_data_), auth::GetMethodId(auth::kSignOut)); firebase::util::CheckAndClearJniExceptions(env); // Release our current user implementation in Java. MutexLock lock(auth_data_->future_impl.mutex()); - SetImplFromLocalRef(env, nullptr, &auth_data_->user_impl); + SetImplFromLocalRef(env, nullptr, + &auth_data_->deprecated_fields.android_user_impl); + SetUserImpl(auth_data_, nullptr); } Future Auth::SendPasswordResetEmail(const char* email) { + FIREBASE_ASSERT_RETURN(Future(), auth_data_); + MutexLock(auth_data_->auth_mutex); ReferenceCountedFutureImpl& futures = auth_data_->future_impl; const auto handle = futures.SafeAlloc(kAuthFn_SendPasswordResetEmail); @@ -626,7 +674,8 @@ Future Auth::SendPasswordResetEmail(const char* email) { env->DeleteLocalRef(j_email); if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, nullptr); + RegisterCallback(auth_data_, pending_result, handle, + auth_data_->future_api_id, &futures, nullptr); env->DeleteLocalRef(pending_result); } return MakeFuture(&futures, handle); diff --git a/auth/src/android/common_android.cc b/auth/src/android/common_android.cc index b939c76c6b..98c43d9497 100644 --- a/auth/src/android/common_android.cc +++ b/auth/src/android/common_android.cc @@ -483,9 +483,13 @@ void ReadSignInResult(jobject result, FutureCallbackData* d, util::CheckAndClearJniExceptions(env); // Update our pointer to the Android FirebaseUser that we're wrapping. - // Note: Cannot call UpdateCurrentUser(d->auth_data) because the Java + // Note: Cannot call UpdateCurrentUser(env, d->auth_data) because the Java // Auth class has not been updated at this point. - SetImplFromLocalRef(env, j_user, &d->auth_data->user_impl); + SetImplFromLocalRef(env, j_user, + &d->auth_data->deprecated_fields.android_user_impl); + SetUserImpl(d->auth_data, + static_cast( + d->auth_data->deprecated_fields.android_user_impl)); // Grab the additional user info too. // Additional user info is not guaranteed to exist, so could be nullptr. @@ -498,7 +502,7 @@ void ReadSignInResult(jobject result, FutureCallbackData* d, SignInResult* sign_in_result = static_cast(void_data); // Return a pointer to the user and gather the additional data. - sign_in_result->user = d->auth_data->auth->current_user(); + sign_in_result->user = d->auth_data->auth->current_user_DEPRECATED(); ReadAdditionalUserInfo(env, j_additional_user_info, &sign_in_result->info); env->DeleteLocalRef(j_additional_user_info); } @@ -519,14 +523,18 @@ void ReadUserFromSignInResult(jobject result, FutureCallbackData* d, util::CheckAndClearJniExceptions(env); // Update our pointer to the Android FirebaseUser that we're wrapping. - // Note: Cannot call UpdateCurrentUser(d->auth_data) because the Java + // Note: Cannot call UpdateCurrentUser(env, d->auth_data) because the Java // Auth class has not been updated at this point. - SetImplFromLocalRef(env, j_user, &d->auth_data->user_impl); + SetImplFromLocalRef(env, j_user, + &d->auth_data->deprecated_fields.android_user_impl); + SetUserImpl(d->auth_data, + static_cast( + d->auth_data->deprecated_fields.android_user_impl)); } // Return a pointer to the current user, if the current user is valid. User** user_ptr = static_cast(void_data); - *user_ptr = d->auth_data->auth->current_user(); + *user_ptr = d->auth_data->auth->current_user_DEPRECATED(); } } // namespace auth diff --git a/auth/src/android/common_android.h b/auth/src/android/common_android.h index 6cbe4ac9c0..aed4e22b55 100644 --- a/auth/src/android/common_android.h +++ b/auth/src/android/common_android.h @@ -50,20 +50,136 @@ template struct FutureCallbackData { // During the callback, read `result` data from Java into the returned // C++ data in `d->future_data->Data()`. - typedef void ReadFutureResultFn(jobject result, FutureCallbackData* d, + typedef void ReadFutureResultFn(jobject result, + FutureCallbackData* future_callback_Data, bool success, void* void_data); - FutureCallbackData(const SafeFutureHandle& handle, AuthData* auth_data, + FutureCallbackData(AuthData* auth_data, const SafeFutureHandle& handle, + ReferenceCountedFutureImpl* future_impl, ReadFutureResultFn* future_data_read_fn) - : handle(handle), - auth_data(auth_data), + : auth_data(auth_data), + handle(handle), + future_impl(future_impl), future_data_read_fn(future_data_read_fn) {} - - SafeFutureHandle handle; AuthData* auth_data; + SafeFutureHandle handle; + ReferenceCountedFutureImpl* future_impl; ReadFutureResultFn* future_data_read_fn; }; +// Contains the interface between the public API and the underlying +// Android Java SDK FirebaseUser implemention. +class UserInternal { + public: + // Constructor + explicit UserInternal(AuthData* auth_data, jobject android_user); + + // Copy constructor. + UserInternal(const UserInternal& user_internal); + + ~UserInternal(); + + // @deprecated + // + // Provides a mechanism for the deprecated auth-contained user object to + // update its underlying Android Java SDK FirebaseUser object. Assumes that + // a global ref has already been set on android_user. Releases the global + // ref on any previously held user. + void set_native_user_object_deprecated(jobject android_user); + + bool is_valid() const; + + Future GetToken(bool force_refresh); + Future GetTokenLastResult() const; + + Future UpdateEmail(const char* email); + Future UpdateEmailLastResult() const; + + std::vector provider_data() const; + const std::vector& provider_data_DEPRECATED(); + + Future UpdatePassword(const char* password); + Future UpdatePasswordLastResult() const; + + Future UpdateUserProfile(const User::UserProfile& profile); + Future UpdateUserProfileLastResult() const; + + Future SendEmailVerification(); + Future SendEmailVerificationLastResult() const; + + Future LinkWithCredential_DEPRECATED(const Credential& credential); + Future LinkWithCredentialLastResult_DEPRECATED() const; + + Future LinkAndRetrieveDataWithCredential_DEPRECATED( + const Credential& credential); + Future LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED() + const; + + Future LinkWithProvider_DEPRECATED( + FederatedAuthProvider* provider); + Future LinkWithProviderLastResult_DEPRECATED() const; + + Future Unlink_DEPRECATED(const char* provider); + Future UnlinkLastResult_DEPRECATED() const; + + Future UpdatePhoneNumberCredential_DEPRECATED( + const Credential& credential); + Future UpdatePhoneNumberCredentialLastResult_DEPRECATED() const; + + Future Reload(); + Future ReloadLastResult() const; + + Future Reauthenticate(const Credential& credential); + Future ReauthenticateLastResult() const; + + Future ReauthenticateAndRetrieveData_DEPRECATED( + const Credential& credential); + Future ReauthenticateAndRetrieveDataLastResult_DEPRECATED() + const; + + Future ReauthenticateWithProvider_DEPRECATED( + FederatedAuthProvider* provider); + Future ReauthenticateWithProviderLastResult_DEPRECATED() const; + + Future Delete(); + Future DeleteLastResult() const; + + UserMetadata metadata() const; + bool is_email_verified() const; + bool is_anonymous() const; + std::string uid() const; + std::string email() const; + std::string display_name() const; + std::string phone_number() const; + std::string photo_url() const; + std::string provider_id() const; + + private: + friend class firebase::auth::FederatedOAuthProvider; + friend class firebase::auth::User; + + void clear_user_infos(); + + // Pointer to the originating auth context. + AuthData* auth_data_; + + // Android Java SDK Implementation of a FirebaseUser object. + jobject user_; + + // Future data used to synchronize asynchronous calls. + FutureData future_data_; + + // Used to support older method invocation of provider_data_DEPRECATED(). + std::vector user_infos_; + + // Guard against changes to the user_ object. + Mutex user_mutex_; + + // Used to identify on-going futures in case we need to cancel them + // upon UserInternal destruction. + std::string future_api_id_; +}; + // The `ReadFutureResultFn` for `SignIn` APIs. // Reads the `AuthResult` in `result` and initialize the `User*` in `void_data`. void ReadSignInResult(jobject result, FutureCallbackData* d, @@ -112,18 +228,27 @@ inline JNIEnv* Env(AuthData* auth_data) { return auth_data->app->GetJNIEnv(); } // Delete the existing impl pointer global reference, if it already exists. void SetImplFromLocalRef(JNIEnv* env, jobject j_local, void** impl); +// Synchronize the current user. +void UpdateCurrentUser(JNIEnv* env, AuthData* auth_data); + +/// @deprecated +/// +/// Replace the platform-dependent FirebaseUser Android SDK object. +/// Note: this function is only used to support DEPRECATED methods which return +/// User*. This functionality should be removed when those deprecated methods +/// are removed. +inline void SetUserImpl(AuthData* _Nonnull auth_data, jobject j_user) { + assert(auth_data->deprecated_fields.user_internal_deprecated); + auth_data->deprecated_fields.user_internal_deprecated + ->set_native_user_object_deprecated(j_user); +} + // Return the Java FirebaseAuth class from our platform-independent // representation. inline jobject AuthImpl(AuthData* auth_data) { return static_cast(auth_data->auth_impl); } -// Return the Java FirebaseUser class from our platform-independent -// representation. -inline jobject UserImpl(AuthData* auth_data) { - return static_cast(auth_data->user_impl); -} - // Return a platform-independent representation of Java's FirebaseUser class. inline void* ImplFromUser(jobject user) { return static_cast(user); } @@ -177,24 +302,25 @@ AuthError MapFutureCallbackResultToAuthError(JNIEnv* env, jobject result, template void FutureCallback(JNIEnv* env, jobject result, util::FutureResult result_code, const char* status_message, void* callback_data) { - FutureCallbackData* data = + FutureCallbackData* future_callback_data = static_cast*>(callback_data); bool success = false; const AuthError error = MapFutureCallbackResultToAuthError(env, result, result_code, &success); // Finish off the asynchronous call so that the caller can read it. - data->auth_data->future_impl.Complete( - data->handle, error, status_message, - [result, success, data](void* user_data) { - if (data->future_data_read_fn != nullptr) { - data->future_data_read_fn(result, data, success, user_data); + future_callback_data->future_impl->Complete( + future_callback_data->handle, error, status_message, + [result, success, future_callback_data](void* user_data) { + if (future_callback_data->future_data_read_fn != nullptr) { + future_callback_data->future_data_read_fn( + result, future_callback_data, success, user_data); } }); // Remove the callback structure that was allocated when the callback was // created in SetupFuture(). - delete data; - data = nullptr; + delete future_callback_data; + future_callback_data = nullptr; } // The function called by the Java thread when a result completes. @@ -203,7 +329,7 @@ void FederatedAuthProviderFutureCallback(JNIEnv* env, jobject result, util::FutureResult result_code, const char* status_message, void* callback_data) { - FutureCallbackData* data = + FutureCallbackData* future_callback_data = static_cast*>(callback_data); bool success = false; AuthError error = @@ -215,18 +341,19 @@ void FederatedAuthProviderFutureCallback(JNIEnv* env, jobject result, error = kAuthErrorInvalidProviderId; } // Finish off the asynchronous call so that the caller can read it. - data->auth_data->future_impl.Complete( - data->handle, error, status_message, - [result, success, data](void* user_data) { - if (data->future_data_read_fn != nullptr) { - data->future_data_read_fn(result, data, success, user_data); + future_callback_data->future_impl->Complete( + future_callback_data->handle, error, status_message, + [result, success, future_callback_data](void* user_data) { + if (future_callback_data->future_data_read_fn != nullptr) { + future_callback_data->future_data_read_fn( + result, future_callback_data, success, user_data); } }); // Remove the callback structure that was allocated when the callback was // created in SetupFuture(). - delete data; - data = nullptr; + delete future_callback_data; + future_callback_data = nullptr; } // Ensure `FutureCallback` gets called when `pending_result` completes. @@ -234,13 +361,14 @@ void FederatedAuthProviderFutureCallback(JNIEnv* env, jobject result, // data from Java, and then complete the Future for `handle`. template void RegisterCallback( - jobject pending_result, SafeFutureHandle handle, AuthData* auth_data, + AuthData* auth_data, jobject pending_result, SafeFutureHandle handle, + const std::string& future_api_id, ReferenceCountedFutureImpl* future_impl, typename FutureCallbackData::ReadFutureResultFn read_result_fn) { // The FutureCallbackData structure is deleted in FutureCallback(). util::RegisterCallbackOnTask( Env(auth_data), pending_result, FutureCallback, - new FutureCallbackData(handle, auth_data, read_result_fn), - auth_data->future_api_id.c_str()); + new FutureCallbackData(auth_data, handle, future_impl, read_result_fn), + future_api_id.c_str()); } // Akin to RegisterCallback above, but has a special callback handler @@ -250,14 +378,15 @@ void RegisterCallback( // with the existing API behavior for other sign in events. template void RegisterFederatedAuthProviderCallback( - jobject pending_result, SafeFutureHandle handle, AuthData* auth_data, + AuthData* auth_data, jobject pending_result, SafeFutureHandle handle, + const std::string& future_api_id, ReferenceCountedFutureImpl* future_impl, typename FutureCallbackData::ReadFutureResultFn read_result_fn) { // The FutureCallbackData structure is deleted in // FederatedAuthProviderFutureCallback(). util::RegisterCallbackOnTask( Env(auth_data), pending_result, FederatedAuthProviderFutureCallback, - new FutureCallbackData(handle, auth_data, read_result_fn), - auth_data->future_api_id.c_str()); + new FutureCallbackData(auth_data, handle, future_impl, read_result_fn), + future_api_id.c_str()); } // Checks if there was an error, and if so, completes the given future with the diff --git a/auth/src/android/credential_android.cc b/auth/src/android/credential_android.cc index 192934298f..1c06f266b7 100644 --- a/auth/src/android/credential_android.cc +++ b/auth/src/android/credential_android.cc @@ -652,24 +652,24 @@ Future GameCenterAuthProvider::GetCredential() { // Game Center is not available on Android bool is_gamecenter_available_on_android = false; - auto future_api = GetCredentialFutureImpl(); - const auto handle = - future_api->SafeAlloc(kCredentialFn_GameCenterGetCredential); + ReferenceCountedFutureImpl* future_impl = GetCredentialFutureImpl(); + const auto future_handle = + future_impl->SafeAlloc(kCredentialFn_GameCenterGetCredential); - future_api->Complete(handle, kAuthErrorInvalidCredential, - "GameCenter is not supported on Android."); + future_impl->Complete(future_handle, kAuthErrorInvalidCredential, + "GameCenter is not supported on Android."); - FIREBASE_ASSERT_RETURN(MakeFuture(future_api, handle), + FIREBASE_ASSERT_RETURN(MakeFuture(future_impl, future_handle), is_gamecenter_available_on_android); - return MakeFuture(future_api, handle); + return MakeFuture(future_impl, future_handle); } // static Future GameCenterAuthProvider::GetCredentialLastResult() { - auto future_api = GetCredentialFutureImpl(); + ReferenceCountedFutureImpl* future_impl = GetCredentialFutureImpl(); auto last_result = - future_api->LastResult(kCredentialFn_GameCenterGetCredential); + future_impl->LastResult(kCredentialFn_GameCenterGetCredential); return static_cast&>(last_result); } @@ -1013,75 +1013,80 @@ Future FederatedOAuthProvider::SignIn(AuthData* auth_data) { assert(auth_data); JNIEnv* env = Env(auth_data); - ReferenceCountedFutureImpl& futures = auth_data->future_impl; - const auto handle = futures.SafeAlloc( - kAuthFn_SignInWithProvider, SignInResult()); + ReferenceCountedFutureImpl& future_impl = auth_data->future_impl; + const auto future_handle = future_impl.SafeAlloc( + kAuthFn_SignInWithProvider_DEPRECATED, SignInResult()); jobject oauthprovider = ConstructOAuthProvider(auth_data, provider_data_); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { + if (!CheckAndCompleteFutureOnError(env, &future_impl, future_handle)) { jobject task = env->CallObjectMethod( AuthImpl(auth_data), auth_idp::GetMethodId(auth_idp::kStartActivityForSignInWithProvider), auth_data->app->activity(), oauthprovider); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterFederatedAuthProviderCallback(task, handle, auth_data, - ReadSignInResult); + + if (!CheckAndCompleteFutureOnError(env, &future_impl, future_handle)) { + RegisterFederatedAuthProviderCallback( + auth_data, task, future_handle, auth_data->future_api_id, + &auth_data->future_impl, ReadSignInResult); } env->DeleteLocalRef(task); } env->DeleteLocalRef(oauthprovider); - return MakeFuture(&futures, handle); + return MakeFuture(&future_impl, future_handle); } -Future FederatedOAuthProvider::Link(AuthData* auth_data) { - assert(auth_data); - JNIEnv* env = Env(auth_data); - ReferenceCountedFutureImpl& futures = auth_data->future_impl; - const auto handle = - futures.SafeAlloc(kUserFn_LinkWithProvider, SignInResult()); +Future FederatedOAuthProvider::Link(AuthData* auth_data, + UserInternal* user_internal) { + ReferenceCountedFutureImpl& future_impl = + user_internal->future_data_.future_impl; + const auto future_handle = future_impl.SafeAlloc( + kUserFn_LinkWithProvider_DEPRECATED, SignInResult()); + JNIEnv* env = Env(auth_data); jobject oauthprovider = ConstructOAuthProvider(auth_data, provider_data_); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { + if (!CheckAndCompleteFutureOnError(env, &future_impl, future_handle)) { jobject task = env->CallObjectMethod( - UserImpl(auth_data), + user_internal->user_, user_idp::GetMethodId(user_idp::kStartActivityForLinkWithProvider), auth_data->app->activity(), oauthprovider); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterFederatedAuthProviderCallback(task, handle, auth_data, - ReadSignInResult); + if (!CheckAndCompleteFutureOnError(env, &future_impl, future_handle)) { + RegisterFederatedAuthProviderCallback( + auth_data, task, future_handle, auth_data->future_api_id, + &auth_data->future_impl, ReadSignInResult); } env->DeleteLocalRef(task); } env->DeleteLocalRef(oauthprovider); - return MakeFuture(&futures, handle); + return MakeFuture(&future_impl, future_handle); } Future FederatedOAuthProvider::Reauthenticate( - AuthData* auth_data) { - assert(auth_data); - JNIEnv* env = Env(auth_data); - ReferenceCountedFutureImpl& futures = auth_data->future_impl; - const auto handle = futures.SafeAlloc( - kUserFn_ReauthenticateWithProvider, SignInResult()); + AuthData* auth_data, UserInternal* user_internal) { + ReferenceCountedFutureImpl& future_impl = + user_internal->future_data_.future_impl; + const auto future_handle = future_impl.SafeAlloc( + kUserFn_ReauthenticateWithProvider_DEPRECATED, SignInResult()); + JNIEnv* env = Env(auth_data); jobject oauthprovider = ConstructOAuthProvider(auth_data, provider_data_); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { + if (!CheckAndCompleteFutureOnError(env, &future_impl, future_handle)) { jobject task = env->CallObjectMethod( - UserImpl(auth_data), + user_internal->user_, user_idp::GetMethodId( user_idp::kStartActivityForReauthenticateWithProvider), auth_data->app->activity(), oauthprovider); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterFederatedAuthProviderCallback(task, handle, auth_data, - ReadSignInResult); + if (!CheckAndCompleteFutureOnError(env, &future_impl, future_handle)) { + RegisterFederatedAuthProviderCallback( + auth_data, task, future_handle, auth_data->future_api_id, + &auth_data->future_impl, ReadSignInResult); } env->DeleteLocalRef(task); } env->DeleteLocalRef(oauthprovider); - return MakeFuture(&futures, handle); + return MakeFuture(&future_impl, future_handle); } } // namespace auth diff --git a/auth/src/android/user_android.cc b/auth/src/android/user_android.cc index a9769f057e..9dfc927f03 100644 --- a/auth/src/android/user_android.cc +++ b/auth/src/android/user_android.cc @@ -128,7 +128,7 @@ METHOD_LOOKUP_DEFINITION( "com/google/firebase/auth/UserProfileChangeRequest$Builder", USER_PROFILE_BUILDER_METHODS) -bool CacheUserMethodIds(JNIEnv* env, jobject activity) { +bool CacheUserMethodIds(JNIEnv *env, jobject activity) { return phonecredential::CacheMethodIds(env, activity) && tokenresult::CacheMethodIds(env, activity) && user::CacheMethodIds(env, activity) && @@ -137,7 +137,7 @@ bool CacheUserMethodIds(JNIEnv* env, jobject activity) { userprofilebuilder::CacheMethodIds(env, activity); } -void ReleaseUserClasses(JNIEnv* env) { +void ReleaseUserClasses(JNIEnv *env) { phonecredential::ReleaseClass(env); tokenresult::ReleaseClass(env); user::ReleaseClass(env); @@ -146,137 +146,407 @@ void ReleaseUserClasses(JNIEnv* env) { userprofilebuilder::ReleaseClass(env); } +/// +/// AndroidWrappedUserInfo Class. +/// Queries data out of Java Android SDK UserInfo objects. +/// enum PropertyType { kPropertyTypeString, kPropertyTypeUri }; -static std::string GetUserProperty(AuthData* auth_data, jobject impl, - userinfo::Method method_id, - PropertyType type = kPropertyTypeString) { - JNIEnv* env = Env(auth_data); - jobject property = - impl ? env->CallObjectMethod(impl, userinfo::GetMethodId(method_id)) - : nullptr; - if (firebase::util::CheckAndClearJniExceptions(env) || !property) { - return std::string(); +class AndroidWrappedUserInfo : public UserInfoInterface { + public: + AndroidWrappedUserInfo(AuthData *auth_data, jobject user_info) + : auth_data_(auth_data), user_info_(user_info) { + // Convert `user_info` to a global reference. + JNIEnv *env = Env(auth_data_); + user_info_ = env->NewGlobalRef(user_info); + env->DeleteLocalRef(user_info); + } + + virtual ~AndroidWrappedUserInfo() { + // Delete global reference. + JNIEnv *env = Env(auth_data_); + env->DeleteGlobalRef(user_info_); + user_info_ = nullptr; + auth_data_ = nullptr; + } + + std::string uid() const override { + return GetUserProperty(userinfo::kGetUid); } - if (type == kPropertyTypeUri) { - return JniUriToString(env, property); + + std::string email() const override { + return GetUserProperty(userinfo::kGetEmail); + } + + std::string display_name() const override { + return GetUserProperty(userinfo::kGetDisplayName); + } + + std::string phone_number() const override { + return GetUserProperty(userinfo::kGetPhoneNumber); + } + + std::string photo_url() const override { + return GetUserProperty(userinfo::kGetPhotoUrl, kPropertyTypeUri); + } + + std::string provider_id() const override { + return GetUserProperty(userinfo::kGetProviderId); + } + + private: + std::string GetUserProperty(userinfo::Method method_id, + PropertyType type = kPropertyTypeString) const { + JNIEnv *env = Env(auth_data_); + jobject property = user_info_ + ? env->CallObjectMethod( + user_info_, userinfo::GetMethodId(method_id)) + : nullptr; + if (firebase::util::CheckAndClearJniExceptions(env) || !property) { + return std::string(); + } + if (type == kPropertyTypeUri) { + return JniUriToString(env, property); + } else { + // type == kPropertyTypeString + return JniStringToString(env, property); + } + } + + /// The AuthData context, required JNI environment data. + AuthData *auth_data_; + + /// Pointer to the main class. + /// Needed for context in implementation of virtuals. + jobject user_info_; +}; + +/// +/// User Class +/// Platform specific implementation of UserInternal. +/// +User::User(AuthData *auth_data, UserInternal *user_internal) { + assert(auth_data); + auth_data_ = auth_data; + if (user_internal == nullptr) { + // Create an invalid user internal. + // This will return is_valid() false, and operations will fail. + user_internal_ = new UserInternal(auth_data_, nullptr); + } else { + user_internal_ = user_internal; + } +} + +User::User(const User &user) { + assert(user.auth_data_); + auth_data_ = user.auth_data_; + if (user.user_internal_ != nullptr) { + user_internal_ = new UserInternal(auth_data_, user.user_internal_->user_); } else { - // type == kPropertyTypeString - return JniStringToString(env, property); + user_internal_ = new UserInternal(auth_data_, nullptr); } } -static std::string GetUID(AuthData* auth_data, jobject impl) { - return GetUserProperty(auth_data, impl, userinfo::kGetUid); +User::~User() { + delete user_internal_; + user_internal_ = nullptr; + auth_data_ = nullptr; +} + +User &User::operator=(const User &user) { + assert(user_internal_); + delete user_internal_; + + auth_data_ = user.auth_data_; + + if (user.user_internal_ != nullptr) { + user_internal_ = new UserInternal(auth_data_, user.user_internal_->user_); + } else { + user_internal_ = new UserInternal(auth_data_, nullptr); + } + + return *this; +} + +bool User::is_valid() const { + assert(user_internal_); + return user_internal_->is_valid(); +} + +Future User::GetToken(bool force_refresh) { + assert(user_internal_); + return user_internal_->GetToken(force_refresh); +} + +std::vector User::provider_data() const { + assert(user_internal_); + return user_internal_->provider_data(); +} + +const std::vector &User::provider_data_DEPRECATED() { + assert(user_internal_); + return user_internal_->provider_data_DEPRECATED(); +} + +Future User::UpdateEmail(const char *email) { + assert(user_internal_); + return user_internal_->UpdateEmail(email); +} + +Future User::UpdateEmailLastResult() const { + assert(user_internal_); + return user_internal_->UpdateEmailLastResult(); +} + +Future User::UpdatePassword(const char *password) { + assert(user_internal_); + return user_internal_->UpdatePassword(password); +} + +Future User::UpdatePasswordLastResult() const { + assert(user_internal_); + return user_internal_->UpdatePasswordLastResult(); +} + +Future User::Reauthenticate(const Credential &credential) { + assert(user_internal_); + return user_internal_->Reauthenticate(credential); +} + +Future User::ReauthenticateLastResult() const { + assert(user_internal_); + return user_internal_->ReauthenticateLastResult(); +} + +Future User::ReauthenticateAndRetrieveData_DEPRECATED( + const Credential &credential) { + assert(user_internal_); + return user_internal_->ReauthenticateAndRetrieveData_DEPRECATED(credential); +} + +Future User::ReauthenticateAndRetrieveDataLastResult_DEPRECATED() + const { + assert(user_internal_); + return user_internal_->ReauthenticateAndRetrieveDataLastResult_DEPRECATED(); +} + +Future User::ReauthenticateWithProvider_DEPRECATED( + FederatedAuthProvider *provider) const { + assert(user_internal_); + return user_internal_->ReauthenticateWithProvider_DEPRECATED(provider); +} + +Future User::SendEmailVerification() { + assert(user_internal_); + return user_internal_->SendEmailVerification(); +} + +Future User::SendEmailVerificationLastResult() const { + assert(user_internal_); + return user_internal_->SendEmailVerificationLastResult(); +} + +Future User::UpdateUserProfile(const UserProfile &profile) { + assert(user_internal_); + return user_internal_->UpdateUserProfile(profile); +} + +Future User::UpdateUserProfileLastResult() const { + assert(user_internal_); + return user_internal_->UpdateUserProfileLastResult(); +} + +Future User::LinkWithCredential_DEPRECATED( + const Credential &credential) { + assert(user_internal_); + return user_internal_->LinkWithCredential_DEPRECATED(credential); } -static std::string GetEmail(AuthData* auth_data, jobject impl) { - return GetUserProperty(auth_data, impl, userinfo::kGetEmail); +Future User::LinkWithCredentialLastResult_DEPRECATED() const { + assert(user_internal_); + return user_internal_->LinkWithCredentialLastResult_DEPRECATED(); } -static std::string GetDisplayName(AuthData* auth_data, jobject impl) { - return GetUserProperty(auth_data, impl, userinfo::kGetDisplayName); +Future User::LinkAndRetrieveDataWithCredential_DEPRECATED( + const Credential &credential) { + assert(user_internal_); + return user_internal_->LinkAndRetrieveDataWithCredential_DEPRECATED( + credential); } -static std::string GetPhoneNumber(AuthData* auth_data, jobject impl) { - return GetUserProperty(auth_data, impl, userinfo::kGetPhoneNumber); +Future +User::LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED() const { + assert(user_internal_); + return user_internal_ + ->LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED(); } -static std::string GetPhotoUrl(AuthData* auth_data, jobject impl) { - return GetUserProperty(auth_data, impl, userinfo::kGetPhotoUrl, - kPropertyTypeUri); +Future User::LinkWithProvider_DEPRECATED( + FederatedAuthProvider *provider) { + assert(user_internal_); + return user_internal_->LinkWithProvider_DEPRECATED(provider); } -static std::string GetProviderId(AuthData* auth_data, jobject impl) { - return GetUserProperty(auth_data, impl, userinfo::kGetProviderId); +Future User::Unlink_DEPRECATED(const char *provider) { + assert(user_internal_); + return user_internal_->Unlink_DEPRECATED(provider); } -User::~User() {} +Future User::UnlinkLastResult_DEPRECATED() const { + assert(user_internal_); + return user_internal_->UnlinkLastResult_DEPRECATED(); +} + +Future User::UpdatePhoneNumberCredential_DEPRECATED( + const Credential &credential) { + assert(user_internal_); + return user_internal_->UpdatePhoneNumberCredential_DEPRECATED(credential); +} + +Future User::UpdatePhoneNumberCredentialLastResult_DEPRECATED() const { + assert(user_internal_); + return user_internal_->UpdatePhoneNumberCredentialLastResult_DEPRECATED(); +} + +Future User::Reload() { + assert(user_internal_); + return user_internal_->Reload(); +} + +Future User::ReloadLastResult() const { + assert(user_internal_); + return user_internal_->ReloadLastResult(); +} + +Future User::Delete() { + assert(user_internal_); + return user_internal_->Delete(); +} + +Future User::DeleteLastResult() const { + assert(user_internal_); + return user_internal_->DeleteLastResult(); +} + +UserMetadata User::metadata() const { + assert(user_internal_); + return user_internal_->metadata(); +} + +bool User::is_email_verified() const { + assert(user_internal_); + return user_internal_->is_email_verified(); +} + +bool User::is_anonymous() const { + assert(user_internal_); + return user_internal_->is_anonymous(); +} std::string User::uid() const { - return ValidUser(auth_data_) ? GetUID(auth_data_, UserImpl(auth_data_)) : ""; + assert(user_internal_); + return user_internal_->uid(); } std::string User::email() const { - return ValidUser(auth_data_) ? GetEmail(auth_data_, UserImpl(auth_data_)) - : ""; + assert(user_internal_); + return user_internal_->email(); } std::string User::display_name() const { - return ValidUser(auth_data_) - ? GetDisplayName(auth_data_, UserImpl(auth_data_)) - : ""; -} - -std::string User::phone_number() const { - return ValidUser(auth_data_) - ? GetPhoneNumber(auth_data_, UserImpl(auth_data_)) - : ""; + assert(user_internal_); + return user_internal_->display_name(); } std::string User::photo_url() const { - return ValidUser(auth_data_) ? GetPhotoUrl(auth_data_, UserImpl(auth_data_)) - : ""; + assert(user_internal_); + return user_internal_->photo_url(); } std::string User::provider_id() const { - return ValidUser(auth_data_) ? GetProviderId(auth_data_, UserImpl(auth_data_)) - : ""; + assert(user_internal_); + return user_internal_->provider_id(); } -class AndroidWrappedUserInfo : public UserInfoInterface { - public: - AndroidWrappedUserInfo(AuthData* auth_data, jobject user_info) - : auth_data_(auth_data), user_info_(user_info) { - // Convert `user_info` to a global reference. - JNIEnv* env = Env(auth_data_); - user_info_ = env->NewGlobalRef(user_info); - env->DeleteLocalRef(user_info); - } - - virtual ~AndroidWrappedUserInfo() { - // Delete global reference. - JNIEnv* env = Env(auth_data_); - env->DeleteGlobalRef(user_info_); - user_info_ = nullptr; - } +std::string User::phone_number() const { + assert(user_internal_); + return user_internal_->phone_number(); +} - std::string uid() const override { return GetUID(auth_data_, user_info_); } +/// +/// UserInternal Class +/// +void assign_future_id(UserInternal *user_internal, std::string *future_api_id) { + static const char *kApiIdentifier = "UserInternal"; + future_api_id->reserve(strlen(kApiIdentifier) + + 16 /* hex characters in the pointer */ + + 1 /* null terminator */); + snprintf(&((*future_api_id)[0]), future_api_id->capacity(), "%s0x%016llx", + kApiIdentifier, + static_cast( // NOLINT + reinterpret_cast(user_internal))); +} - std::string email() const override { - return GetEmail(auth_data_, user_info_); +UserInternal::UserInternal(AuthData *auth_data, jobject user) + : auth_data_(auth_data), user_(nullptr), future_data_(kUserFnCount) { + assert(auth_data_); + JNIEnv *env = Env(auth_data_); + if (user != nullptr) { + user_ = env->NewGlobalRef(user); + assert(env->ExceptionCheck() == false); } + assign_future_id(this, &future_api_id_); +} - std::string display_name() const override { - return GetDisplayName(auth_data_, user_info_); +UserInternal::UserInternal(const UserInternal &user_internal) + : auth_data_(user_internal.auth_data_), + user_(nullptr), + future_data_(kUserFnCount) { + assert(auth_data_); + JNIEnv *env = Env(auth_data_); + if (user_internal.user_ != nullptr) { + user_ = env->NewGlobalRef(user_internal.user_); + assert(env->ExceptionCheck() == false); } + assign_future_id(this, &future_api_id_); +} - std::string phone_number() const override { - return GetPhoneNumber(auth_data_, user_info_); - } +UserInternal::~UserInternal() { + MutexLock user_lock(user_mutex_); + JNIEnv *env = Env(auth_data_); + util::CancelCallbacks(env, future_api_id_.c_str()); - std::string photo_url() const override { - return GetPhotoUrl(auth_data_, user_info_); + // Make sure we don't have any pending futures in flight before we disappear. + while (!future_data_.future_impl.IsSafeToDelete()) { + internal::Sleep(100); } - std::string provider_id() const override { - return GetProviderId(auth_data_, user_info_); - } + env->DeleteGlobalRef(user_); + user_ = nullptr; + auth_data_ = nullptr; - private: - /// Pointer to the main class. - /// Needed for context in implementation of virtuals. - AuthData* auth_data_; + clear_user_infos(); +} - /// Pointer to the main class. - /// Needed for context in implementation of virtuals. - jobject user_info_; -}; +void UserInternal::set_native_user_object_deprecated(jobject user) { + MutexLock user_lock(user_mutex_); + user_ = user; +} + +bool UserInternal::is_valid() const { return user_ != nullptr; } + +void UserInternal::clear_user_infos() { + for (size_t i = 0; i < user_infos_.size(); ++i) { + delete user_infos_[i]; + user_infos_[i] = nullptr; + } + user_infos_.clear(); +} -void ReadTokenResult(jobject result, FutureCallbackData* d, - bool success, void* void_data) { - auto data = static_cast(void_data); - JNIEnv* env = Env(d->auth_data); +void ReadTokenResult(jobject result, FutureCallbackData *d, + bool success, void *void_data) { + auto data = static_cast(void_data); + JNIEnv *env = Env(d->auth_data); // `result` is of type GetTokenResult when `success` is true. if (success) { @@ -295,45 +565,82 @@ void ReadTokenResult(jobject result, FutureCallbackData* d, } } -Future User::GetToken(bool force_refresh) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::GetToken(bool force_refresh) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_GetToken, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, + &future_data_, ""); } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_GetToken); - JNIEnv* env = Env(auth_data_); + + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_GetToken); + Future future = + MakeFuture(&future_data_.future_impl, future_handle); auth_data_->SetExpectIdTokenListenerCallback(force_refresh); + + JNIEnv *env = Env(auth_data_); jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kToken), force_refresh); + user_, user::GetMethodId(user::kToken), force_refresh); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, ReadTokenResult); + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, ReadTokenResult); env->DeleteLocalRef(pending_result); } else { // If the method failed for some reason, clear the expected callback. auth_data_->SetExpectIdTokenListenerCallback(false); } - return MakeFuture(&futures, handle); + return future; } -const std::vector& User::provider_data() const { - ClearUserInfos(auth_data_); +std::vector UserInternal::provider_data() const { + JNIEnv *env = Env(auth_data_); + std::vector local_user_infos; + if (is_valid()) { + const jobject list = + env->CallObjectMethod(user_, user::GetMethodId(user::kProviderData)); + assert(env->ExceptionCheck() == false); - if (ValidUser(auth_data_)) { - JNIEnv* env = Env(auth_data_); + if (list != nullptr) { + const int num_providers = + env->CallIntMethod(list, util::list::GetMethodId(util::list::kSize)); + assert(env->ExceptionCheck() == false); + local_user_infos.resize(num_providers); + for (int i = 0; i < num_providers; ++i) { + // user_info is converted to a global reference in + // AndroidWrappedUserInfo() and the local reference is released. + jobject user_info = env->CallObjectMethod( + list, util::list::GetMethodId(util::list::kGet), i); + assert(env->ExceptionCheck() == false); + local_user_infos[i] = AndroidWrappedUserInfo(auth_data_, user_info); + } + env->DeleteLocalRef(list); + } + } + return local_user_infos; +} + +const std::vector + &UserInternal::provider_data_DEPRECATED() { + MutexLock user_info_lock(user_mutex_); + clear_user_infos(); + if (is_valid()) { + JNIEnv *env = Env(auth_data_); // getProviderData returns `List` - const jobject list = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kProviderData)); + const jobject list = + env->CallObjectMethod(user_, user::GetMethodId(user::kProviderData)); assert(env->ExceptionCheck() == false); - // Copy the list into auth_data_->user_infos. + // Copy the list into user_infos_. if (list != nullptr) { const int num_providers = env->CallIntMethod(list, util::list::GetMethodId(util::list::kSize)); assert(env->ExceptionCheck() == false); - auth_data_->user_infos.resize(num_providers); + user_infos_.resize(num_providers); for (int i = 0; i < num_providers; ++i) { // user_info is converted to a global reference in @@ -341,73 +648,97 @@ const std::vector& User::provider_data() const { jobject user_info = env->CallObjectMethod( list, util::list::GetMethodId(util::list::kGet), i); assert(env->ExceptionCheck() == false); - auth_data_->user_infos[i] = - new AndroidWrappedUserInfo(auth_data_, user_info); + user_infos_[i] = new AndroidWrappedUserInfo(auth_data_, user_info); } env->DeleteLocalRef(list); } } - // Return a reference to our internally-backed values. - return auth_data_->user_infos; + return user_infos_; } -Future User::UpdateEmail(const char* email) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::UpdateEmail(const char *email) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_UpdateEmail, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, + &future_data_); } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_UpdateEmail); - JNIEnv* env = Env(auth_data_); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_UpdateEmail); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + JNIEnv *env = Env(auth_data_); jstring j_email = env->NewStringUTF(email); jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kUpdateEmail), j_email); + user_, user::GetMethodId(user::kUpdateEmail), j_email); env->DeleteLocalRef(j_email); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, nullptr); + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, nullptr); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; } -Future User::UpdatePassword(const char* password) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::UpdateEmailLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_UpdateEmail)); +} + +Future UserInternal::UpdatePassword(const char *password) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture( + kUserFn_UpdatePassword, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_UpdatePassword); - JNIEnv* env = Env(auth_data_); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_UpdatePassword); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + JNIEnv *env = Env(auth_data_); jstring j_password = env->NewStringUTF(password); jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kUpdatePassword), - j_password); + user_, user::GetMethodId(user::kUpdatePassword), j_password); env->DeleteLocalRef(j_password); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, nullptr); + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, nullptr); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; +} + +Future UserInternal::UpdatePasswordLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_UpdatePassword)); } -Future User::UpdateUserProfile(const UserProfile& profile) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::UpdateUserProfile(const User::UserProfile &profile) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture( + kUserFn_UpdateUserProfile, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_UpdateUserProfile); - JNIEnv* env = Env(auth_data_); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_UpdateUserProfile); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + + JNIEnv *env = Env(auth_data_); AuthError error = kAuthErrorNone; std::string exception_error_message; jobject j_user_profile_builder = env->NewObject( userprofilebuilder::GetClass(), userprofilebuilder::GetMethodId(userprofilebuilder::kConstructor)); - // Painfully call UserProfileChangeRequest.Builder.setDisplayName. + // Call UserProfileChangeRequest.Builder.setDisplayName. if (profile.display_name != nullptr) { jstring j_display_name = env->NewStringUTF(profile.display_name); jobject j_builder_discard = env->CallObjectMethod( @@ -422,7 +753,7 @@ Future User::UpdateUserProfile(const UserProfile& profile) { env->DeleteLocalRef(j_display_name); } - // Extra painfully call UserProfileChangeRequest.Builder.setPhotoUri. + // Call UserProfileChangeRequest.Builder.setPhotoUri. if (error == kAuthErrorNone && profile.photo_url != nullptr) { jobject j_uri = CharsToJniUri(env, profile.photo_url); jobject j_builder_discard = env->CallObjectMethod( @@ -448,269 +779,489 @@ Future User::UpdateUserProfile(const UserProfile& profile) { if (error == kAuthErrorNone) { // Call FirebaseUser.updateProfile. jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kUpdateUserProfile), + user_, user::GetMethodId(user::kUpdateUserProfile), j_user_profile_request); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, nullptr); + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, + future_api_id_, &future_data_.future_impl, nullptr); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; } else { - futures.Complete(handle, error, exception_error_message.c_str()); + future_data_.future_impl.Complete(future_handle, error, + exception_error_message.c_str()); } if (j_user_profile_request) { env->DeleteLocalRef(j_user_profile_request); } env->DeleteLocalRef(j_user_profile_builder); - return MakeFuture(&futures, handle); + return future; +} + +Future UserInternal::UpdateUserProfileLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_UpdateUserProfile)); } -Future User::LinkWithCredential(const Credential& credential) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::SendEmailVerification() { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture( + kUserFn_SendEmailVerification, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_LinkWithCredential); - JNIEnv* env = Env(auth_data_); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_SendEmailVerification); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + + JNIEnv *env = Env(auth_data_); jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kLinkWithCredential), - CredentialFromImpl(credential.impl_)); + user_, user::GetMethodId(user::kSendEmailVerification)); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, - ReadUserFromSignInResult); + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, nullptr); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; +} + +Future UserInternal::SendEmailVerificationLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_SendEmailVerification)); } -Future User::LinkAndRetrieveDataWithCredential( - const Credential& credential) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::LinkWithCredential_DEPRECATED( + const Credential &credential) { + MutexLock user_info_lock(user_mutex_); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc( + kUserFn_LinkWithCredential_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + + if (!is_valid()) { + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, + future_handle, &future_data_, (User *)nullptr); + return future; } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc( - kUserFn_LinkAndRetrieveDataWithCredential); - JNIEnv* env = Env(auth_data_); - jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kLinkWithCredential), - CredentialFromImpl(credential.impl_)); + JNIEnv *env = Env(auth_data_); + jobject pending_result = + env->CallObjectMethod(user_, user::GetMethodId(user::kLinkWithCredential), + CredentialFromImpl(credential.impl_)); + + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, ReadUserFromSignInResult); + env->DeleteLocalRef(pending_result); + } + return future; +} + +Future UserInternal::LinkWithCredentialLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult( + kUserFn_LinkWithCredential_DEPRECATED)); +} + +Future UserInternal::LinkAndRetrieveDataWithCredential_DEPRECATED( + const Credential &credential) { + MutexLock user_info_lock(user_mutex_); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc( + kUserFn_LinkAndRetrieveDataWithCredential_DEPRECATED); + Future future = + MakeFuture(&future_data_.future_impl, future_handle); + if (!is_valid()) { + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, + future_handle, &future_data_, SignInResult()); + return future; + } + + JNIEnv *env = Env(auth_data_); + jobject pending_result = + env->CallObjectMethod(user_, user::GetMethodId(user::kLinkWithCredential), + CredentialFromImpl(credential.impl_)); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, ReadSignInResult); + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, ReadSignInResult); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; } -Future User::LinkWithProvider( - FederatedAuthProvider* provider) const { - FIREBASE_ASSERT_RETURN(Future(), provider); - return provider->Link(auth_data_); +Future +UserInternal::LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult( + kUserFn_LinkAndRetrieveDataWithCredential_DEPRECATED)); } -Future User::Unlink(const char* provider) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::LinkWithProvider_DEPRECATED( + FederatedAuthProvider *provider) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid() || provider == nullptr) { + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc( + kUserFn_LinkWithProvider_DEPRECATED); + Future future = + MakeFuture(&future_data_.future_impl, future_handle); + if (!is_valid()) { + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, + future_handle, &future_data_, SignInResult()); + } else { + CompleteFuture(kAuthErrorInvalidParameter, + kUserNotInitializedErrorMessage, future_handle, + &future_data_, SignInResult()); + } + return future; } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_Unlink); - JNIEnv* env = Env(auth_data_); + return provider->Link(auth_data_, this); +} + +Future UserInternal::Unlink_DEPRECATED(const char *provider) { + MutexLock user_info_lock(user_mutex_); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_Unlink_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + if (!is_valid()) { + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, + future_handle, &future_data_, (User *)nullptr); + return future; + } + + JNIEnv *env = Env(auth_data_); jstring j_provider = env->NewStringUTF(provider); jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kUnlink), j_provider); + user_, user::GetMethodId(user::kUnlink), j_provider); env->DeleteLocalRef(j_provider); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, - ReadUserFromSignInResult); + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, ReadUserFromSignInResult); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; +} + +Future UserInternal::UnlinkLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_Unlink_DEPRECATED)); } -Future User::UpdatePhoneNumberCredential(const Credential& credential) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::UpdatePhoneNumberCredential_DEPRECATED( + const Credential &credential) { + MutexLock user_info_lock(user_mutex_); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc( + kUserFn_UpdatePhoneNumberCredential_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + + if (!is_valid()) { + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, + future_handle, &future_data_, (User *)nullptr); + return future; } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = - futures.SafeAlloc(kUserFn_UpdatePhoneNumberCredential); - JNIEnv* env = Env(auth_data_); + JNIEnv *env = Env(auth_data_); jobject j_credential = CredentialFromImpl(credential.impl_); if (env->IsInstanceOf(j_credential, phonecredential::GetClass())) { jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), - user::GetMethodId(user::kUpdatePhoneNumberCredential), j_credential); + user_, user::GetMethodId(user::kUpdatePhoneNumberCredential), + j_credential); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, + future_api_id_, &future_data_.future_impl, ReadUserFromSignInResult); env->DeleteLocalRef(pending_result); } } else { - futures.Complete(handle, kAuthErrorInvalidCredential, - "Credential is not a phone credential."); + CompleteFuture(kAuthErrorInvalidCredential, kInvalidCredentialErrorMessage, + future_handle, &future_data_, (User *)nullptr); } - return MakeFuture(&futures, handle); + return future; } -Future User::Reload() { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::UpdatePhoneNumberCredentialLastResult_DEPRECATED() + const { + return static_cast &>( + future_data_.future_impl.LastResult( + kUserFn_UpdatePhoneNumberCredential_DEPRECATED)); +} + +Future UserInternal::Reload() { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_Reload, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, + &future_data_); } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_Reload); - JNIEnv* env = Env(auth_data_); - jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kReload)); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_Reload); + Future future = MakeFuture(&future_data_.future_impl, future_handle); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, nullptr); + JNIEnv *env = Env(auth_data_); + jobject pending_result = + env->CallObjectMethod(user_, user::GetMethodId(user::kReload)); + + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, nullptr); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; +} + +Future UserInternal::ReloadLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_Reload)); } -Future User::Reauthenticate(const Credential& credential) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::Reauthenticate(const Credential &credential) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture( + kUserFn_Reauthenticate, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_Reauthenticate); - JNIEnv* env = Env(auth_data_); - jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kReauthenticate), - CredentialFromImpl(credential.impl_)); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_Reload); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + + JNIEnv *env = Env(auth_data_); + jobject pending_result = + env->CallObjectMethod(user_, user::GetMethodId(user::kReauthenticate), + CredentialFromImpl(credential.impl_)); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, nullptr); + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, nullptr); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; } -Future User::ReauthenticateAndRetrieveData( - const Credential& credential) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::ReauthenticateLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_Reauthenticate)); +} + +Future UserInternal::ReauthenticateAndRetrieveData_DEPRECATED( + const Credential &credential) { + MutexLock user_info_lock(user_mutex_); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc( + kUserFn_ReauthenticateAndRetrieveData_DEPRECATED); + Future future = + MakeFuture(&future_data_.future_impl, future_handle); + if (!is_valid()) { + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, + future_handle, &future_data_, SignInResult()); + return future; } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = - futures.SafeAlloc(kUserFn_ReauthenticateAndRetrieveData); - JNIEnv* env = Env(auth_data_); + JNIEnv *env = Env(auth_data_); jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), - user::GetMethodId(user::kReauthenticateAndRetrieveData), + user_, user::GetMethodId(user::kReauthenticateAndRetrieveData), CredentialFromImpl(credential.impl_)); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, ReadSignInResult); + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, ReadSignInResult); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; } -Future User::ReauthenticateWithProvider( - FederatedAuthProvider* provider) const { - FIREBASE_ASSERT_RETURN(Future(), provider); - return provider->Reauthenticate(auth_data_); +Future +UserInternal::ReauthenticateAndRetrieveDataLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult( + kUserFn_ReauthenticateAndRetrieveData_DEPRECATED)); } -Future User::SendEmailVerification() { - if (!ValidUser(auth_data_)) { - return Future(); - } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_SendEmailVerification); - JNIEnv* env = Env(auth_data_); - - jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kSendEmailVerification)); - - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, nullptr); - env->DeleteLocalRef(pending_result); +Future UserInternal::ReauthenticateWithProvider_DEPRECATED( + FederatedAuthProvider *provider) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid() || provider == nullptr) { + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc( + kUserFn_ReauthenticateWithProvider_DEPRECATED); + Future future = + MakeFuture(&future_data_.future_impl, future_handle); + if (!is_valid()) { + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, + future_handle, &future_data_, SignInResult()); + } else { + CompleteFuture(kAuthErrorInvalidParameter, + kUserNotInitializedErrorMessage, future_handle, + &future_data_, SignInResult()); + } + return future; } - return MakeFuture(&futures, handle); + return provider->Reauthenticate(auth_data_, this); } -Future User::Delete() { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::Delete() { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_Delete, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, + &future_data_); } - ReferenceCountedFutureImpl& futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_Delete); - JNIEnv* env = Env(auth_data_); - jobject pending_result = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kDelete)); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_Reload); + Future future = MakeFuture(&future_data_.future_impl, future_handle); - if (!CheckAndCompleteFutureOnError(env, &futures, handle)) { - RegisterCallback(pending_result, handle, auth_data_, - [](jobject result, FutureCallbackData* d, - bool success, void* void_data) { + JNIEnv *env = Env(auth_data_); + jobject pending_result = + env->CallObjectMethod(user_, user::GetMethodId(user::kDelete)); + + if (!CheckAndCompleteFutureOnError(env, &future_data_.future_impl, + future_handle)) { + RegisterCallback(auth_data_, pending_result, future_handle, future_api_id_, + &future_data_.future_impl, + [](jobject result, FutureCallbackData *d, + bool success, void *void_data) { if (success) { - UpdateCurrentUser(d->auth_data); + UpdateCurrentUser(Env(d->auth_data), d->auth_data); } }); env->DeleteLocalRef(pending_result); } - return MakeFuture(&futures, handle); + return future; } -UserMetadata User::metadata() const { - if (!ValidUser(auth_data_)) return UserMetadata(); +Future UserInternal::DeleteLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_Delete)); +} - JNIEnv* env = Env(auth_data_); +UserMetadata UserInternal::metadata() const { + UserMetadata user_metadata; + if (!is_valid()) return user_metadata; - jobject userMetadata = env->CallObjectMethod( - UserImpl(auth_data_), user::GetMethodId(user::kGetMetadata)); + JNIEnv *env = Env(auth_data_); + jobject jUserMetadata = + env->CallObjectMethod(user_, user::GetMethodId(user::kGetMetadata)); util::CheckAndClearJniExceptions(env); - if (!userMetadata) return UserMetadata(); + if (!jUserMetadata) return user_metadata; - UserMetadata data; - data.last_sign_in_timestamp = env->CallLongMethod( - userMetadata, metadata::GetMethodId(metadata::kGetLastSignInTimestamp)); + user_metadata.last_sign_in_timestamp = env->CallLongMethod( + jUserMetadata, metadata::GetMethodId(metadata::kGetLastSignInTimestamp)); assert(env->ExceptionCheck() == false); - data.creation_timestamp = env->CallLongMethod( - userMetadata, metadata::GetMethodId(metadata::kGetCreationTimestamp)); + user_metadata.creation_timestamp = env->CallLongMethod( + jUserMetadata, metadata::GetMethodId(metadata::kGetCreationTimestamp)); assert(env->ExceptionCheck() == false); - env->DeleteLocalRef(userMetadata); + env->DeleteLocalRef(jUserMetadata); - return data; + return user_metadata; } -bool User::is_email_verified() const { - if (!ValidUser(auth_data_)) return false; +bool UserInternal::is_email_verified() const { + if (!is_valid()) return false; - JNIEnv* env = Env(auth_data_); + JNIEnv *env = Env(auth_data_); bool result = env->CallBooleanMethod( - UserImpl(auth_data_), userinfo::GetMethodId(userinfo::kIsEmailVerified)); + user_, userinfo::GetMethodId(userinfo::kIsEmailVerified)); util::CheckAndClearJniExceptions(env); return result; } -bool User::is_anonymous() const { - if (!ValidUser(auth_data_)) return false; +bool UserInternal::is_anonymous() const { + if (!is_valid()) return false; - JNIEnv* env = Env(auth_data_); - bool result = env->CallBooleanMethod(UserImpl(auth_data_), - user::GetMethodId(user::kIsAnonymous)); + JNIEnv *env = Env(auth_data_); + bool result = + env->CallBooleanMethod(user_, user::GetMethodId(user::kIsAnonymous)); util::CheckAndClearJniExceptions(env); return result; } +std::string UserInternal::uid() const { + if (!is_valid()) return ""; + JNIEnv *env = Env(auth_data_); + jobject property = + env->CallObjectMethod(user_, userinfo::GetMethodId(userinfo::kGetUid)); + if (firebase::util::CheckAndClearJniExceptions(env) || !property) { + return std::string(); + } + return JniStringToString(env, property); +} + +std::string UserInternal::email() const { + if (!is_valid()) return ""; + JNIEnv *env = Env(auth_data_); + jobject property = + env->CallObjectMethod(user_, userinfo::GetMethodId(userinfo::kGetEmail)); + if (firebase::util::CheckAndClearJniExceptions(env) || !property) { + return std::string(); + } + return JniStringToString(env, property); +} + +std::string UserInternal::display_name() const { + if (!is_valid()) return ""; + JNIEnv *env = Env(auth_data_); + jobject property = env->CallObjectMethod( + user_, userinfo::GetMethodId(userinfo::kGetDisplayName)); + if (firebase::util::CheckAndClearJniExceptions(env) || !property) { + return std::string(); + } + return JniStringToString(env, property); +} + +std::string UserInternal::photo_url() const { + if (!is_valid()) return ""; + JNIEnv *env = Env(auth_data_); + jobject property = env->CallObjectMethod( + user_, userinfo::GetMethodId(userinfo::kGetPhotoUrl)); + if (firebase::util::CheckAndClearJniExceptions(env) || !property) { + return std::string(); + } + return JniUriToString(env, property); +} + +std::string UserInternal::provider_id() const { + if (!is_valid()) return ""; + JNIEnv *env = Env(auth_data_); + jobject property = env->CallObjectMethod( + user_, userinfo::GetMethodId(userinfo::kGetProviderId)); + if (firebase::util::CheckAndClearJniExceptions(env) || !property) { + return std::string(); + } + return JniStringToString(env, property); +} + +std::string UserInternal::phone_number() const { + if (!is_valid()) return ""; + JNIEnv *env = Env(auth_data_); + jobject property = env->CallObjectMethod( + user_, userinfo::GetMethodId(userinfo::kGetPhoneNumber)); + if (firebase::util::CheckAndClearJniExceptions(env) || !property) { + return std::string(); + } + return JniStringToString(env, property); +} + } // namespace auth } // namespace firebase diff --git a/auth/src/auth.cc b/auth/src/auth.cc index 0c3cb86035..40680df32c 100644 --- a/auth/src/auth.cc +++ b/auth/src/auth.cc @@ -81,7 +81,6 @@ Auth* Auth::GetAuth(App* app, InitResult* init_result_out) { // Create a new Auth and initialize. Auth* auth = new Auth(app, auth_impl); - LogDebug("Creating Auth %p for App %p", auth, app); // Stick it in the global map so we remember it, and can delete it on // shutdown. @@ -135,48 +134,55 @@ Auth::Auth(App* app, void* auth_impl) : auth_data_(new AuthData) { } void Auth::DeleteInternal() { - MutexLock lock(*g_auths_mutex); + // Mutex is contained within the auth_data_ object. Retain a pointer to it so + // that we can clean up its contents and then delete it after we leave the + // mutex. + AuthData* retained_auth_impl = auth_data_; + { + MutexLock(auth_data_->auth_mutex); + MutexLock lock(*g_auths_mutex); - if (!auth_data_) return; + if (!auth_data_) return; - { - MutexLock destructing_lock(auth_data_->desctruting_mutex); - auth_data_->destructing = true; - } + { + MutexLock destructing_lock(auth_data_->destructing_mutex); + auth_data_->destructing = true; + } - CleanupNotifier* notifier = CleanupNotifier::FindByOwner(auth_data_->app); - assert(notifier); - notifier->UnregisterObject(this); + CleanupNotifier* notifier = CleanupNotifier::FindByOwner(auth_data_->app); + assert(notifier); + notifier->UnregisterObject(this); - int num_auths_remaining = 0; - { - // Remove `this` from the g_auths map. - // The mapping is 1:1, so we should only ever delete one. - for (auto it = g_auths.begin(); it != g_auths.end(); ++it) { - if (it->second == this) { - LogDebug("Deleting Auth %p for App %p", this, it->first); - g_auths.erase(it); - break; + int num_auths_remaining = 0; + { + // Remove `this` from the g_auths map. + // The mapping is 1:1, so we should only ever delete one. + for (auto it = g_auths.begin(); it != g_auths.end(); ++it) { + if (it->second == this) { + LogDebug("Deleting Auth %p for App %p", this, it->first); + g_auths.erase(it); + break; + } } - } - num_auths_remaining = g_auths.size(); - } + num_auths_remaining = g_auths.size(); + } - auth_data_->ClearListeners(); + auth_data_->ClearListeners(); - // If this is the last Auth instance to be cleaned up, also clean up data for - // Credentials. - if (num_auths_remaining == 0) { - CleanupCredentialFutureImpl(); - } + // If this is the last Auth instance to be cleaned up, also clean up data + // for Credentials. + if (num_auths_remaining == 0) { + CleanupCredentialFutureImpl(); + } - // Destroy the platform-specific object. - DestroyPlatformAuth(auth_data_); + // Destroy the platform-specific object. + DestroyPlatformAuth(auth_data_); + auth_data_ = nullptr; + } // Delete the pimpl data. - delete auth_data_; - auth_data_ = nullptr; + delete retained_auth_impl; } Auth::~Auth() { DeleteInternal(); } @@ -184,6 +190,7 @@ Auth::~Auth() { DeleteInternal(); } // Always non-nullptr since set in constructor. App& Auth::app() { FIREBASE_ASSERT(auth_data_ != nullptr); + MutexLock(auth_data_->auth_mutex); return *auth_data_->app; } @@ -218,6 +225,7 @@ static bool AddListener(T listener, std::vector* listener_vector, Auth* auth, void Auth::AddAuthStateListener(AuthStateListener* listener) { if (!auth_data_) return; + MutexLock(auth_data_->auth_mutex); // Would have to lock mutex till the method ends to protect on race // conditions. MutexLock lock(auth_data_->listeners_mutex); @@ -227,8 +235,8 @@ void Auth::AddAuthStateListener(AuthStateListener* listener) { // If the listener is registered successfully and persistent cache has been // loaded, trigger OnAuthStateChanged() immediately. Otherwise, wait until // the cache is loaded, through AuthStateListener event. - // NOTE: This should be called synchronously or current_user() for desktop - // implementation may not work. + // NOTE: This should be called synchronously or current_user_DEPRECATED() for + // desktop implementation may not work. if (added && !auth_data_->persistent_cache_load_pending) { listener->OnAuthStateChanged(this); } @@ -236,6 +244,7 @@ void Auth::AddAuthStateListener(AuthStateListener* listener) { void Auth::AddIdTokenListener(IdTokenListener* listener) { if (!auth_data_) return; + MutexLock(auth_data_->auth_mutex); // Would have to lock mutex till the method ends to protect on race // conditions. MutexLock lock(auth_data_->listeners_mutex); @@ -290,12 +299,14 @@ static void RemoveListener(T listener, std::vector* listener_vector, void Auth::RemoveAuthStateListener(AuthStateListener* listener) { if (!auth_data_) return; + MutexLock(auth_data_->auth_mutex); RemoveListener(listener, &auth_data_->listeners, this, &listener->auths_, &auth_data_->listeners_mutex); } void Auth::RemoveIdTokenListener(IdTokenListener* listener) { if (!auth_data_) return; + MutexLock(auth_data_->auth_mutex); int listener_count = auth_data_->id_token_listeners.size(); RemoveListener(listener, &auth_data_->id_token_listeners, this, &listener->auths_, &auth_data_->listeners_mutex); @@ -364,13 +375,15 @@ AUTH_NOTIFY_LISTENERS(NotifyIdTokenListeners, "ID token", id_token_listeners, OnIdTokenChanged); AUTH_RESULT_FN(Auth, FetchProvidersForEmail, Auth::FetchProvidersResult) -AUTH_RESULT_FN(Auth, SignInWithCustomToken, User*) -AUTH_RESULT_FN(Auth, SignInWithCredential, User*) -AUTH_RESULT_FN(Auth, SignInAndRetrieveDataWithCredential, SignInResult) -AUTH_RESULT_FN(Auth, SignInAnonymously, User*) -AUTH_RESULT_FN(Auth, SignInWithEmailAndPassword, User*) -AUTH_RESULT_FN(Auth, CreateUserWithEmailAndPassword, User*) AUTH_RESULT_FN(Auth, SendPasswordResetEmail, void) +AUTH_RESULT_DEPRECATED_FN(Auth, SignInWithCustomToken, User*) +AUTH_RESULT_DEPRECATED_FN(Auth, SignInWithCredential, User*) +AUTH_RESULT_DEPRECATED_FN(Auth, SignInAndRetrieveDataWithCredential, + SignInResult) +AUTH_RESULT_DEPRECATED_FN(Auth, SignInAnonymously, User*) +AUTH_RESULT_DEPRECATED_FN(Auth, SignInWithEmailAndPassword, User*) +AUTH_RESULT_DEPRECATED_FN(Auth, CreateUserWithEmailAndPassword, User*) + } // namespace auth } // namespace firebase diff --git a/auth/src/common.cc b/auth/src/common.cc index 70324d4831..165c8c6cfd 100644 --- a/auth/src/common.cc +++ b/auth/src/common.cc @@ -21,6 +21,17 @@ namespace firebase { namespace auth { +const char* kUserNotInitializedErrorMessage = + "Operation attempted on an invalid User object."; +const char* kPhoneAuthNotSupportedErrorMessage = + "Phone Auth is not supported on this platform."; +const char* kAuthInvalidParameterErrorMessage = + "A parameter pass to the auth method is null or invalid."; +extern const char* kInvalidCredentialErrorMessage = + "The provided credential does not match the required type."; +extern const char* kErrorEmptyEmailPasswordErrorMessage = + "Empty email or password are not allowed."; + // static member variables const uint32_t PhoneAuthProvider::kMaxTimeoutMs = 3000; @@ -47,6 +58,59 @@ ReferenceCountedFutureImpl* GetCredentialFutureImpl() { return future_data->api(); } +void CompleteFuture(int error, const char* error_msg, + SafeFutureHandle handle, FutureData* future_data) { + if (future_data->future_impl.ValidFuture(handle)) { + future_data->future_impl.Complete(handle, error, error_msg); + } +} + +void CompleteFuture(int error, const char* error_msg, + SafeFutureHandle handle, + FutureData* future_data, const std::string& result) { + if (future_data->future_impl.ValidFuture(handle)) { + future_data->future_impl.CompleteWithResult(handle, error, error_msg, + result); + } +} + +void CompleteFuture(int error, const char* error_msg, + SafeFutureHandle handle, FutureData* future_data, + User* user) { + if (future_data->future_impl.ValidFuture(handle)) { + future_data->future_impl.CompleteWithResult(handle, error, error_msg, user); + } +} + +void CompleteFuture(int error, const char* error_msg, + SafeFutureHandle handle, + FutureData* future_data, SignInResult sign_in_result) { + if (future_data->future_impl.ValidFuture(handle)) { + future_data->future_impl.CompleteWithResult(handle, error, error_msg, + sign_in_result); + } +} + +// For calls that aren't asynchronous, we can create and complete at the +// same time. +Future CreateAndCompleteFuture(int fn_idx, int error, + const char* error_msg, + FutureData* future_data) { + SafeFutureHandle handle = CreateFuture(fn_idx, future_data); + CompleteFuture(error, error_msg, handle, future_data); + return MakeFuture(&future_data->future_impl, handle); +} + +Future CreateAndCompleteFuture(int fn_idx, int error, + const char* error_msg, + FutureData* future_data, + const std::string& result) { + SafeFutureHandle handle = + CreateFuture(fn_idx, future_data); + CompleteFuture(error, error_msg, handle, future_data, result); + return MakeFuture(&future_data->future_impl, handle); +} + void CleanupCredentialFutureImpl() { StaticFutureData::CleanupFutureDataForModule(&kCredentialFutureIdentifier); } diff --git a/auth/src/common.h b/auth/src/common.h index f92acb301f..0079c9eb61 100644 --- a/auth/src/common.h +++ b/auth/src/common.h @@ -17,11 +17,21 @@ #ifndef FIREBASE_AUTH_SRC_COMMON_H_ #define FIREBASE_AUTH_SRC_COMMON_H_ +#include + #include "auth/src/data.h" namespace firebase { namespace auth { +// Error messages used for completing futures. These match the error codes in +// the AdErrorCode enumeration in the C++ API. +extern const char* kUserNotInitializedErrorMessage; +extern const char* kPhoneAuthNotSupportedErrorMessage; +extern const char* kAuthInvalidParameterErrorMessage; +extern const char* kInvalidCredentialErrorMessage; +extern const char* kErrorEmptyEmailPasswordErrorMessage; + // Enumeration for Credential API functions that return a Future. // This allows us to hold a Future for the most recent call to that API. enum CredentialApiFunction { @@ -30,6 +40,53 @@ enum CredentialApiFunction { kNumCredentialFunctions }; +// Hold backing data for returned Futures. +struct FutureData { + explicit FutureData(int num_functions_that_return_futures) + : future_impl(num_functions_that_return_futures) {} + + // Handle calls from Futures that the API returns. + ReferenceCountedFutureImpl future_impl; +}; + +// Create a future and update the corresponding last result. +template +SafeFutureHandle CreateFuture(int fn_idx, FutureData* future_data) { + return future_data->future_impl.SafeAlloc(fn_idx); +} + +// Mark a Future as complete. +void CompleteFuture(int error, const char* error_msg, + SafeFutureHandle handle, FutureData* future_data); + +// Mark a Future as complete +void CompleteFuture(int error, const char* error_msg, + SafeFutureHandle handle, + FutureData* future_data, const std::string& result); + +// Mark a Future as complete +void CompleteFuture(int error, const char* error_msg, + SafeFutureHandle handle, FutureData* future_data, + User* user); + +// Mark a Future as complete +void CompleteFuture(int error, const char* error_msg, + SafeFutureHandle handle, + FutureData* future_data, SignInResult result); + +// For calls that aren't asynchronous, create and complete a Future at +// the same time. +Future CreateAndCompleteFuture(int fn_idx, int error, + const char* error_msg, + FutureData* future_data); + +// For calls that aren't asynchronous, create and complete a +// Future at the same time. +Future CreateAndCompleteFuture(int fn_idx, int error, + const char* error_msg, + FutureData* future_data, + const std::string& result); + // Platform-specific method to create the wrapped Auth class. void* CreatePlatformAuth(App* app); @@ -51,9 +108,18 @@ void LogHeartbeat(Auth* auth); auth_data_->future_impl.LastResult(k##class_name##Fn_##fn_name)); \ } +// All the result functions are similar. +// Just return the local Future, cast to the proper result type. +#define AUTH_RESULT_DEPRECATED_FN(class_name, fn_name, result_type) \ + Future class_name::fn_name##LastResult_DEPRECATED() const { \ + return static_cast&>( \ + auth_data_->future_impl.LastResult( \ + k##class_name##Fn_##fn_name##_DEPRECATED)); \ + } + // Returns true if `auth_data` has a user that's currently active. inline bool ValidUser(const AuthData* auth_data) { - return auth_data->user_impl != nullptr; + return auth_data->deprecated_fields.user_deprecated->is_valid(); } // Notify all the listeners of the state change. @@ -62,9 +128,6 @@ void NotifyAuthStateListeners(AuthData* auth_data); // Notify all the listeners of the ID token change. void NotifyIdTokenListeners(AuthData* auth_data); -// Synchronize the current user. -void UpdateCurrentUser(AuthData* auth_data); - // Get a FutureImpl to use for Credential methods that return Futures. ReferenceCountedFutureImpl* GetCredentialFutureImpl(); diff --git a/auth/src/data.h b/auth/src/data.h index 797a680148..529355f951 100644 --- a/auth/src/data.h +++ b/auth/src/data.h @@ -27,43 +27,64 @@ namespace firebase { namespace auth { +// @deprecated +// +// Fields that should be removed when the Auth Breaking Changes Deprecation +// window ends. +struct AuthDataDeprecatedFields { + // Used to return User* objects from deprecated methods. + User* user_deprecated; + + // Internal implementation of user_deprecated. This object's contains a + // pointer the platform specific user object, which is updated on User + // operations. + UserInternal* user_internal_deprecated; + + // JNI reference to the user object in the Firebase Android SDK. + void* android_user_impl; +}; + // Enumeration for API functions that return a Future. // This allows us to hold a Future for the most recent call to that API. enum AuthApiFunction { // External functions in the Auth API. kAuthFn_FetchProvidersForEmail, - kAuthFn_SignInWithCustomToken, - kAuthFn_SignInWithCredential, - kAuthFn_SignInAndRetrieveDataWithCredential, - kAuthFn_SignInAnonymously, - kAuthFn_SignInWithEmailAndPassword, - kAuthFn_SignInWithProvider, - kAuthFn_CreateUserWithEmailAndPassword, + kAuthFn_SignInWithCustomToken_DEPRECATED, + kAuthFn_SignInWithCredential_DEPRECATED, + kAuthFn_SignInAndRetrieveDataWithCredential_DEPRECATED, + kAuthFn_SignInAnonymously_DEPRECATED, + kAuthFn_SignInWithEmailAndPassword_DEPRECATED, + kAuthFn_SignInWithProvider_DEPRECATED, + kAuthFn_CreateUserWithEmailAndPassword_DEPRECATED, kAuthFn_SendPasswordResetEmail, - // External functions in the User API. + // Internal functions that are still handles, but are only used internally: + kInternalFn_GetTokenForRefresher, + kInternalFn_GetTokenForFunctionRegistry, + + kAuthFnCount +}; + +// Constants representing each User function that returns a Future. +enum UserFn { kUserFn_GetToken, kUserFn_UpdateEmail, kUserFn_UpdatePassword, kUserFn_Reauthenticate, - kUserFn_ReauthenticateAndRetrieveData, + kUserFn_ReauthenticateAndRetrieveData_DEPRECATED, kUserFn_SendEmailVerification, kUserFn_ConfirmEmailVerification, kUserFn_UpdateUserProfile, - kUserFn_LinkWithCredential, - kUserFn_LinkAndRetrieveDataWithCredential, - kUserFn_LinkWithProvider, - kUserFn_ReauthenticateWithProvider, - kUserFn_Unlink, - kUserFn_UpdatePhoneNumberCredential, + kUserFn_LinkWithCredential_DEPRECATED, + kUserFn_LinkAndRetrieveDataWithCredential_DEPRECATED, + kUserFn_LinkWithProvider_DEPRECATED, + kUserFn_ReauthenticateWithProvider_DEPRECATED, + kUserFn_Unlink_DEPRECATED, + kUserFn_UpdatePhoneNumberCredential_DEPRECATED, kUserFn_Reload, kUserFn_Delete, - // Internal functions that are still handles, but are only used internally: - kInternalFn_GetTokenForRefresher, - kInternalFn_GetTokenForFunctionRegistry, - - kNumAuthFunctions + kUserFnCount }; /// Delete all the user_infos in auth_data and reset the length to zero. @@ -76,10 +97,8 @@ struct AuthData { AuthData() : app(nullptr), auth(nullptr), - future_impl(kNumAuthFunctions), - current_user(this), + future_impl(kAuthFnCount), auth_impl(nullptr), - user_impl(nullptr), listener_impl(nullptr), id_token_listener_impl(nullptr), expect_id_token_listener_callback(false), @@ -96,7 +115,6 @@ struct AuthData { app = nullptr; auth = nullptr; auth_impl = nullptr; - user_impl = nullptr; listener_impl = nullptr; id_token_listener_impl = nullptr; } @@ -116,23 +134,24 @@ struct AuthData { /// Backpointer to the external Auth class that holds this internal data. Auth* auth; + /// @deprecated Remove when Auth deprecation APIs are removed. + /// + /// Contains a User object that's updated whenever the current user changes. + /// This is used to return User* values from deprecated Auth and User + /// methods. These methods have been replaced with methods that return + /// Users by value (now that we can copy users.) + AuthDataDeprecatedFields deprecated_fields; + /// Handle calls from Futures that the API returns. ReferenceCountedFutureImpl future_impl; /// Identifier used to track futures associated with future_impl. std::string future_api_id; - /// Unique user for this Auth. Note: we only support one user per Auth. - User current_user; - /// Platform-dependent implementation of Auth (that we're wrapping). /// For example, on Android `jobject`. void* auth_impl; - /// Platform-dependent implementation of User (that we're wrapping). - /// For example, on iOS `FIRUser`. - void* user_impl; - /// Platform-dependent implementation of AuthStateListener (that we're /// wrapping). For example, on Android `jobject`. void* listener_impl; @@ -179,7 +198,10 @@ struct AuthData { bool destructing; // Mutex protecting destructing - Mutex desctruting_mutex; + Mutex destructing_mutex; + + // Mutex guarding the auth object for standard API operations. + Mutex auth_mutex; // Sets if the Id Token Listener is expecting a callback. // Used to workaround an issue where the Id Token is not reset with a new one, diff --git a/auth/src/desktop/auth_desktop.cc b/auth/src/desktop/auth_desktop.cc index b7fcf763a5..307c00a971 100644 --- a/auth/src/desktop/auth_desktop.cc +++ b/auth/src/desktop/auth_desktop.cc @@ -111,7 +111,7 @@ void IdTokenRefreshListener::OnIdTokenChanged(Auth* auth) { // to prevent deadlocks! MutexLock lock(mutex_); MutexLock future_lock(auth->auth_data_->future_impl.mutex()); - if (auth->current_user()) { + if (auth->current_user_DEPRECATED()) { ResetTokenRefreshCounter(auth->auth_data_); // Retrieve id_token from auth_data @@ -151,7 +151,7 @@ bool Auth::GetAuthTokenForRegistry(App* app, void* /*unused*/, void* out) { Auth* auth = Auth::FindAuth(app); if (auth) { // Make sure the persistent cache is loaded. - auth->current_user(); + auth->current_user_DEPRECATED(); auto result = static_cast(out); MutexLock lock(auth->auth_data_->token_listener_mutex); @@ -176,7 +176,7 @@ bool Auth::GetAuthTokenAsyncForRegistry(App* app, void* force_refresh, Auth* auth = Auth::FindAuth(app); if (auth) { - User* user = auth->current_user(); + User* user = auth->current_user_DEPRECATED(); if (user) { Future future = user->GetTokenInternal( *in_force_refresh, kInternalFn_GetTokenForFunctionRegistry); @@ -199,7 +199,7 @@ bool Auth::GetCurrentUserUidForRegistry(App* app, void* /*unused*/, void* out) { Auth* auth = Auth::FindAuth(app); if (!auth) return false; - User* user = auth->current_user(); + User* user = auth->current_user_DEPRECATED(); if (!user) return false; if (out_string) { @@ -337,9 +337,10 @@ void Auth::DestroyPlatformAuth(AuthData* const auth_data) { // RPCs -Future Auth::SignInWithCustomToken(const char* const custom_token) { +Future Auth::SignInWithCustomToken_DEPRECATED( + const char* const custom_token) { Promise promise(&auth_data_->future_impl, - kAuthFn_SignInWithCustomToken); + kAuthFn_SignInWithCustomToken_DEPRECATED); if (!custom_token || strlen(custom_token) == 0) { FailPromise(&promise, kAuthErrorInvalidCustomToken); return promise.LastResult(); @@ -355,9 +356,10 @@ Future Auth::SignInWithCustomToken(const char* const custom_token) { PerformSignInFlow); } -Future Auth::SignInWithCredential(const Credential& credential) { +Future Auth::SignInWithCredential_DEPRECATED( + const Credential& credential) { Promise promise(&auth_data_->future_impl, - kAuthFn_SignInWithCredential); + kAuthFn_SignInWithCredential_DEPRECATED); if (!ValidateCredential(&promise, credential.provider(), credential.impl_)) { return promise.LastResult(); } @@ -366,14 +368,15 @@ Future Auth::SignInWithCredential(const Credential& credential) { credential.impl_); } -Future Auth::SignInWithProvider(FederatedAuthProvider* provider) { +Future Auth::SignInWithProvider_DEPRECATED( + FederatedAuthProvider* provider) { FIREBASE_ASSERT_RETURN(Future(), provider); // TODO(b/139363200) // return provider->SignIn(auth_data_); SafeFutureHandle handle = auth_data_->future_impl.SafeAlloc( - kAuthFn_SignInWithProvider); + kAuthFn_SignInWithProvider_DEPRECATED); auth_data_->future_impl.CompleteWithResult( handle, kAuthErrorUnimplemented, "Operation is not supported on non-mobile systems.", @@ -381,8 +384,9 @@ Future Auth::SignInWithProvider(FederatedAuthProvider* provider) { return MakeFuture(&auth_data_->future_impl, handle); } -Future Auth::SignInAnonymously() { - Promise promise(&auth_data_->future_impl, kAuthFn_SignInAnonymously); +Future Auth::SignInAnonymously_DEPRECATED() { + Promise promise(&auth_data_->future_impl, + kAuthFn_SignInAnonymously_DEPRECATED); // If user is already signed in anonymously, return immediately. bool is_anonymous = false; @@ -405,10 +409,10 @@ Future Auth::SignInAnonymously() { PerformSignInFlow); } -Future Auth::SignInWithEmailAndPassword(const char* const email, - const char* const password) { +Future Auth::SignInWithEmailAndPassword_DEPRECATED( + const char* const email, const char* const password) { Promise promise(&auth_data_->future_impl, - kAuthFn_SignInWithEmailAndPassword); + kAuthFn_SignInWithEmailAndPassword_DEPRECATED); if (!ValidateEmailAndPassword(&promise, email, password)) { return promise.LastResult(); } @@ -421,10 +425,10 @@ Future Auth::SignInWithEmailAndPassword(const char* const email, PerformSignInFlow); } -Future Auth::CreateUserWithEmailAndPassword(const char* const email, - const char* const password) { +Future Auth::CreateUserWithEmailAndPassword_DEPRECATED( + const char* const email, const char* const password) { Promise promise(&auth_data_->future_impl, - kAuthFn_CreateUserWithEmailAndPassword); + kAuthFn_CreateUserWithEmailAndPassword_DEPRECATED); if (!ValidateEmailAndPassword(&promise, email, password)) { return promise.LastResult(); } @@ -438,10 +442,11 @@ Future Auth::CreateUserWithEmailAndPassword(const char* const email, PerformSignInFlow); } -Future Auth::SignInAndRetrieveDataWithCredential( +Future Auth::SignInAndRetrieveDataWithCredential_DEPRECATED( const Credential& credential) { - Promise promise(&auth_data_->future_impl, - kAuthFn_SignInAndRetrieveDataWithCredential); + Promise promise( + &auth_data_->future_impl, + kAuthFn_SignInAndRetrieveDataWithCredential_DEPRECATED); return DoSignInWithCredential(promise, auth_data_, credential.provider(), credential.impl_); } @@ -509,11 +514,11 @@ void Auth::SignOut() { AuthenticationResult::SignOut(auth_data_); } -// AuthStateListener to wait for current_user() until persistent cache load is -// finished. +// AuthStateListener to wait for current_user_DEPRECATED() until persistent +// cache load is finished. class CurrentUserBlockListener : public firebase::auth::AuthStateListener { public: - explicit CurrentUserBlockListener() : semaphore_(0) {} + CurrentUserBlockListener() : semaphore_(0) {} ~CurrentUserBlockListener() override {} void OnAuthStateChanged(Auth* auth) override { semaphore_.Post(); } @@ -527,7 +532,7 @@ class CurrentUserBlockListener : public firebase::auth::AuthStateListener { // It's safe to return a direct pointer to `current_user` because that class // holds nothing but a pointer to AuthData, which never changes. // All User functions that require synchronization go through AuthData's mutex. -User* Auth::current_user() { +User* Auth::current_user_DEPRECATED() { if (!auth_data_) return nullptr; // Add a listener and wait for the first trigger. diff --git a/auth/src/desktop/auth_providers/federated_auth_provider.cc b/auth/src/desktop/auth_providers/federated_auth_provider.cc index 7d6a30c71d..22239b75d2 100644 --- a/auth/src/desktop/auth_providers/federated_auth_provider.cc +++ b/auth/src/desktop/auth_providers/federated_auth_provider.cc @@ -81,7 +81,7 @@ Future FederatedOAuthProvider::SignIn(AuthData* auth_data) { FIREBASE_ASSERT_RETURN(Future(), handler_); assert(auth_data); Future future = - CreateAuthFuture(auth_data, kAuthFn_SignInWithProvider); + CreateAuthFuture(auth_data, kAuthFn_SignInWithProvider_DEPRECATED); if (future.status() == kFutureStatusPending) { AuthCompletionHandle* auth_completion_handle = new AuthCompletionHandle( SafeFutureHandle(future.GetHandle()), auth_data); @@ -94,7 +94,7 @@ Future FederatedOAuthProvider::Link(AuthData* auth_data) { assert(auth_data); FIREBASE_ASSERT_RETURN(Future(), handler_); Future future = - CreateAuthFuture(auth_data, kUserFn_LinkWithProvider); + CreateAuthFuture(auth_data, kUserFn_LinkWithProvider_DEPRECATED); if (future.status() == kFutureStatusPending) { AuthCompletionHandle* auth_completion_handle = new AuthCompletionHandle( SafeFutureHandle(future.GetHandle()), auth_data); @@ -107,8 +107,8 @@ Future FederatedOAuthProvider::Reauthenticate( AuthData* auth_data) { assert(auth_data); FIREBASE_ASSERT_RETURN(Future(), handler_); - Future future = - CreateAuthFuture(auth_data, kUserFn_ReauthenticateWithProvider); + Future future = CreateAuthFuture( + auth_data, kUserFn_ReauthenticateWithProvider_DEPRECATED); if (future.status() == kFutureStatusPending) { AuthCompletionHandle* auth_completion_handle = new AuthCompletionHandle( SafeFutureHandle(future.GetHandle()), auth_data); diff --git a/auth/src/desktop/authentication_result.cc b/auth/src/desktop/authentication_result.cc index b8252e9ebe..c0ef5996e8 100644 --- a/auth/src/desktop/authentication_result.cc +++ b/auth/src/desktop/authentication_result.cc @@ -45,7 +45,8 @@ SignInResult AuthenticationResult::SetAsCurrentUser( // Save the previous user state to be able to check whether listeners should // be notified later on. UserData previous_user; - // Don't call Auth::current_user() to avoid locking the mutex twice. + // Don't call Auth::current_user_DEPRECATED() to avoid locking the mutex + // twice. User* api_user_to_return = nullptr; { UserView::Writer writer = diff --git a/auth/src/desktop/user_desktop.cc b/auth/src/desktop/user_desktop.cc index d70eb76d66..25d15127e2 100644 --- a/auth/src/desktop/user_desktop.cc +++ b/auth/src/desktop/user_desktop.cc @@ -105,9 +105,9 @@ GetTokenResult GetTokenIfFresh(const UserView::Reader& user, return GetTokenResult(kAuthErrorFailure); } -// Makes sure that calling auth->current_user()->id_token() will result in -// a token that is good for at least 5 minutes. Will fetch a new token from the -// backend if necessary. +// Makes sure that calling auth->current_user_DEPRECATED()->id_token() will +// result in a token that is good for at least 5 minutes. Will fetch a new token +// from the backend if necessary. // // If force_refresh is given, then a new token will be fetched without checking // the current token at all. @@ -426,7 +426,7 @@ UserDataPersist::UserDataPersist( : user_secure_manager_(std::move(user_secure_manager)) {} void UserDataPersist::OnAuthStateChanged(Auth* auth) { // NOLINT - if (auth->current_user() != nullptr) { + if (auth->current_user_DEPRECATED() != nullptr) { SaveUserData(auth->auth_data_); } else { DeleteUserData(auth->auth_data_); @@ -511,7 +511,7 @@ void AssignLoadedData(const Future& future, AuthData* auth_data) { void HandleLoadedData(const Future& future, void* auth_data) { auto cast_auth_data = static_cast(auth_data); - MutexLock destructing_lock(cast_auth_data->desctruting_mutex); + MutexLock destructing_lock(cast_auth_data->destructing_mutex); if (cast_auth_data->destructing) { // If auth is destructing, abort. return; @@ -811,8 +811,8 @@ Future User::UpdateUserProfile(const UserProfile& profile) { PerformSetAccountInfoFlow); } -Future User::Unlink(const char* const provider) { - Promise promise(&auth_data_->future_impl, kUserFn_Unlink); +Future User::Unlink_DEPRECATED(const char* const provider) { + Promise promise(&auth_data_->future_impl, kUserFn_Unlink_DEPRECATED); if (!provider || strlen(provider) == 0) { FailPromise(&promise, kAuthErrorNoSuchProvider); return promise.LastResult(); @@ -840,8 +840,10 @@ Future User::Unlink(const char* const provider) { PerformSetAccountInfoFlow); } -Future User::LinkWithCredential(const Credential& credential) { - Promise promise(&auth_data_->future_impl, kUserFn_LinkWithCredential); +Future User::LinkWithCredential_DEPRECATED( + const Credential& credential) { + Promise promise(&auth_data_->future_impl, + kUserFn_LinkWithCredential_DEPRECATED); return DoLinkCredential(promise, auth_data_, credential.provider(), credential.impl_); } @@ -854,13 +856,14 @@ Future User::LinkAndRetrieveDataWithCredential( credential.impl_); } -Future User::LinkWithProvider( +Future User::LinkWithProvider_DEPRECATED( FederatedAuthProvider* provider) const { FIREBASE_ASSERT_RETURN(Future(), provider); // TODO(b/139363200) // return provider->Link(auth_data_); SafeFutureHandle handle = - auth_data_->future_impl.SafeAlloc(kUserFn_LinkWithProvider); + auth_data_->future_impl.SafeAlloc( + kUserFn_LinkWithProvider_DEPRECATED); auth_data_->future_impl.CompleteWithResult( handle, kAuthErrorUnimplemented, "Operation is not supported on non-mobile systems.", @@ -874,22 +877,23 @@ Future User::Reauthenticate(const Credential& credential) { credential.impl_); } -Future User::ReauthenticateAndRetrieveData( +Future User::ReauthenticateAndRetrieveData_DEPRECATED( const Credential& credential) { - Promise promise(&auth_data_->future_impl, - kUserFn_ReauthenticateAndRetrieveData); + Promise promise( + &auth_data_->future_impl, + kUserFn_ReauthenticateAndRetrieveData_DEPRECATED); return DoReauthenticate(promise, auth_data_, credential.provider(), credential.impl_); } -Future User::ReauthenticateWithProvider( +Future User::ReauthenticateWithProvider_DEPRECATED( FederatedAuthProvider* provider) const { FIREBASE_ASSERT_RETURN(Future(), provider); // TODO(b/139363200) // return provider->Reauthenticate(auth_data_); SafeFutureHandle handle = auth_data_->future_impl.SafeAlloc( - kUserFn_ReauthenticateWithProvider); + kUserFn_ReauthenticateWithProvider_DEPRECATED); auth_data_->future_impl.CompleteWithResult( handle, kAuthErrorUnimplemented, "Operation is not supported on non-mobile systems.", @@ -954,9 +958,10 @@ std::string User::provider_id() const { // Not implemented -Future User::UpdatePhoneNumberCredential(const Credential& credential) { +Future User::UpdatePhoneNumberCredential_DEPRECATED( + const Credential& credential) { Promise promise(&auth_data_->future_impl, - kUserFn_UpdatePhoneNumberCredential); + kUserFn_UpdatePhoneNumberCredential_DEPRECATED); if (!ValidateCurrentUser(&promise, auth_data_)) { return promise.LastResult(); } diff --git a/auth/src/desktop/user_desktop.h b/auth/src/desktop/user_desktop.h index f03a6f9f3c..40af4762ad 100644 --- a/auth/src/desktop/user_desktop.h +++ b/auth/src/desktop/user_desktop.h @@ -26,7 +26,51 @@ namespace firebase { namespace auth { -// LINT.IfChange +class UserInternal { + public: + // The user's ID, unique to the Firebase project. + std::string uid; + + // The associated email, if any. + std::string email; + + // The display name, if any. + std::string display_name; + + // Associated photo url, if any. + std::string photo_url; + + // A provider ID for the user e.g. "Facebook". + std::string provider_id; + + // The user's phone number, if any. + std::string phone_number; + + // Whether is anonymous. + bool is_anonymous; + + // Whether email is verified. + bool is_email_verified; + + // Tokens for authentication and authorization. + std::string id_token; // an authorization code or access_token + std::string refresh_token; + std::string access_token; + + // The approximate expiration date of the access token. + std::time_t access_token_expiration_date; + + // Whether or not the user can be authenticated by provider 'password'. + bool has_email_password_credential; + + /// The last sign in UTC timestamp in milliseconds. + /// See https://en.wikipedia.org/wiki/Unix_time for details of UTC. + uint64_t last_sign_in_timestamp; + + /// The Firebase user creation UTC timestamp in milliseconds. + uint64_t creation_timestamp; +}; + // The desktop-specific UserInfo implementation. struct UserInfoImpl { // Note: since Visual Studio 2013 and below don't autogenerate move diff --git a/auth/src/include/firebase/auth.h b/auth/src/include/firebase/auth.h index 408c34ea90..4f6d5e95ba 100644 --- a/auth/src/include/firebase/auth.h +++ b/auth/src/include/firebase/auth.h @@ -48,6 +48,7 @@ struct AuthCompletionHandle; class FederatedAuthProvider; class FederatedOAuthProvider; struct SignInResult; +class UserInternal; /// @brief Firebase authentication object. /// @@ -102,7 +103,7 @@ struct SignInResult; /// /// // Request anonymous sign-in and wait until asynchronous call completes. /// firebase::Future sign_in_future = -/// auth->SignInAnonymously(); +/// auth->SignInAnonymously_DEPRECATED(); /// while(sign_in_future.status() == firebase::kFutureStatusPending) { /// // when polling, like this, make sure you service your platform's /// // message loop @@ -146,6 +147,8 @@ class Auth { ~Auth(); + /// @deprecated This is a deprecated method. Please use @current_user instead. + /// /// Synchronously gets the cached current user, or nullptr if there is none. /// @note This function may block and wait until the Auth instance finishes /// loading the saved user's state. This should only happen for a short @@ -160,7 +163,7 @@ class Auth { /// /// @endxmlonly /// - User* current_user(); + FIREBASE_DEPRECATED User* current_user_DEPRECATED(); /// The current user language code. This can be set to the app’s current /// language by calling set_language_code. The string must be a language code @@ -238,23 +241,40 @@ class Auth { /// Get results of the most recent call to @ref FetchProvidersForEmail. Future FetchProvidersForEmailLastResult() const; - // ----- Sign In --------------------------------------------------------- + /// @deprecated This is a deprecated method. Please use @SignInWithCustomToken + /// instead. + /// /// Asynchronously logs into Firebase with the given Auth token. /// /// An error is returned, if the token is invalid, expired or otherwise /// not accepted by the server. - Future SignInWithCustomToken(const char* token); + FIREBASE_DEPRECATED Future SignInWithCustomToken_DEPRECATED( + const char* token); + /// @deprecated + /// /// Get results of the most recent call to @ref SignInWithCustomToken. - Future SignInWithCustomTokenLastResult() const; + FIREBASE_DEPRECATED Future SignInWithCustomTokenLastResult_DEPRECATED() + const; + /// @deprecated This is a deprecated method. Please use @SignInWithCredential + /// instead. + /// /// Convenience method for @ref SignInAndRetrieveDataWithCredential that /// doesn't return additional identity provider data. - Future SignInWithCredential(const Credential& credential); + FIREBASE_DEPRECATED Future SignInWithCredential_DEPRECATED( + const Credential& credential); - /// Get results of the most recent call to @ref SignInWithCredential. - Future SignInWithCredentialLastResult() const; + /// @deprecated + /// + /// Get results of the most recent call to @ref + /// SignInWithCredential_DEPRECATED. + FIREBASE_DEPRECATED Future SignInWithCredentialLastResult_DEPRECATED() + const; + /// @deprecated This is a deprecated method. Please use @SignInWithProvider + /// instead. + /// /// Sign-in a user authenticated via a federated auth provider. /// /// @param[in] provider Contains information on the provider to authenticate @@ -265,8 +285,12 @@ class Auth { /// @note: This operation is supported only on iOS, tvOS and Android /// platforms. On other platforms this method will return a Future with a /// preset error code: kAuthErrorUnimplemented. - Future SignInWithProvider(FederatedAuthProvider* provider); + FIREBASE_DEPRECATED Future SignInWithProvider_DEPRECATED( + FederatedAuthProvider* provider); + /// @deprecated This is a deprecated method. Please use + /// @SignInAndRetrieveDataWithCredential instead. + /// /// Asynchronously logs into Firebase with the given credentials. /// /// For example, the credential could wrap a Facebook login access token or @@ -278,13 +302,19 @@ class Auth { /// /// An error is returned if the token is invalid, expired, or otherwise not /// accepted by the server. - Future SignInAndRetrieveDataWithCredential( - const Credential& credential); + FIREBASE_DEPRECATED Future + SignInAndRetrieveDataWithCredential_DEPRECATED(const Credential& credential); + /// @deprecated + /// /// Get results of the most recent call to - /// @ref SignInAndRetrieveDataWithCredential. - Future SignInAndRetrieveDataWithCredentialLastResult() const; + /// @ref SignInAndRetrieveDataWithCredential_DEPRECATED. + FIREBASE_DEPRECATED Future + SignInAndRetrieveDataWithCredentialLastResult_DEPRECATED() const; + /// @deprecated This is a deprecated method. Please use @SignInAnonymously + /// instead. + /// /// Asynchronously creates and becomes an anonymous user. /// If there is already an anonymous user signed in, that user will be /// returned instead. @@ -329,7 +359,7 @@ class Auth { /// if (future.status() == firebase::kFutureStatusInvalid || /// (future.status() == firebase::kFutureStatusComplete && /// future.error() != firebase::auth::kAuthErrorNone)) { - /// auth.SignInAnonymously(); + /// auth.SignInAnonymously_DEPRECATED(); /// } /// /// // We're signed in if the most recent result was successful. @@ -338,31 +368,41 @@ class Auth { /// } /// @endcode /// @endif - Future SignInAnonymously(); + Future SignInAnonymously_DEPRECATED(); - /// Get results of the most recent call to @ref SignInAnonymously. - Future SignInAnonymouslyLastResult() const; + /// Get results of the most recent call to @ref SignInAnonymously_DEPRECATED. + Future SignInAnonymouslyLastResult_DEPRECATED() const; + /// @deprecated This is a deprecated method. Please use + /// @SignInWithEmailAndPassword instead. + /// /// Signs in using provided email address and password. /// An error is returned if the password is wrong or otherwise not accepted /// by the server. - Future SignInWithEmailAndPassword(const char* email, - const char* password); + FIREBASE_DEPRECATED Future SignInWithEmailAndPassword_DEPRECATED( + const char* email, const char* password); - /// Get results of the most recent call to @ref SignInWithEmailAndPassword. - Future SignInWithEmailAndPasswordLastResult() const; + /// @deprecated + /// + /// Get results of the most recent call to @ref + /// SignInWithEmailAndPassword_DEPRECATED. + Future SignInWithEmailAndPasswordLastResult_DEPRECATED() const; + /// @deprecated This is a deprecated method. Please use + /// @CreateUserWithEmailAndPassword instead. + /// /// Creates, and on success, logs in a user with the given email address /// and password. /// /// An error is returned when account creation is unsuccessful /// (due to another existing account, invalid password, etc.). - Future CreateUserWithEmailAndPassword(const char* email, - const char* password); + FIREBASE_DEPRECATED Future CreateUserWithEmailAndPassword_DEPRECATED( + const char* email, const char* password); /// Get results of the most recent call to - /// @ref CreateUserWithEmailAndPassword. - Future CreateUserWithEmailAndPasswordLastResult() const; + /// @ref CreateUserWithEmailAndPassword_DEPRECATED. + FIREBASE_DEPRECATED Future + CreateUserWithEmailAndPasswordLastResult_DEPRECATED() const; /// Removes any existing authentication credentials from this client. /// This function always succeeds. @@ -551,9 +591,9 @@ class Auth { void* out_future); // Provides access to the current user's uid, equivalent to calling - // this->current_user()->uid(). Returns the current user's uid or an empty - // string, if there isn't one. The out pointer is expected to point to an - // instance of std::string. + // this->current_user_DEPRECATED()->uid(). Returns the current user's uid or + // an empty string, if there isn't one. The out pointer is expected to point + // to an instance of std::string. static bool GetCurrentUserUidForRegistry(App* app, void* /*unused*/, void* out); @@ -838,9 +878,13 @@ class FederatedAuthProvider { private: friend class ::firebase::auth::Auth; friend class ::firebase::auth::User; + friend class ::firebase::auth::UserInternal; + virtual Future SignIn(AuthData* auth_data) = 0; - virtual Future Link(AuthData* auth_data) = 0; - virtual Future Reauthenticate(AuthData* auth_data) = 0; + virtual Future Link(AuthData* auth_data, + UserInternal* user_internal) = 0; + virtual Future Reauthenticate(AuthData* auth_data, + UserInternal* user_internal) = 0; }; /// @brief Authenticates with Federated OAuth Providers via the @@ -922,10 +966,13 @@ class FederatedOAuthProvider : public FederatedAuthProvider { private: friend class ::firebase::auth::Auth; + friend class ::firebase::auth::UserInternal; Future SignIn(AuthData* auth_data) override; - Future Link(AuthData* auth_data) override; - Future Reauthenticate(AuthData* auth_data) override; + Future Link(AuthData* auth_data, + UserInternal* user_internal) override; + Future Reauthenticate(AuthData* auth_data, + UserInternal* user_internal) override; FederatedOAuthProviderData provider_data_; #ifdef INTERNAL_EXPERIMENTAL diff --git a/auth/src/include/firebase/auth/credential.h b/auth/src/include/firebase/auth/credential.h index a179d199b6..d87d542e17 100644 --- a/auth/src/include/firebase/auth/credential.h +++ b/auth/src/include/firebase/auth/credential.h @@ -28,6 +28,7 @@ namespace firebase { // Predeclarations. class App; +class UserInternal; /// @cond FIREBASE_APP_INTERNAL template @@ -109,6 +110,7 @@ class Credential { /// @cond FIREBASE_APP_INTERNAL friend class Auth; friend class User; + friend class UserInternal; /// Platform-specific implementation. /// For example, FIRAuthCredential* on iOS. diff --git a/auth/src/include/firebase/auth/types.h b/auth/src/include/firebase/auth/types.h index 3f141ad369..4c0fe9c0be 100644 --- a/auth/src/include/firebase/auth/types.h +++ b/auth/src/include/firebase/auth/types.h @@ -428,6 +428,12 @@ enum AuthError { kAuthErrorTokenRefreshUnavailable, #endif // INTERNAL_EXEPERIMENTAL + + /// Indicates that an operation was attempted on an invalid User. + kAuthErrorInvalidUser, + + /// Indicates that an invalid parameter was passed to an auth method. + kAuthErrorInvalidParameter, }; /// @brief Contains information required to authenticate with a third party diff --git a/auth/src/include/firebase/auth/user.h b/auth/src/include/firebase/auth/user.h index ddd1ba8906..5278c7d593 100644 --- a/auth/src/include/firebase/auth/user.h +++ b/auth/src/include/firebase/auth/user.h @@ -31,6 +31,7 @@ namespace auth { // Predeclarations. class Auth; +class UserInternal; struct AuthData; class FederatedAuthProvider; @@ -62,7 +63,7 @@ class UserInfoInterface { /// /// @endxmlonly /// - virtual std::string uid() const = 0; + virtual std::string uid() const; /// Gets email associated with the user, if any. /// @@ -72,7 +73,7 @@ class UserInfoInterface { /// /// @endxmlonly /// - virtual std::string email() const = 0; + virtual std::string email() const; /// Gets the display name associated with the user, if any. /// @@ -82,7 +83,7 @@ class UserInfoInterface { /// /// @endxmlonly /// - virtual std::string display_name() const = 0; + virtual std::string display_name() const; /// Gets the photo url associated with the user, if any. /// @@ -92,7 +93,7 @@ class UserInfoInterface { /// /// @endxmlonly /// - virtual std::string photo_url() const = 0; + virtual std::string photo_url() const; /// Gets the provider ID for the user (For example, "Facebook"). /// @@ -102,10 +103,10 @@ class UserInfoInterface { /// /// @endxmlonly /// - virtual std::string provider_id() const = 0; + virtual std::string provider_id() const; /// Gets the phone number for the user, in E.164 format. - virtual std::string phone_number() const = 0; + virtual std::string phone_number() const; }; /// @brief Additional user data returned from an identity provider. @@ -178,8 +179,19 @@ class User : public UserInfoInterface { const char* photo_url; }; + /// Copy Constructor. + User(const User&); + + /// Assignment Operator. + User& operator=(const User& user); + ~User(); + /// Returns whether this User object represents a valid user. Could be false + /// on Users contained with @ref AuthResult structures from failed Auth + /// operations. + bool is_valid() const; + /// The Java Web Token (JWT) that can be used to identify the user to /// the backend. /// @@ -214,7 +226,11 @@ class User : public UserInfoInterface { /// /// @endxmlonly /// - const std::vector& provider_data() const; + std::vector provider_data() const; + + /// @deprecated This is a deprecated method. Please use @ref provider_data + /// instead. + const std::vector& provider_data_DEPRECATED(); /// Sets the email address for the user. /// @@ -253,6 +269,9 @@ class User : public UserInfoInterface { /// Get results of the most recent call to @ref Reauthenticate. Future ReauthenticateLastResult() const; + /// @deprecated This is a deprecated method. Please use + /// @ref ReauthenticateAndRetrieveData(const Credential&) instead. + /// /// Reauthenticate using a credential. /// /// @if cpp_examples @@ -279,12 +298,18 @@ class User : public UserInfoInterface { /// or if sign-in with that credential failed. /// @note: The current user may be signed out if this operation fails on /// Android and desktop platforms. - Future ReauthenticateAndRetrieveData( - const Credential& credential); + FIREBASE_DEPRECATED Future + ReauthenticateAndRetrieveData_DEPRECATED(const Credential& credential); + /// @deprecated + /// /// Get results of the most recent call to @ref ReauthenticateAndRetrieveData. - Future ReauthenticateAndRetrieveDataLastResult() const; + FIREBASE_DEPRECATED Future + ReauthenticateAndRetrieveDataLastResult_DEPRECATED() const; + /// @deprecated This is a deprecated method. Please use + /// @ref ReauthenticateWithProvider(FederatedAuthProvider*) instead. + /// /// @brief Re-authenticates the user with a federated auth provider. /// /// @param[in] provider Contains information on the auth provider to @@ -294,7 +319,7 @@ class User : public UserInfoInterface { /// @note: This operation is supported only on iOS, tvOS and Android /// platforms. On other platforms this method will return a Future with a /// preset error code: kAuthErrorUnimplemented. - Future ReauthenticateWithProvider( + Future ReauthenticateWithProvider_DEPRECATED( FederatedAuthProvider* provider) const; /// Initiates email verification for the user. @@ -309,13 +334,23 @@ class User : public UserInfoInterface { /// Get results of the most recent call to @ref UpdateUserProfile. Future UpdateUserProfileLastResult() const; + /// @deprecated This is a deprecated method. Please use + /// @ref LinkWithCredential(const Credential&) instead. + /// /// Convenience function for @ref ReauthenticateAndRetrieveData that discards /// the returned @ref AdditionalUserInfo in @ref SignInResult. - Future LinkWithCredential(const Credential& credential); + FIREBASE_DEPRECATED Future LinkWithCredential_DEPRECATED( + const Credential& credential); - /// Get results of the most recent call to @ref LinkWithCredential. - Future LinkWithCredentialLastResult() const; + /// @deprecated + /// + /// Get results of the most recent call to @ref LinkWithCredential_DEPRECATED. + FIREBASE_DEPRECATED Future LinkWithCredentialLastResult_DEPRECATED() + const; + /// @deprecated This is a deprecated method. Please use + /// @ref LinkAndRetrieveDataWithCredential(const Credential&) instead. + /// /// Links the user with the given 3rd party credentials. /// /// For example, a Facebook login access token, a Twitter token/token-secret @@ -327,13 +362,19 @@ class User : public UserInfoInterface { /// /// Data from the Identity Provider used to sign-in is returned in the /// @ref AdditionalUserInfo inside @ref SignInResult. - Future LinkAndRetrieveDataWithCredential( - const Credential& credential); + FIREBASE_DEPRECATED Future + LinkAndRetrieveDataWithCredential_DEPRECATED(const Credential& credential); + /// @deprecated + /// /// Get results of the most recent call to - /// @ref LinkAndRetrieveDataWithCredential. - Future LinkAndRetrieveDataWithCredentialLastResult() const; + /// @ref LinkAndRetrieveDataWithCredential_DEPRECATED. + FIREBASE_DEPRECATED Future + LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED() const; + /// @deprecated This is a deprecated method. Please use + /// @ref LinkWithProvider(FederatedAuthProvider*) instead. + /// /// Links this user with a federated auth provider. /// /// @param[in] provider Contains information on the auth provider to link @@ -344,24 +385,37 @@ class User : public UserInfoInterface { /// @note: This operation is supported only on iOS, tvOS and Android /// platforms. On other platforms this method will return a Future with a /// preset error code: kAuthErrorUnimplemented. - Future LinkWithProvider(FederatedAuthProvider* provider) const; + FIREBASE_DEPRECATED Future LinkWithProvider_DEPRECATED( + FederatedAuthProvider* provider); + /// @deprecated This is a deprecated method. Please use @ref Unlink(const + /// char*) instead. + /// /// Unlinks the current user from the provider specified. /// Status will be an error if the user is not linked to the given provider. - Future Unlink(const char* provider); + FIREBASE_DEPRECATED Future Unlink_DEPRECATED(const char* provider); + /// @deprecated + /// /// Get results of the most recent call to @ref Unlink. - Future UnlinkLastResult() const; + FIREBASE_DEPRECATED Future UnlinkLastResult_DEPRECATED() const; + /// @deprecated This is a deprecated method. Please use + /// @ref UpdatePhoneNumberCredential(const PhoneAuthCredential&) instead. + /// /// Updates the currently linked phone number on the user. /// This is useful when a user wants to change their phone number. It is a - /// shortcut to calling Unlink(phone_credential.provider().c_str()) and then - /// LinkWithCredential(phone_credential). - /// `credential` must have been created with @ref PhoneAuthProvider. - Future UpdatePhoneNumberCredential(const Credential& credential); + /// shortcut to calling Unlink_DEPRECATED(phone_credential.provider().c_str()) + /// and then LinkWithCredential_DEPRECATED(phone_credential). `credential` + /// must have been created with @ref PhoneAuthProvider. + FIREBASE_DEPRECATED Future UpdatePhoneNumberCredential_DEPRECATED( + const Credential& credential); - /// Get results of the most recent call to @ref UpdatePhoneNumberCredential. - Future UpdatePhoneNumberCredentialLastResult() const; + /// @deprecated + //// + /// Get results of the most recent call to @ref + /// UpdatePhoneNumberCredential_DEPRECATED. + Future UpdatePhoneNumberCredentialLastResult_DEPRECATED() const; /// Refreshes the data for this user. /// @@ -469,16 +523,12 @@ class User : public UserInfoInterface { virtual std::string phone_number() const; private: + // Constructor of an internal opaque type. Memory ownership of UserInternal + // passes to to this User object. + User(AuthData* auth_data, UserInternal* user_internal); + /// @cond FIREBASE_APP_INTERNAL friend struct AuthData; - // Only exists in AuthData. Access via @ref Auth::CurrentUser(). - explicit User(AuthData* auth_data) : auth_data_(auth_data) {} - - // Disable copy constructor. - User(const User&) = delete; - // Disable copy operator. - User& operator=(const User&) = delete; - /// @endcond #if defined(INTERNAL_EXPERIMENTAL) // Doxygen should not make docs for this function. @@ -493,6 +543,7 @@ class User : public UserInfoInterface { // Use the pimpl mechanism to hide data details in the cpp files. AuthData* auth_data_; + UserInternal* user_internal_; }; } // namespace auth diff --git a/auth/src/ios/auth_ios.mm b/auth/src/ios/auth_ios.mm index 01ab3d160f..af60ff8ac0 100644 --- a/auth/src/ios/auth_ios.mm +++ b/auth/src/ios/auth_ios.mm @@ -149,13 +149,20 @@ explicit ListenerHandleHolder(T handle) : handle(handle) {} // Grab the user value from the iOS API and remember it locally. void UpdateCurrentUser(AuthData *auth_data) { - MutexLock lock(auth_data->future_impl.mutex()); + MutexLock(auth_data->auth_mutex); FIRUser *user = [AuthImpl(auth_data) currentUser]; SetUserImpl(auth_data, user); } // Platform-specific method to initialize AuthData. void Auth::InitPlatformAuth(AuthData *auth_data) { + // Create persistent User data to continue to facilitate deprecated aysnc + // methods which return a pointer to a User. Remove this structure when those + // deprecated methods are removed. + auth_data->deprecated_fields.user_internal_deprecated = new UserInternal((FIRUser *)nil); + auth_data->deprecated_fields.user_deprecated = + new User(auth_data, auth_data->deprecated_fields.user_internal_deprecated); + FIRCPPAuthListenerHandle *listener_cpp_handle = [[FIRCPPAuthListenerHandle alloc] init]; listener_cpp_handle.authData = auth_data; reinterpret_cast(auth_data->auth_impl)->listener_handle = listener_cpp_handle; @@ -195,6 +202,7 @@ void UpdateCurrentUser(AuthData *auth_data) { // Platform-specific method to destroy the wrapped Auth class. void Auth::DestroyPlatformAuth(AuthData *auth_data) { + // Note: auth_data->auth_mutex is already locked by Auth::DeleteInternal(). // Remove references from listener blocks. AuthDataIos *auth_data_ios = reinterpret_cast(auth_data->auth_impl); FIRCPPAuthListenerHandle *listener_cpp_handle = auth_data_ios->listener_handle.get(); @@ -218,6 +226,13 @@ void UpdateCurrentUser(AuthData *auth_data) { SetUserImpl(auth_data, nullptr); + auth_data->deprecated_fields.user_internal_deprecated = nullptr; + + // This also deletes auth_data->deprecated_fields.user_internal_deprecated + // since User has ownership of the UserInternal allocation. + delete auth_data->deprecated_fields.user_deprecated; + auth_data->deprecated_fields.user_deprecated = nullptr; + // Release the FIRAuth* that we allocated in CreatePlatformAuth(). delete auth_data_ios; auth_data->auth_impl = nullptr; @@ -229,18 +244,19 @@ void LogHeartbeat(Auth *auth) { } Future Auth::FetchProvidersForEmail(const char *email) { + MutexLock(auth_data_->auth_mutex); // Create data structure to hold asynchronous results. FetchProvidersResult initial_data; - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = - futures.SafeAlloc(kAuthFn_FetchProvidersForEmail, initial_data); - + ReferenceCountedFutureImpl &future_impl = auth_data_->future_impl; + const auto future_handle = + future_impl.SafeAlloc(kAuthFn_FetchProvidersForEmail, initial_data); + Future future = MakeFuture(&future_impl, future_handle); [AuthImpl(auth_data_) fetchSignInMethodsForEmail:@(email) completion:^(NSArray *_Nullable providers, NSError *_Nullable error) { - futures.Complete( - handle, AuthErrorFromNSError(error), + future_impl.Complete( + future_handle, AuthErrorFromNSError(error), [error.localizedDescription UTF8String], [providers](FetchProvidersResult *data) { // Copy data to our result format. @@ -251,37 +267,37 @@ void LogHeartbeat(Auth *auth) { } }); }]; - - return MakeFuture(&futures, handle); + return future; } -// It's safe to return a direct pointer to `current_user` because that class -// holds nothing but a pointer to AuthData, which never changes. -// All User functions that require synchronization go through AuthData's mutex. -User *Auth::current_user() { +// Support the deprecated current_user method by returning a pointer to the +// User contained within Auth. This maintains the older behavior of +// current_user() via current_user_DEPRECATED throughout the deprecation +// window. +User *Auth::current_user_DEPRECATED() { if (!auth_data_) return nullptr; - MutexLock lock(auth_data_->future_impl.mutex()); - - // auth_data_->current_user should be available after Auth is created because - // [AuthImpl(auth_data) currentUser] is called during Auth::InitPlatformAuth() - // and it would block until persistence is loaded. - User *user = auth_data_->user_impl == nullptr ? nullptr : &auth_data_->current_user; - return user; + MutexLock(auth_data_->auth_mutex); + if (auth_data_->deprecated_fields.user_deprecated == nullptr || + !auth_data_->deprecated_fields.user_deprecated->is_valid()) { + return nullptr; + } else { + return auth_data_->deprecated_fields.user_deprecated; + } } static User *AssignUser(FIRUser *_Nullable user, AuthData *auth_data) { // Update our pointer to the iOS user that we're wrapping. - MutexLock lock(auth_data->future_impl.mutex()); + MutexLock(auth_data->auth_mutex); if (user) { SetUserImpl(auth_data, user); } - // If the returned `user` is non-null then the current user is active. - return auth_data->user_impl == nullptr ? nullptr : &auth_data->current_user; + return auth_data->deprecated_fields.user_deprecated; } std::string Auth::language_code() const { if (!auth_data_) return ""; + MutexLock(auth_data_->auth_mutex); NSString *language_code = [AuthImpl(auth_data_) languageCode]; if (language_code == nil) { return std::string(); @@ -292,6 +308,7 @@ void LogHeartbeat(Auth *auth) { void Auth::set_language_code(const char *language_code) { if (!auth_data_) return; + MutexLock(auth_data_->auth_mutex); NSString *code; if (language_code != nullptr) { code = [NSString stringWithUTF8String:language_code]; @@ -301,6 +318,7 @@ void LogHeartbeat(Auth *auth) { void Auth::UseAppLanguage() { if (!auth_data_) return; + MutexLock(auth_data_->auth_mutex); [AuthImpl(auth_data_) useAppLanguage]; } @@ -315,27 +333,31 @@ AuthError AuthErrorFromNSError(NSError *_Nullable error) { } void SignInCallback(FIRUser *_Nullable user, NSError *_Nullable error, - SafeFutureHandle handle, AuthData *auth_data) { + SafeFutureHandle future_handle, ReferenceCountedFutureImpl &future_impl, + AuthData *auth_data) { User *result = AssignUser(user, auth_data); - // Finish off the asynchronous call so that the caller can read it. - ReferenceCountedFutureImpl &futures = auth_data->future_impl; - futures.CompleteWithResult(handle, AuthErrorFromNSError(error), - util::NSStringToString(error.localizedDescription).c_str(), result); + if (future_impl.ValidFuture(future_handle)) { + // Finish off the asynchronous call so that the caller can read it. + future_impl.CompleteWithResult(future_handle, AuthErrorFromNSError(error), + util::NSStringToString(error.localizedDescription).c_str(), + result); + } } void SignInResultWithProviderCallback( FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error, - SafeFutureHandle handle, AuthData *_Nonnull auth_data, - const FIROAuthProvider *_Nonnull ios_auth_provider /*unused */) { + SafeFutureHandle future_handle, ReferenceCountedFutureImpl &future_impl, + AuthData *_Nonnull auth_data, const FIROAuthProvider *_Nonnull ios_auth_provider /*unused */) { // ios_auth_provider exists as a parameter to hold a reference to the FIROAuthProvider preventing // its release by the Objective-C runtime during the asynchronous SignIn operation. error = RemapBadProviderIDErrors(error); - SignInResultCallback(auth_result, error, handle, auth_data); + SignInResultCallback(auth_result, error, future_handle, future_impl, auth_data); } void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error, - SafeFutureHandle handle, AuthData *auth_data) { + SafeFutureHandle future_handle, + ReferenceCountedFutureImpl &future_impl, AuthData *auth_data) { User *user = AssignUser(auth_result.user, auth_data); SignInResult result; @@ -355,105 +377,125 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu } } - ReferenceCountedFutureImpl &futures = auth_data->future_impl; - futures.CompleteWithResult(handle, AuthErrorFromNSError(error), - util::NSStringToString(error.localizedDescription).c_str(), result); + if (future_impl.ValidFuture(future_handle)) { + future_impl.CompleteWithResult(future_handle, AuthErrorFromNSError(error), + util::NSStringToString(error.localizedDescription).c_str(), + result); + } } -Future Auth::SignInWithCustomToken(const char *token) { - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kAuthFn_SignInWithCustomToken, nullptr); - +Future Auth::SignInWithCustomToken_DEPRECATED(const char *token) { + MutexLock(auth_data_->auth_mutex); + ReferenceCountedFutureImpl &future_impl = auth_data_->future_impl; + const auto future_handle = + future_impl.SafeAlloc(kAuthFn_SignInWithCustomToken_DEPRECATED, nullptr); + Future future = MakeFuture(&future_impl, future_handle); [AuthImpl(auth_data_) signInWithCustomToken:@(token) completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInCallback(auth_result.user, error, handle, auth_data_); + SignInCallback(auth_result.user, error, future_handle, future_impl, auth_data_); }]; - return MakeFuture(&futures, handle); + return future; } -Future Auth::SignInWithCredential(const Credential &credential) { - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kAuthFn_SignInWithCredential, nullptr); - +Future Auth::SignInWithCredential_DEPRECATED(const Credential &credential) { + MutexLock(auth_data_->auth_mutex); + ReferenceCountedFutureImpl &future_impl = auth_data_->future_impl; + const auto future_handle = + future_impl.SafeAlloc(kAuthFn_SignInWithCredential_DEPRECATED, nullptr); + Future future = MakeFuture(&future_impl, future_handle); [AuthImpl(auth_data_) signInWithCredential:CredentialFromImpl(credential.impl_) completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInCallback(auth_result.user, error, handle, auth_data_); + SignInCallback(auth_result.user, error, future_handle, future_impl, auth_data_); }]; - return MakeFuture(&futures, handle); + return future; } -Future Auth::SignInAndRetrieveDataWithCredential(const Credential &credential) { - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = - futures.SafeAlloc(kAuthFn_SignInAndRetrieveDataWithCredential, SignInResult()); - +Future Auth::SignInAndRetrieveDataWithCredential_DEPRECATED( + const Credential &credential) { + MutexLock(auth_data_->auth_mutex); + ReferenceCountedFutureImpl &future_impl = auth_data_->future_impl; + const auto future_handle = future_impl.SafeAlloc( + kAuthFn_SignInAndRetrieveDataWithCredential_DEPRECATED, SignInResult()); + Future future = MakeFuture(&future_impl, future_handle); [AuthImpl(auth_data_) signInWithCredential:CredentialFromImpl(credential.impl_) completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInResultCallback(auth_result, error, handle, auth_data_); + SignInResultCallback(auth_result, error, future_handle, future_impl, auth_data_); }]; - - return MakeFuture(&futures, handle); + return future; } -Future Auth::SignInWithProvider(FederatedAuthProvider *provider) { +Future Auth::SignInWithProvider_DEPRECATED(FederatedAuthProvider *provider) { FIREBASE_ASSERT_RETURN(Future(), provider); return provider->SignIn(auth_data_); } -Future Auth::SignInAnonymously() { - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = auth_data_->future_impl.SafeAlloc(kAuthFn_SignInAnonymously, nullptr); - +Future Auth::SignInAnonymously_DEPRECATED() { + MutexLock(auth_data_->auth_mutex); + ReferenceCountedFutureImpl &future_impl = auth_data_->future_impl; + const auto future_handle = + auth_data_->future_impl.SafeAlloc(kAuthFn_SignInAnonymously_DEPRECATED, nullptr); + Future future = MakeFuture(&future_impl, future_handle); [AuthImpl(auth_data_) signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInCallback(auth_result.user, error, handle, auth_data_); + SignInCallback(auth_result.user, error, future_handle, future_impl, auth_data_); }]; - - return MakeFuture(&futures, handle); + return future; } -Future Auth::SignInWithEmailAndPassword(const char *email, const char *password) { - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kAuthFn_SignInWithEmailAndPassword, nullptr); +Future Auth::SignInWithEmailAndPassword_DEPRECATED(const char *email, + const char *password) { + MutexLock(auth_data_->auth_mutex); + ReferenceCountedFutureImpl &future_impl = auth_data_->future_impl; + const auto future_handle = + future_impl.SafeAlloc(kAuthFn_SignInWithEmailAndPassword_DEPRECATED, nullptr); + Future future = MakeFuture(&future_impl, future_handle); if (!email || strlen(email) == 0) { - futures.Complete(handle, kAuthErrorMissingEmail, "Empty email is not allowed."); + future_impl.Complete(future_handle, kAuthErrorMissingEmail, "Empty email is not allowed."); } else if (!password || strlen(password) == 0) { - futures.Complete(handle, kAuthErrorMissingPassword, "Empty password is not allowed."); + future_impl.Complete(future_handle, kAuthErrorMissingPassword, + "Empty password is not allowed."); } else { [AuthImpl(auth_data_) signInWithEmail:@(email) password:@(password) completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInCallback(auth_result.user, error, handle, auth_data_); + SignInCallback(auth_result.user, error, future_handle, future_impl, auth_data_); }]; } - return MakeFuture(&futures, handle); + return future; } -Future Auth::CreateUserWithEmailAndPassword(const char *email, const char *password) { - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kAuthFn_CreateUserWithEmailAndPassword, nullptr); +Future Auth::CreateUserWithEmailAndPassword_DEPRECATED(const char *email, + const char *password) { + MutexLock(auth_data_->auth_mutex); + ReferenceCountedFutureImpl &future_impl = auth_data_->future_impl; + const auto future_handle = + future_impl.SafeAlloc(kAuthFn_CreateUserWithEmailAndPassword_DEPRECATED, nullptr); + Future future = MakeFuture(&future_impl, future_handle); if (!email || strlen(email) == 0) { - futures.Complete(handle, kAuthErrorMissingEmail, "Empty email is not allowed."); + future_impl.Complete(future_handle, kAuthErrorMissingEmail, + kErrorEmptyEmailPasswordErrorMessage); } else if (!password || strlen(password) == 0) { - futures.Complete(handle, kAuthErrorMissingPassword, "Empty password is not allowed."); + future_impl.Complete(future_handle, kAuthErrorMissingPassword, + kErrorEmptyEmailPasswordErrorMessage); } else { [AuthImpl(auth_data_) createUserWithEmail:@(email) password:@(password) completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInCallback(auth_result.user, error, handle, auth_data_); + SignInCallback(auth_result.user, error, future_handle, future_impl, auth_data_); }]; } - return MakeFuture(&futures, handle); + return future; } void Auth::SignOut() { + MutexLock(auth_data_->auth_mutex); // TODO(jsanmiya): Verify with iOS team why this returns an error. NSError *_Nullable error; [AuthImpl(auth_data_) signOut:&error]; @@ -461,16 +503,17 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu } Future Auth::SendPasswordResetEmail(const char *email) { - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kAuthFn_SendPasswordResetEmail); - - [AuthImpl(auth_data_) sendPasswordResetWithEmail:@(email) - completion:^(NSError *_Nullable error) { - futures.Complete(handle, AuthErrorFromNSError(error), - [error.localizedDescription UTF8String]); - }]; - - return MakeFuture(&futures, handle); + MutexLock(auth_data_->auth_mutex); + ReferenceCountedFutureImpl &future_impl = auth_data_->future_impl; + const auto future_handle = future_impl.SafeAlloc(kAuthFn_SendPasswordResetEmail); + Future future = MakeFuture(&future_impl, future_handle); + [AuthImpl(auth_data_) + sendPasswordResetWithEmail:@(email) + completion:^(NSError *_Nullable error) { + future_impl.Complete(future_handle, AuthErrorFromNSError(error), + [error.localizedDescription UTF8String]); + }]; + return future; } // Remap iOS SDK errors reported by the UIDelegate. While these errors seem like diff --git a/auth/src/ios/common_ios.h b/auth/src/ios/common_ios.h index d6d471e811..4f9f655218 100644 --- a/auth/src/ios/common_ios.h +++ b/auth/src/ios/common_ios.h @@ -26,9 +26,13 @@ #import "FIRUserInfo.h" #import "FIRUserMetadata.h" +#include +#include + #include "app/src/log.h" #include "app/src/util_ios.h" #include "auth/src/common.h" +#include "auth/src/include/firebase/auth.h" #include "auth/src/include/firebase/auth/user.h" @class FIRCPPAuthListenerHandle; @@ -44,31 +48,133 @@ OBJ_C_PTR_WRAPPER(FIRAuthCredential); OBJ_C_PTR_WRAPPER(FIRUser); OBJ_C_PTR_WRAPPER(FIRCPPAuthListenerHandle); +// Synchronize the current user. +void UpdateCurrentUser(AuthData *auth_data); + // Auth implementation on iOS. struct AuthDataIos { FIRAuthPointer fir_auth; FIRCPPAuthListenerHandlePointer listener_handle; }; -/// Convert from the platform-independent void* to the Obj-C FIRUser pointer. -static inline FIRUser *_Nullable UserImpl(AuthData *_Nonnull auth_data) { - return FIRUserPointer::SafeGet(static_cast(auth_data->user_impl)); -} +// Struct to contain the data required to complete +// futures asynchronously on iOS. +template +struct FutureCallbackData { + FutureData *future_data; + SafeFutureHandle future_handle; +}; + +// Contains the interface between the public API and the underlying +// Obj-C SDK FirebaseUser implemention. +class UserInternal { + public: + // Constructor + explicit UserInternal(FIRUser *user); + + // Copy constructor. + UserInternal(const UserInternal &user_internal); + + ~UserInternal(); + + // @deprecated + // + // Provides a mechanism for the deprecated auth-contained user object to + // update its underlying FIRUser data. + void set_native_user_object_deprecated(FIRUser *user); + + bool is_valid() const; + + Future GetToken(bool force_refresh); + Future GetTokenLastResult() const; + + Future UpdateEmail(const char *email); + Future UpdateEmailLastResult() const; + + std::vector provider_data() const; + const std::vector &provider_data_DEPRECATED(); + + Future UpdatePassword(const char *password); + Future UpdatePasswordLastResult() const; + + Future UpdateUserProfile(const User::UserProfile &profile); + Future UpdateUserProfileLastResult() const; + + Future SendEmailVerification(); + Future SendEmailVerificationLastResult() const; + + Future LinkWithCredential_DEPRECATED(AuthData *auth_data, const Credential &credential); + Future LinkWithCredentialLastResult_DEPRECATED() const; -/// Release the platform-dependent FIRUser object. -static inline void SetUserImpl(AuthData *_Nonnull auth_data, FIRUser *_Nullable user) { - MutexLock lock(auth_data->future_impl.mutex()); + Future LinkAndRetrieveDataWithCredential_DEPRECATED(AuthData *auth_data_, + const Credential &credential); + Future LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED() const; - // Delete existing pointer to FIRUser. - if (auth_data->user_impl != nullptr) { - delete static_cast(auth_data->user_impl); - auth_data->user_impl = nullptr; - } + Future LinkWithProvider_DEPRECATED(AuthData *auth_data, + FederatedAuthProvider *provider); + Future LinkWithProviderLastResult_DEPRECATED() const; + + Future Unlink_DEPRECATED(AuthData *auth_data, const char *provider); + Future UnlinkLastResult_DEPRECATED() const; + + Future UpdatePhoneNumberCredential_DEPRECATED(AuthData *auth_data, + const Credential &credential); + Future UpdatePhoneNumberCredentialLastResult_DEPRECATED() const; + + Future Reload(); + Future ReloadLastResult() const; + + Future Reauthenticate(const Credential &credential); + Future ReauthenticateLastResult() const; + + Future ReauthenticateAndRetrieveData_DEPRECATED(AuthData *auth_data, + const Credential &credential); + Future ReauthenticateAndRetrieveDataLastResult_DEPRECATED() const; + + Future ReauthenticateWithProvider_DEPRECATED(AuthData *auth_data, + FederatedAuthProvider *provider); + Future ReauthenticateWithProviderLastResult_DEPRECATED() const; + + Future Delete(AuthData *auth_data); + Future DeleteLastResult() const; + + UserMetadata metadata() const; + bool is_email_verified() const; + bool is_anonymous() const; + std::string uid() const; + std::string email() const; + std::string display_name() const; + std::string phone_number() const; + std::string photo_url() const; + std::string provider_id() const; + + private: + friend class firebase::auth::FederatedOAuthProvider; + friend class firebase::auth::User; + + void clear_user_infos(); + + // Obj-c Implementation of a User object. + FIRUser *user_; + + // Future data used to synchronize asynchronous calls. + FutureData future_data_; + + // Used to support older method invocation of provider_data_DEPRECATED(). + std::vector user_infos_; + + // Guard against changes to the user_ object. + Mutex user_mutex_; +}; - // Create new pointer to FIRUser. - if (user != nullptr) { - auth_data->user_impl = new FIRUserPointer(user); - } +/// @deprecated +/// +/// Replace the platform-dependent FIRUser object. +/// Note: this function is only used to support DEPRECATED methods which return User*. This +/// functionality should be removed when those deprecated methods are removed. +static inline void SetUserImpl(AuthData *_Nonnull auth_data, FIRUser *_Nullable ios_user) { + auth_data->deprecated_fields.user_internal_deprecated->set_native_user_object_deprecated( + ios_user); } /// Convert from the platform-independent void* to the Obj-C FIRAuth pointer. @@ -87,12 +193,14 @@ AuthError AuthErrorFromNSError(NSError *_Nullable error); /// Common code for all API calls that return a User*. /// Initialize `auth_data->current_user` and complete the `future`. void SignInCallback(FIRUser *_Nullable user, NSError *_Nullable error, - SafeFutureHandle handle, AuthData *_Nonnull auth_data); + SafeFutureHandle handle, ReferenceCountedFutureImpl &future_impl, + AuthData *_Nonnull auth_data); /// Common code for all API calls that return a SignInResult. /// Initialize `auth_data->current_user` and complete the `future`. void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error, - SafeFutureHandle handle, AuthData *_Nonnull auth_data); + SafeFutureHandle handle, + ReferenceCountedFutureImpl &future_impl, AuthData *_Nonnull auth_data); /// Common code for all FederatedOAuth API calls which return a SignInResult and /// must hold a reference to a FIROAuthProvider so that the provider is not @@ -101,6 +209,7 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu void SignInResultWithProviderCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error, SafeFutureHandle handle, + ReferenceCountedFutureImpl &future_impl, AuthData *_Nonnull auth_data, const FIROAuthProvider *_Nonnull ios_auth_provider); diff --git a/auth/src/ios/credential_ios.mm b/auth/src/ios/credential_ios.mm index 5c271f907c..5fbade9c73 100644 --- a/auth/src/ios/credential_ios.mm +++ b/auth/src/ios/credential_ios.mm @@ -170,10 +170,12 @@ @implementation PhoneListenerDataObjC // static Future GameCenterAuthProvider::GetCredential() { - auto future_api = GetCredentialFutureImpl(); - FIREBASE_ASSERT(future_api != nullptr); + ReferenceCountedFutureImpl* future_impl = GetCredentialFutureImpl(); + FIREBASE_ASSERT(future_impl != nullptr); + const auto future_handle = + future_impl->SafeAlloc(kCredentialFn_GameCenterGetCredential); + Future future = MakeFuture(future_impl, future_handle); - const auto handle = future_api->SafeAlloc(kCredentialFn_GameCenterGetCredential); /** Linking GameKit.framework without using it on macOS results in App Store rejection. Thus we don't link GameKit.framework to our SDK directly. `optionalLocalPlayer` is used for @@ -184,20 +186,19 @@ @implementation PhoneListenerDataObjC // Early-out if GameKit is not linked if (!optionalLocalPlayer) { - future_api->Complete(handle, kAuthErrorInvalidCredential, - "GameCenter authentication is unavailable - missing GameKit capability."); - return MakeFuture(future_api, handle); + future_impl->Complete(future_handle, kAuthErrorInvalidCredential, + "GameCenter authentication is unavailable - missing GameKit capability."); + } else { + [FIRGameCenterAuthProvider + getCredentialWithCompletion:^(FIRAuthCredential* _Nullable credential, + NSError* _Nullable error) { + Credential result(new FIRAuthCredentialPointer(credential)); + future_impl->CompleteWithResult( + future_handle, AuthErrorFromNSError(error), + util::NSStringToString(error.localizedDescription).c_str(), result); + }]; } - - [FIRGameCenterAuthProvider getCredentialWithCompletion:^(FIRAuthCredential* _Nullable credential, - NSError* _Nullable error) { - Credential result(new FIRAuthCredentialPointer(credential)); - future_api->CompleteWithResult(handle, AuthErrorFromNSError(error), - util::NSStringToString(error.localizedDescription).c_str(), - result); - }]; - - return MakeFuture(future_api, handle); + return future; } // static @@ -407,22 +408,21 @@ explicit PhoneAuthProviderData(FIRPhoneAuthProvider* objc_provider) // current API. void LinkWithProviderGetCredentialCallback(FIRAuthCredential* _Nullable credential, NSError* _Nullable error, - SafeFutureHandle handle, - AuthData* auth_data, + SafeFutureHandle future_handle, + ReferenceCountedFutureImpl& future_impl, + AuthData* auth_data, FIRUser* user, const FIROAuthProvider* ios_auth_provider) { if (error && error.code != 0) { - ReferenceCountedFutureImpl& futures = auth_data->future_impl; error = RemapBadProviderIDErrors(error); - futures.CompleteWithResult(handle, AuthErrorFromNSError(error), - util::NSStringToString(error.localizedDescription).c_str(), - SignInResult()); + future_impl.CompleteWithResult(future_handle, AuthErrorFromNSError(error), + util::NSStringToString(error.localizedDescription).c_str(), + SignInResult()); } else { - [UserImpl(auth_data) - linkWithCredential:credential - completion:^(FIRAuthDataResult* _Nullable auth_result, NSError* _Nullable error) { - SignInResultWithProviderCallback(auth_result, error, handle, auth_data, - ios_auth_provider); - }]; + [user linkWithCredential:credential + completion:^(FIRAuthDataResult* _Nullable auth_result, NSError* _Nullable error) { + SignInResultWithProviderCallback(auth_result, error, future_handle, future_impl, + auth_data, ios_auth_provider); + }]; } } @@ -431,30 +431,33 @@ void LinkWithProviderGetCredentialCallback(FIRAuthCredential* _Nullable credenti // accessible via their current API. void ReauthenticateWithProviderGetCredentialCallback(FIRAuthCredential* _Nullable credential, NSError* _Nullable error, - SafeFutureHandle handle, - AuthData* auth_data, + SafeFutureHandle future_handle, + ReferenceCountedFutureImpl& future_impl, + AuthData* auth_data, FIRUser* user, const FIROAuthProvider* ios_auth_provider) { if (error && error.code != 0) { - ReferenceCountedFutureImpl& futures = auth_data->future_impl; error = RemapBadProviderIDErrors(error); - futures.CompleteWithResult(handle, AuthErrorFromNSError(error), - util::NSStringToString(error.localizedDescription).c_str(), - SignInResult()); + future_impl.CompleteWithResult(future_handle, AuthErrorFromNSError(error), + util::NSStringToString(error.localizedDescription).c_str(), + SignInResult()); } else { - [UserImpl(auth_data) - reauthenticateWithCredential:credential - completion:^(FIRAuthDataResult* _Nullable auth_result, - NSError* _Nullable error) { - SignInResultWithProviderCallback(auth_result, error, handle, auth_data, - ios_auth_provider); - }]; + [user reauthenticateWithCredential:credential + completion:^(FIRAuthDataResult* _Nullable auth_result, + NSError* _Nullable error) { + SignInResultWithProviderCallback(auth_result, error, future_handle, + future_impl, auth_data, + ios_auth_provider); + }]; } } Future FederatedOAuthProvider::SignIn(AuthData* auth_data) { assert(auth_data); - ReferenceCountedFutureImpl& futures = auth_data->future_impl; - const auto handle = futures.SafeAlloc(kAuthFn_SignInWithProvider, SignInResult()); + ReferenceCountedFutureImpl& future_impl = auth_data->future_impl; + const auto future_handle = + future_impl.SafeAlloc(kAuthFn_SignInWithProvider_DEPRECATED, SignInResult()); + Future future = MakeFuture(&future_impl, future_handle); + FIROAuthProvider* ios_provider = (FIROAuthProvider*)[FIROAuthProvider providerWithProviderID:@(provider_data_.provider_id.c_str()) auth:AuthImpl(auth_data)]; @@ -465,22 +468,25 @@ void ReauthenticateWithProviderGetCredentialCallback(FIRAuthCredential* _Nullabl signInWithProvider:ios_provider UIDelegate:nullptr completion:^(FIRAuthDataResult* _Nullable auth_result, NSError* _Nullable error) { - SignInResultWithProviderCallback(auth_result, error, handle, auth_data, - ios_provider); + SignInResultWithProviderCallback(auth_result, error, future_handle, future_impl, + auth_data, ios_provider); }]; - return MakeFuture(&futures, handle); } else { - Future future = MakeFuture(&futures, handle); - futures.CompleteWithResult(handle, kAuthErrorFailure, "Internal error constructing provider.", - SignInResult()); - return future; + future_impl.CompleteWithResult(future_handle, kAuthErrorFailure, + "Internal error constructing provider.", SignInResult()); } + return future; } -Future FederatedOAuthProvider::Link(AuthData* auth_data) { +Future FederatedOAuthProvider::Link(AuthData* auth_data, + UserInternal* user_internal) { assert(auth_data); - ReferenceCountedFutureImpl& futures = auth_data->future_impl; - auto handle = futures.SafeAlloc(kUserFn_LinkWithProvider, SignInResult()); + assert(user_internal); + ReferenceCountedFutureImpl& future_impl = user_internal->future_data_.future_impl; + auto future_handle = + future_impl.SafeAlloc(kUserFn_LinkWithProvider_DEPRECATED, SignInResult()); + Future future = MakeFuture(&future_impl, future_handle); + #if FIREBASE_PLATFORM_IOS FIROAuthProvider* ios_provider = (FIROAuthProvider*)[FIROAuthProvider providerWithProviderID:@(provider_data_.provider_id.c_str()) @@ -488,33 +494,39 @@ void ReauthenticateWithProviderGetCredentialCallback(FIRAuthCredential* _Nullabl if (ios_provider != nullptr) { ios_provider.customParameters = util::StringMapToNSDictionary(provider_data_.custom_parameters); ios_provider.scopes = util::StringVectorToNSMutableArray(provider_data_.scopes); + FIRUser* user = user_internal->user_; // TODO(b/138788092) invoke FIRUser linkWithProvider instead, once that method is added to the // iOS SDK. [ios_provider getCredentialWithUIDelegate:nullptr completion:^(FIRAuthCredential* _Nullable credential, NSError* _Nullable error) { LinkWithProviderGetCredentialCallback( - credential, error, handle, auth_data, ios_provider); + credential, error, future_handle, + user_internal->future_data_.future_impl, auth_data, user, + ios_provider); }]; - return MakeFuture(&futures, handle); } else { - Future future = MakeFuture(&futures, handle); - futures.CompleteWithResult(handle, kAuthErrorFailure, "Internal error constructing provider.", - SignInResult()); - return future; + future_impl.CompleteWithResult(future_handle, kAuthErrorFailure, + "Internal error constructing provider.", SignInResult()); } #else // non-iOS Apple platforms (eg: tvOS) - Future future = MakeFuture(&futures, handle); - futures.Complete(handle, kAuthErrorApiNotAvailable, - "OAuth provider linking is not supported on non-iOS Apple platforms."); + future_impl.CompleteWithResult( + future_handle, kAuthErrorApiNotAvailable, + "OAuth provider linking is not supported on non-iOS Apple platforms.", SignInResult()); #endif // FIREBASE_PLATFORM_IOS + return future; } -Future FederatedOAuthProvider::Reauthenticate(AuthData* auth_data) { +Future FederatedOAuthProvider::Reauthenticate(AuthData* auth_data, + UserInternal* user_internal) { assert(auth_data); - ReferenceCountedFutureImpl& futures = auth_data->future_impl; - auto handle = futures.SafeAlloc(kUserFn_LinkWithProvider, SignInResult()); + assert(user_internal); + ReferenceCountedFutureImpl& future_impl = user_internal->future_data_.future_impl; + auto future_handle = future_impl.SafeAlloc( + kUserFn_ReauthenticateWithProvider_DEPRECATED, SignInResult()); + Future future = MakeFuture(&future_impl, future_handle); + #if FIREBASE_PLATFORM_IOS FIROAuthProvider* ios_provider = (FIROAuthProvider*)[FIROAuthProvider providerWithProviderID:@(provider_data_.provider_id.c_str()) @@ -522,27 +534,26 @@ void ReauthenticateWithProviderGetCredentialCallback(FIRAuthCredential* _Nullabl if (ios_provider != nullptr) { ios_provider.customParameters = util::StringMapToNSDictionary(provider_data_.custom_parameters); ios_provider.scopes = util::StringVectorToNSMutableArray(provider_data_.scopes); + FIRUser* user = user_internal->user_; // TODO(b/138788092) invoke FIRUser:reuthenticateWithProvider instead, once that method is added // to the iOS SDK. [ios_provider getCredentialWithUIDelegate:nullptr completion:^(FIRAuthCredential* _Nullable credential, NSError* _Nullable error) { ReauthenticateWithProviderGetCredentialCallback( - credential, error, handle, auth_data, ios_provider); + credential, error, future_handle, future_impl, auth_data, + user, ios_provider); }]; - return MakeFuture(&futures, handle); } else { - Future future = MakeFuture(&futures, handle); - futures.CompleteWithResult(handle, kAuthErrorFailure, "Internal error constructing provider.", - SignInResult()); - return future; + future_impl.CompleteWithResult(future_handle, kAuthErrorFailure, + "Internal error constructing provider.", SignInResult()); } - #else // non-iOS Apple platforms (eg: tvOS) - Future future = MakeFuture(&futures, handle); - futures.Complete(handle, kAuthErrorApiNotAvailable, - "OAuth reauthentication is not supported on non-iOS Apple platforms."); + future_impl.CompleteWithResult( + future_handle, kAuthErrorApiNotAvailable, + "OAuth reauthentication is not supported on non-iOS Apple platforms.", SignInResult()); #endif // FIREBASE_PLATFORM_IOS + return future; } } // namespace auth diff --git a/auth/src/ios/user_ios.mm b/auth/src/ios/user_ios.mm index e4c3817440..6882b3e6f8 100644 --- a/auth/src/ios/user_ios.mm +++ b/auth/src/ios/user_ios.mm @@ -19,6 +19,7 @@ #if FIREBASE_PLATFORM_IOS #import "FIRPhoneAuthCredential.h" +#import "FIRUser.h" #endif namespace firebase { @@ -29,108 +30,417 @@ const char kInvalidCredentialMessage[] = "Credential is not a phone credential."; +/// +/// User Class +/// Platform specific implementation +/// +User::User(AuthData *auth_data, UserInternal *user_internal) { + assert(auth_data); + auth_data_ = auth_data; + if (user_internal == nullptr) { + // Create an invalid user internal. + // This will return is_valid() false, and operations will fail. + user_internal_ = new UserInternal(nullptr); + } else { + user_internal_ = user_internal; + } +} + +User::User(const User &user) { + assert(user.auth_data_); + auth_data_ = user.auth_data_; + if (user.user_internal_ == nullptr) { + // Create an invalid user internal. + // This will return is_valid() false, and operations will fail. + user_internal_ = new UserInternal(nullptr); + } else { + user_internal_ = new UserInternal(user.user_internal_->user_); + } +} + +User::~User() { + delete user_internal_; + user_internal_ = nullptr; + auth_data_ = nullptr; +} + +User &User::operator=(const User &user) { + assert(user_internal_); + delete user_internal_; + if (user.user_internal_ != nullptr) { + user_internal_ = new UserInternal(user.user_internal_->user_); + } else { + user_internal_ = new UserInternal(nullptr); + } + auth_data_ = user.auth_data_; + return *this; +} + +bool User::is_valid() const { + assert(user_internal_); + return user_internal_->is_valid(); +} + +Future User::GetToken(bool force_refresh) { + assert(user_internal_); + return user_internal_->GetToken(force_refresh); +} + +std::vector User::provider_data() const { + assert(user_internal_); + return user_internal_->provider_data(); +} + +const std::vector &User::provider_data_DEPRECATED() { + assert(user_internal_); + return user_internal_->provider_data_DEPRECATED(); +} + +Future User::UpdateEmail(const char *email) { + assert(user_internal_); + return user_internal_->UpdateEmail(email); +} + +Future User::UpdateEmailLastResult() const { + assert(user_internal_); + return user_internal_->UpdateEmailLastResult(); +} + +Future User::UpdatePassword(const char *password) { + assert(user_internal_); + return user_internal_->UpdatePassword(password); +} + +Future User::UpdatePasswordLastResult() const { + assert(user_internal_); + return user_internal_->UpdatePasswordLastResult(); +} + +Future User::Reauthenticate(const Credential &credential) { + assert(user_internal_); + return user_internal_->Reauthenticate(credential); +} + +Future User::ReauthenticateLastResult() const { + assert(user_internal_); + return user_internal_->ReauthenticateLastResult(); +} + +Future User::ReauthenticateAndRetrieveData_DEPRECATED(const Credential &credential) { + assert(user_internal_); + return user_internal_->ReauthenticateAndRetrieveData_DEPRECATED(auth_data_, credential); +} + +Future User::ReauthenticateAndRetrieveDataLastResult_DEPRECATED() const { + assert(user_internal_); + return user_internal_->ReauthenticateAndRetrieveDataLastResult_DEPRECATED(); +} + +Future User::ReauthenticateWithProvider_DEPRECATED( + FederatedAuthProvider *provider) const { + assert(user_internal_); + return user_internal_->ReauthenticateWithProvider_DEPRECATED(auth_data_, provider); +} + +Future User::SendEmailVerification() { + assert(user_internal_); + return user_internal_->SendEmailVerification(); +} + +Future User::SendEmailVerificationLastResult() const { + assert(user_internal_); + return user_internal_->SendEmailVerificationLastResult(); +} + +Future User::UpdateUserProfile(const UserProfile &profile) { + assert(user_internal_); + return user_internal_->UpdateUserProfile(profile); +} + +Future User::UpdateUserProfileLastResult() const { + assert(user_internal_); + return user_internal_->UpdateUserProfileLastResult(); +} + +Future User::LinkWithCredential_DEPRECATED(const Credential &credential) { + assert(user_internal_); + return user_internal_->LinkWithCredential_DEPRECATED(auth_data_, credential); +} + +Future User::LinkWithCredentialLastResult_DEPRECATED() const { + assert(user_internal_); + return user_internal_->LinkWithCredentialLastResult_DEPRECATED(); +} + +Future User::LinkAndRetrieveDataWithCredential_DEPRECATED( + const Credential &credential) { + assert(user_internal_); + return user_internal_->LinkAndRetrieveDataWithCredential_DEPRECATED(auth_data_, credential); +} + +Future User::LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED() const { + assert(user_internal_); + return user_internal_->LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED(); +} + +Future User::LinkWithProvider_DEPRECATED(FederatedAuthProvider *provider) { + assert(user_internal_); + return user_internal_->LinkWithProvider_DEPRECATED(auth_data_, provider); +} + +Future User::Unlink_DEPRECATED(const char *provider) { + assert(user_internal_); + return user_internal_->Unlink_DEPRECATED(auth_data_, provider); +} + +Future User::UnlinkLastResult_DEPRECATED() const { + assert(user_internal_); + return user_internal_->UnlinkLastResult_DEPRECATED(); +} + +Future User::UpdatePhoneNumberCredential_DEPRECATED(const Credential &credential) { + assert(user_internal_); + return user_internal_->UpdatePhoneNumberCredential_DEPRECATED(auth_data_, credential); +} + +Future User::Reload() { + assert(user_internal_); + return user_internal_->Reload(); +} + +Future User::ReloadLastResult() const { + assert(user_internal_); + return user_internal_->ReloadLastResult(); +} + +Future User::Delete() { + assert(user_internal_); + return user_internal_->Delete(auth_data_); +} + +Future User::DeleteLastResult() const { + assert(user_internal_); + return user_internal_->DeleteLastResult(); +} + +UserMetadata User::metadata() const { + assert(user_internal_); + return user_internal_->metadata(); +} + +bool User::is_email_verified() const { + assert(user_internal_); + return user_internal_->is_email_verified(); +} + +bool User::is_anonymous() const { + assert(user_internal_); + return user_internal_->is_anonymous(); +} + +std::string User::uid() const { + assert(user_internal_); + return user_internal_->uid(); +} + +std::string User::email() const { + assert(user_internal_); + return user_internal_->email(); +} + +std::string User::display_name() const { + assert(user_internal_); + return user_internal_->display_name(); +} + +std::string User::photo_url() const { + assert(user_internal_); + return user_internal_->photo_url(); +} + +std::string User::provider_id() const { + assert(user_internal_); + return user_internal_->provider_id(); +} + +std::string User::phone_number() const { + assert(user_internal_); + return user_internal_->phone_number(); +} + +/// +/// IOSWrapperUserInfo Class +/// class IOSWrappedUserInfo : public UserInfoInterface { public: explicit IOSWrappedUserInfo(id user_info) : user_info_(user_info) {} virtual ~IOSWrappedUserInfo() { user_info_ = nil; } - virtual std::string uid() const { return StringFromNSString(user_info_.uid); } + std::string uid() const override { return StringFromNSString(user_info_.uid); } - virtual std::string email() const { return StringFromNSString(user_info_.email); } + std::string email() const override { return StringFromNSString(user_info_.email); } - virtual std::string display_name() const { return StringFromNSString(user_info_.displayName); } + std::string display_name() const override { return StringFromNSString(user_info_.displayName); } - virtual std::string phone_number() const { return StringFromNSString(user_info_.phoneNumber); } + std::string phone_number() const override { return StringFromNSString(user_info_.phoneNumber); } - virtual std::string photo_url() const { return StringFromNSUrl(user_info_.photoURL); } + std::string photo_url() const override { return StringFromNSUrl(user_info_.photoURL); } - virtual std::string provider_id() const { return StringFromNSString(user_info_.providerID); } + std::string provider_id() const override { return StringFromNSString(user_info_.providerID); } private: - /// Pointer to the main class. - /// Needed for context in implementation of virtuals. id user_info_; }; -User::~User() { +/// +/// UserInternal Class +/// +UserInternal::UserInternal(FIRUser *user) : user_(user), future_data_(kUserFnCount) {} + +UserInternal::UserInternal(const UserInternal &user_internal) + : user_(user_internal.user_), future_data_(kUserFnCount) {} + +UserInternal::~UserInternal() { + MutexLock user_info_lock(user_mutex_); // Make sure we don't have any pending futures in flight before we disappear. - while (!auth_data_->future_impl.IsSafeToDelete()) { + while (!future_data_.future_impl.IsSafeToDelete()) { internal::Sleep(100); } + user_ = nil; + clear_user_infos(); } -Future User::GetToken(bool force_refresh) { - if (!ValidUser(auth_data_)) { - return Future(); +void UserInternal::set_native_user_object_deprecated(FIRUser *user) { + MutexLock user_info_lock(user_mutex_); + user_ = user; +} + +bool UserInternal::is_valid() const { return user_ != nil; } + +void UserInternal::clear_user_infos() { + for (size_t i = 0; i < user_infos_.size(); ++i) { + delete user_infos_[i]; + user_infos_[i] = nullptr; + } + user_infos_.clear(); +} + +Future UserInternal::GetToken(bool force_refresh) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_GetToken, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_, ""); + } + + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc(kUserFn_GetToken)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ getIDTokenForcingRefresh:force_refresh + completion:^(NSString *_Nullable token, NSError *_Nullable error) { + callback_data->future_data->future_impl.Complete( + callback_data->future_handle, AuthErrorFromNSError(error), + [error.localizedDescription UTF8String], [token](std::string *data) { + data->assign(token == nullptr ? "" : [token UTF8String]); + }); + delete callback_data; + }]; + return future; +} + +std::vector UserInternal::provider_data() const { + std::vector local_user_infos; + if (is_valid()) { + NSArray> *provider_data = user_.providerData; + local_user_infos.resize(provider_data.count); + for (size_t i = 0; i < provider_data.count; ++i) { + local_user_infos[i] = IOSWrappedUserInfo(provider_data[i]); + } } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_GetToken); - [UserImpl(auth_data_) - getIDTokenForcingRefresh:force_refresh - completion:^(NSString *_Nullable token, NSError *_Nullable error) { - futures.Complete(handle, AuthErrorFromNSError(error), - [error.localizedDescription UTF8String], - [token](std::string *data) { - data->assign(token == nullptr ? "" : [token UTF8String]); - }); - }]; - return MakeFuture(&futures, handle); -} - -const std::vector &User::provider_data() const { - ClearUserInfos(auth_data_); - - if (ValidUser(auth_data_)) { - NSArray> *provider_data = UserImpl(auth_data_).providerData; - - // Wrap the FIRUserInfos in our IOSWrappedUserInfo class. - auth_data_->user_infos.resize(provider_data.count); + return local_user_infos; +} + +const std::vector &UserInternal::provider_data_DEPRECATED() { + MutexLock user_info_lock(user_mutex_); + clear_user_infos(); + if (is_valid()) { + NSArray> *provider_data = user_.providerData; + user_infos_.resize(provider_data.count); for (size_t i = 0; i < provider_data.count; ++i) { - auth_data_->user_infos[i] = new IOSWrappedUserInfo(provider_data[i]); + user_infos_[i] = new IOSWrappedUserInfo(provider_data[i]); } } // Return a reference to our internally-backed values. - return auth_data_->user_infos; + return user_infos_; } -Future User::UpdateEmail(const char *email) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::UpdateEmail(const char *email) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_UpdateEmail, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_UpdateEmail); - [UserImpl(auth_data_) updateEmail:@(email) - completion:^(NSError *_Nullable error) { - futures.Complete(handle, AuthErrorFromNSError(error), - [error.localizedDescription UTF8String]); - }]; - return MakeFuture(&futures, handle); + + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc(kUserFn_UpdateEmail)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ updateEmail:@(email) + completion:^(NSError *_Nullable error) { + callback_data->future_data->future_impl.Complete( + callback_data->future_handle, AuthErrorFromNSError(error), + [error.localizedDescription UTF8String]); + delete callback_data; + }]; + return future; } -Future User::UpdatePassword(const char *password) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::UpdateEmailLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_UpdateEmail)); +} + +Future UserInternal::UpdatePassword(const char *password) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_UpdatePassword, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_UpdatePassword); - [UserImpl(auth_data_) updatePassword:@(password) - completion:^(NSError *_Nullable error) { - futures.Complete(handle, AuthErrorFromNSError(error), - [error.localizedDescription UTF8String]); - }]; - return MakeFuture(&futures, handle); + + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc(kUserFn_UpdatePassword)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ updatePassword:@(password) + completion:^(NSError *_Nullable error) { + callback_data->future_data->future_impl.Complete( + callback_data->future_handle, AuthErrorFromNSError(error), + [error.localizedDescription UTF8String]); + delete callback_data; + }]; + return future; } -Future User::UpdateUserProfile(const UserProfile &profile) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::UpdatePasswordLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_UpdatePassword)); +} + +Future UserInternal::UpdateUserProfile(const User::UserProfile &profile) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_UpdateUserProfile, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_UpdateUserProfile); + + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc(kUserFn_UpdateUserProfile)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + // Create and populate the change request. - FIRUserProfileChangeRequest *request = [UserImpl(auth_data_) profileChangeRequest]; + FIRUserProfileChangeRequest *request = [user_ profileChangeRequest]; if (profile.display_name != nullptr) { request.displayName = @(profile.display_name); } @@ -143,173 +453,332 @@ explicit IOSWrappedUserInfo(id user_info) : user_info_(user_info) { // Execute the change request. [request commitChangesWithCompletion:^(NSError *_Nullable error) { - futures.Complete(handle, AuthErrorFromNSError(error), [error.localizedDescription UTF8String]); + callback_data->future_data->future_impl.Complete(callback_data->future_handle, + AuthErrorFromNSError(error), + [error.localizedDescription UTF8String]); + delete callback_data; }]; - return MakeFuture(&futures, handle); + return future; } -Future User::SendEmailVerification() { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::UpdateUserProfileLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_UpdateUserProfile)); +} + +Future UserInternal::SendEmailVerification() { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_SendEmailVerification, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_SendEmailVerification); - [UserImpl(auth_data_) sendEmailVerificationWithCompletion:^(NSError *_Nullable error) { - futures.Complete(handle, AuthErrorFromNSError(error), [error.localizedDescription UTF8String]); + + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc(kUserFn_SendEmailVerification)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ sendEmailVerificationWithCompletion:^(NSError *_Nullable error) { + callback_data->future_data->future_impl.Complete(callback_data->future_handle, + AuthErrorFromNSError(error), + [error.localizedDescription UTF8String]); + delete callback_data; }]; - return MakeFuture(&futures, handle); + return future; +} + +Future UserInternal::SendEmailVerificationLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_SendEmailVerification)); } -Future User::LinkWithCredential(const Credential &credential) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::LinkWithCredential_DEPRECATED(AuthData *auth_data, + const Credential &credential) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_LinkWithCredential_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, future_handle, + &future_data_, (User *)nullptr); + return future; } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_LinkWithCredential); - [UserImpl(auth_data_) - linkWithCredential:CredentialFromImpl(credential.impl_) - completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInCallback(auth_result.user, error, handle, auth_data_); - }]; - return MakeFuture(&futures, handle); -} - -Future User::LinkAndRetrieveDataWithCredential(const Credential &credential) { - if (!ValidUser(auth_data_)) { - return Future(); + + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, + future_data_.future_impl.SafeAlloc(kUserFn_LinkWithCredential_DEPRECATED)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ linkWithCredential:CredentialFromImpl(credential.impl_) + completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { + SignInCallback(auth_result.user, error, callback_data->future_handle, + callback_data->future_data->future_impl, auth_data); + delete callback_data; + }]; + return future; +} + +Future UserInternal::LinkWithCredentialLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_LinkWithCredential_DEPRECATED)); +} + +Future UserInternal::LinkAndRetrieveDataWithCredential_DEPRECATED( + AuthData *auth_data, const Credential &credential) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + SafeFutureHandle future_handle = future_data_.future_impl.SafeAlloc( + kUserFn_LinkAndRetrieveDataWithCredential_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, future_handle, + &future_data_, SignInResult()); + return future; } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = auth_data_->future_impl.SafeAlloc( - kUserFn_LinkAndRetrieveDataWithCredential, SignInResult()); - [UserImpl(auth_data_) - linkWithCredential:CredentialFromImpl(credential.impl_) - completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInResultCallback(auth_result, error, handle, auth_data_); - }]; - return MakeFuture(&futures, handle); + + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc( + kUserFn_LinkAndRetrieveDataWithCredential_DEPRECATED)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ linkWithCredential:CredentialFromImpl(credential.impl_) + completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { + SignInResultCallback(auth_result, error, callback_data->future_handle, + callback_data->future_data->future_impl, auth_data); + delete callback_data; + }]; + return future; } -Future User::LinkWithProvider(FederatedAuthProvider *provider) const { - FIREBASE_ASSERT_RETURN(Future(), provider); - return provider->Link(auth_data_); +Future UserInternal::LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_LinkAndRetrieveDataWithCredential_DEPRECATED)); } -Future User::Unlink(const char *provider) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::LinkWithProvider_DEPRECATED(AuthData *auth_data, + FederatedAuthProvider *provider) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid() || provider == nullptr) { + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_LinkWithProvider_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + + if (!is_valid()) { + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, future_handle, + &future_data_, SignInResult()); + } else { + CompleteFuture(kAuthErrorInvalidParameter, kUserNotInitializedErrorMessage, future_handle, + &future_data_, SignInResult()); + } + return future; + } else { + return provider->Link(auth_data, this); } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_Unlink); - [UserImpl(auth_data_) unlinkFromProvider:@(provider) - completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { - SignInCallback(user, error, handle, auth_data_); - }]; - return MakeFuture(&futures, handle); -} - -Future User::UpdatePhoneNumberCredential(const Credential &credential) { - if (!ValidUser(auth_data_)) { - return Future(); +} + +Future UserInternal::Unlink_DEPRECATED(AuthData *auth_data, const char *provider) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_Unlink_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, future_handle, + &future_data_, (User *)nullptr); + return future; } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_UpdatePhoneNumberCredential); + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc(kUserFn_Unlink_DEPRECATED)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ unlinkFromProvider:@(provider) + completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { + SignInCallback(user, error, callback_data->future_handle, + callback_data->future_data->future_impl, auth_data); + delete callback_data; + }]; + return future; +} + +Future UserInternal::UnlinkLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_Unlink_DEPRECATED)); +} + +Future UserInternal::UpdatePhoneNumberCredential_DEPRECATED(AuthData *auth_data, + const Credential &credential) { + MutexLock user_info_lock(user_mutex_); #if FIREBASE_PLATFORM_IOS + if (!is_valid()) { + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_UpdatePhoneNumberCredential_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, future_handle, + &future_data_, (User *)nullptr); + return future; + } + + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, + future_data_.future_impl.SafeAlloc(kUserFn_UpdatePhoneNumberCredential_DEPRECATED)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + FIRAuthCredential *objc_credential = CredentialFromImpl(credential.impl_); if ([objc_credential isKindOfClass:[FIRPhoneAuthCredential class]]) { - [UserImpl(auth_data_) - updatePhoneNumberCredential:(FIRPhoneAuthCredential *)objc_credential - completion:^(NSError *_Nullable error) { - futures.Complete(handle, AuthErrorFromNSError(error), - [error.localizedDescription UTF8String]); - }]; + [user_ updatePhoneNumberCredential:(FIRPhoneAuthCredential *)objc_credential + completion:^(NSError *_Nullable error) { + SignInCallback(user_, error, callback_data->future_handle, + callback_data->future_data->future_impl, auth_data); + delete callback_data; + }]; } else { - futures.Complete(handle, kAuthErrorInvalidCredential, kInvalidCredentialMessage); + CompleteFuture(kAuthErrorInvalidCredential, kInvalidCredentialErrorMessage, + callback_data->future_handle, &future_data_, (User *)nullptr); } - #else // non iOS Apple platforms (eg: tvOS). - futures.Complete(handle, kAuthErrorApiNotAvailable, - "Phone Auth is not supported on non-iOS apple platforms."); + SafeFutureHandle future_handle = + future_data_.future_impl.SafeAlloc(kUserFn_UpdatePhoneNumberCredential_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + CompleteFuture(kAuthErrorApiNotAvailable, kPhoneAuthNotSupportedErrorMessage, future_handle, + &future_data_, (User *)nullptr); #endif // FIREBASE_PLATFORM_IOS - - return MakeFuture(&futures, handle); + return future; } -Future User::Reload() { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::Reload() { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_Reload, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_Reload); - [UserImpl(auth_data_) reloadWithCompletion:^(NSError *_Nullable error) { - futures.Complete(handle, AuthErrorFromNSError(error), [error.localizedDescription UTF8String]); + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc(kUserFn_Reload)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ reloadWithCompletion:^(NSError *_Nullable error) { + callback_data->future_data->future_impl.Complete(callback_data->future_handle, + AuthErrorFromNSError(error), + [error.localizedDescription UTF8String]); + delete callback_data; }]; - return MakeFuture(&futures, handle); + return future; } -Future User::Reauthenticate(const Credential &credential) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::ReloadLastResult() const { + return static_cast &>(future_data_.future_impl.LastResult(kUserFn_Reload)); +} + +Future UserInternal::Reauthenticate(const Credential &credential) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_Reauthenticate, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_Reauthenticate); - [UserImpl(auth_data_) - reauthenticateWithCredential:CredentialFromImpl(credential.impl_) - completion:^(FIRAuthDataResult *_Nullable auth_result, - NSError *_Nullable error) { - futures.Complete(handle, AuthErrorFromNSError(error), - [error.localizedDescription UTF8String]); - }]; - return MakeFuture(&futures, handle); + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc(kUserFn_Reauthenticate)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ reauthenticateWithCredential:CredentialFromImpl(credential.impl_) + completion:^(FIRAuthDataResult *_Nullable auth_result, + NSError *_Nullable error) { + callback_data->future_data->future_impl.Complete( + callback_data->future_handle, AuthErrorFromNSError(error), + [error.localizedDescription UTF8String]); + delete callback_data; + }]; + return future; +} + +Future UserInternal::ReauthenticateLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_Reauthenticate)); } -Future User::ReauthenticateAndRetrieveData(const Credential &credential) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::ReauthenticateAndRetrieveData_DEPRECATED( + AuthData *auth_data, const Credential &credential) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + SafeFutureHandle future_handle = future_data_.future_impl.SafeAlloc( + kUserFn_ReauthenticateAndRetrieveData_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, future_handle, + &future_data_, SignInResult()); + return future; } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = auth_data_->future_impl.SafeAlloc( - kUserFn_ReauthenticateAndRetrieveData, SignInResult()); - [UserImpl(auth_data_) + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc( + kUserFn_ReauthenticateAndRetrieveData_DEPRECATED)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ reauthenticateWithCredential:CredentialFromImpl(credential.impl_) completion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInResultCallback(auth_result, error, handle, auth_data_); + SignInResultCallback(auth_result, error, callback_data->future_handle, + callback_data->future_data->future_impl, auth_data); + delete callback_data; }]; - return MakeFuture(&futures, handle); + return future; } -Future User::ReauthenticateWithProvider(FederatedAuthProvider *provider) const { - FIREBASE_ASSERT_RETURN(Future(), provider); - return provider->Reauthenticate(auth_data_); +Future UserInternal::ReauthenticateAndRetrieveDataLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_ReauthenticateAndRetrieveData_DEPRECATED)); } -Future User::Delete() { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::ReauthenticateWithProvider_DEPRECATED( + AuthData *auth_data, FederatedAuthProvider *provider) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid() || provider == nullptr) { + SafeFutureHandle future_handle = future_data_.future_impl.SafeAlloc( + kUserFn_ReauthenticateWithProvider_DEPRECATED); + Future future = MakeFuture(&future_data_.future_impl, future_handle); + if (!is_valid()) { + CompleteFuture(kAuthErrorInvalidUser, kUserNotInitializedErrorMessage, future_handle, + &future_data_, SignInResult()); + } else { + CompleteFuture(kAuthErrorInvalidParameter, kUserNotInitializedErrorMessage, future_handle, + &future_data_, SignInResult()); + } + return future; + } + return provider->Reauthenticate(auth_data, this); +} + +Future UserInternal::Delete(AuthData *auth_data) { + MutexLock user_info_lock(user_mutex_); + if (!is_valid()) { + return CreateAndCompleteFuture(kUserFn_Delete, kAuthErrorInvalidUser, + kUserNotInitializedErrorMessage, &future_data_); } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_Delete); - [UserImpl(auth_data_) deleteWithCompletion:^(NSError *_Nullable error) { + FutureCallbackData *callback_data = new FutureCallbackData{ + &future_data_, future_data_.future_impl.SafeAlloc(kUserFn_Delete)}; + Future future = MakeFuture(&future_data_.future_impl, callback_data->future_handle); + + [user_ deleteWithCompletion:^(NSError *_Nullable error) { if (!error) { - UpdateCurrentUser(auth_data_); - futures.Complete(handle, kAuthErrorNone, ""); + callback_data->future_data->future_impl.Complete(callback_data->future_handle, kAuthErrorNone, + ""); } else { - futures.Complete(handle, AuthErrorFromNSError(error), - [error.localizedDescription UTF8String]); + callback_data->future_data->future_impl.Complete(callback_data->future_handle, + AuthErrorFromNSError(error), + [error.localizedDescription UTF8String]); } + delete callback_data; }]; - return MakeFuture(&futures, handle); + return future; } -UserMetadata User::metadata() const { - if (!ValidUser(auth_data_)) return UserMetadata(); +Future UserInternal::DeleteLastResult() const { + return static_cast &>(future_data_.future_impl.LastResult(kUserFn_Delete)); +} - FIRUserMetadata *meta = UserImpl(auth_data_).metadata; +UserMetadata UserInternal::metadata() const { + if (!is_valid()) return UserMetadata(); + + FIRUserMetadata *meta = user_.metadata; if (!meta) return UserMetadata(); UserMetadata data; @@ -322,36 +791,30 @@ explicit IOSWrappedUserInfo(id user_info) : user_info_(user_info) { return data; } -bool User::is_email_verified() const { - return ValidUser(auth_data_) ? UserImpl(auth_data_).emailVerified : false; -} +bool UserInternal::is_email_verified() const { return is_valid() ? user_.emailVerified : false; } -bool User::is_anonymous() const { - return ValidUser(auth_data_) ? UserImpl(auth_data_).anonymous : false; -} +bool UserInternal::is_anonymous() const { return is_valid() ? user_.anonymous : false; } -std::string User::uid() const { - return ValidUser(auth_data_) ? StringFromNSString(UserImpl(auth_data_).uid) : ""; -} +std::string UserInternal::uid() const { return is_valid() ? StringFromNSString(user_.uid) : ""; } -std::string User::email() const { - return ValidUser(auth_data_) ? StringFromNSString(UserImpl(auth_data_).email) : ""; +std::string UserInternal::email() const { + return is_valid() ? StringFromNSString(user_.email) : ""; } -std::string User::display_name() const { - return ValidUser(auth_data_) ? StringFromNSString(UserImpl(auth_data_).displayName) : ""; +std::string UserInternal::display_name() const { + return is_valid() ? StringFromNSString(user_.displayName) : ""; } -std::string User::phone_number() const { - return ValidUser(auth_data_) ? StringFromNSString(UserImpl(auth_data_).phoneNumber) : ""; +std::string UserInternal::phone_number() const { + return is_valid() ? StringFromNSString(user_.phoneNumber) : ""; } -std::string User::photo_url() const { - return ValidUser(auth_data_) ? StringFromNSUrl(UserImpl(auth_data_).photoURL) : ""; +std::string UserInternal::photo_url() const { + return is_valid() ? StringFromNSUrl(user_.photoURL) : ""; } -std::string User::provider_id() const { - return ValidUser(auth_data_) ? StringFromNSString(UserImpl(auth_data_).providerID) : ""; +std::string UserInternal::provider_id() const { + return is_valid() ? StringFromNSString(user_.providerID) : ""; } } // namespace auth diff --git a/auth/src/user.cc b/auth/src/user.cc index ea9f5e2399..946a565c3e 100644 --- a/auth/src/user.cc +++ b/auth/src/user.cc @@ -19,19 +19,12 @@ namespace firebase { namespace auth { -AUTH_RESULT_FN(User, GetToken, std::string) -AUTH_RESULT_FN(User, UpdateEmail, void) -AUTH_RESULT_FN(User, UpdatePassword, void) -AUTH_RESULT_FN(User, Reauthenticate, void) -AUTH_RESULT_FN(User, ReauthenticateAndRetrieveData, SignInResult) -AUTH_RESULT_FN(User, SendEmailVerification, void) -AUTH_RESULT_FN(User, UpdateUserProfile, void) -AUTH_RESULT_FN(User, LinkWithCredential, User*) -AUTH_RESULT_FN(User, LinkAndRetrieveDataWithCredential, SignInResult) -AUTH_RESULT_FN(User, Unlink, User*) -AUTH_RESULT_FN(User, UpdatePhoneNumberCredential, User*) -AUTH_RESULT_FN(User, Reload, void) -AUTH_RESULT_FN(User, Delete, void) +std::string UserInfoInterface::uid() const { return ""; } +std::string UserInfoInterface::email() const { return ""; } +std::string UserInfoInterface::display_name() const { return ""; } +std::string UserInfoInterface::photo_url() const { return ""; } +std::string UserInfoInterface::provider_id() const { return ""; } +std::string UserInfoInterface::phone_number() const { return ""; } #if defined(INTERNAL_EXPERIMENTAL) // I'd like to change all the above functions to use LastResultProxy, as it diff --git a/auth/tests/auth_test.cc b/auth/tests/auth_test.cc index e14778a32b..7a156781b1 100644 --- a/auth/tests/auth_test.cc +++ b/auth/tests/auth_test.cc @@ -124,7 +124,7 @@ class AuthTest : public ::testing::Test { void MakeAuth() { firebase_app_ = testing::CreateApp(); firebase_auth_ = Auth::GetAuth(firebase_app_); - if (firebase_auth_->current_user()) { + if (firebase_auth_->current_user_DEPRECATED()) { firebase_auth_->SignOut(); } } @@ -231,7 +231,8 @@ TEST_F(AuthTest, TestSignInWithCustomTokenSucceeded) { " ]" "}"); MakeAuth(); - Future result = firebase_auth_->SignInWithCustomToken("its-a-token"); + Future result = + firebase_auth_->SignInWithCustomToken_DEPRECATED("its-a-token"); Verify(kAuthErrorNone, result); } @@ -260,7 +261,8 @@ TEST_F(AuthTest, TestSignInWithCredentialSucceeded) { "}"); MakeAuth(); Credential credential = EmailAuthProvider::GetCredential("abc@g.com", "abc"); - Future result = firebase_auth_->SignInWithCredential(credential); + Future result = + firebase_auth_->SignInWithCredential_DEPRECATED(credential); Verify(kAuthErrorNone, result); } @@ -288,7 +290,7 @@ TEST_F(AuthTest, TestSignInAnonymouslySucceeded) { " ]" "}"); MakeAuth(); - Future result = firebase_auth_->SignInAnonymously(); + Future result = firebase_auth_->SignInAnonymously_DEPRECATED(); Verify(kAuthErrorNone, result); } @@ -316,8 +318,8 @@ TEST_F(AuthTest, TestSignInWithEmailAndPasswordSucceeded) { " ]" "}"); MakeAuth(); - Future result = - firebase_auth_->SignInWithEmailAndPassword("abc@xyz.com", "password"); + Future result = firebase_auth_->SignInWithEmailAndPassword_DEPRECATED( + "abc@xyz.com", "password"); Verify(kAuthErrorNone, result); } @@ -346,7 +348,8 @@ TEST_F(AuthTest, TestCreateUserWithEmailAndPasswordSucceeded) { "}"); MakeAuth(); Future result = - firebase_auth_->CreateUserWithEmailAndPassword("abc@xyz.com", "password"); + firebase_auth_->CreateUserWithEmailAndPassword_DEPRECATED("abc@xyz.com", + "password"); Verify(kAuthErrorNone, result); } @@ -375,7 +378,8 @@ TEST_F(AuthTest, TestSignInWithCustomTokenFailed) { " ]" "}"); MakeAuth(); - Future result = firebase_auth_->SignInWithCustomToken("its-a-token"); + Future result = + firebase_auth_->SignInWithCustomToken_DEPRECATED("its-a-token"); Verify(kAuthErrorInvalidCustomToken, result); } @@ -399,7 +403,8 @@ TEST_F(AuthTest, TestSignInWithCredentialFailed) { "}"); MakeAuth(); Credential credential = EmailAuthProvider::GetCredential("abc@g.com", "abc"); - Future result = firebase_auth_->SignInWithCredential(credential); + Future result = + firebase_auth_->SignInWithCredential_DEPRECATED(credential); Verify(kAuthErrorInvalidEmail, result); } @@ -422,7 +427,7 @@ TEST_F(AuthTest, TestSignInAnonymouslyFailed) { " ]" "}"); MakeAuth(); - Future result = firebase_auth_->SignInAnonymously(); + Future result = firebase_auth_->SignInAnonymously_DEPRECATED(); Verify(kAuthErrorOperationNotAllowed, result); } @@ -445,8 +450,8 @@ TEST_F(AuthTest, TestSignInWithEmailAndPasswordFailed) { " ]" "}"); MakeAuth(); - Future result = - firebase_auth_->SignInWithEmailAndPassword("abc@xyz.com", "password"); + Future result = firebase_auth_->SignInWithEmailAndPassword_DEPRECATED( + "abc@xyz.com", "password"); Verify(kAuthErrorWrongPassword, result); } @@ -470,7 +475,8 @@ TEST_F(AuthTest, TestCreateUserWithEmailAndPasswordFailed) { "}"); MakeAuth(); Future result = - firebase_auth_->CreateUserWithEmailAndPassword("abc@xyz.com", "password"); + firebase_auth_->CreateUserWithEmailAndPassword_DEPRECATED("abc@xyz.com", + "password"); Verify(kAuthErrorEmailAlreadyInUse, result); } @@ -504,16 +510,16 @@ TEST_F(AuthTest, TestCurrentUserAndSignOut) { MakeAuth(); // No user is signed in. - EXPECT_EQ(nullptr, firebase_auth_->current_user()); + EXPECT_EQ(nullptr, firebase_auth_->current_user_DEPRECATED()); // Now sign-in, say anonymously. - Future result = firebase_auth_->SignInAnonymously(); + Future result = firebase_auth_->SignInAnonymously_DEPRECATED(); MaybeWaitForFuture(result); - EXPECT_NE(nullptr, firebase_auth_->current_user()); + EXPECT_NE(nullptr, firebase_auth_->current_user_DEPRECATED()); // Now sign-out. firebase_auth_->SignOut(); - EXPECT_EQ(nullptr, firebase_auth_->current_user()); + EXPECT_EQ(nullptr, firebase_auth_->current_user_DEPRECATED()); } TEST_F(AuthTest, TestSendPasswordResetEmailSucceeded) { diff --git a/auth/tests/desktop/auth_desktop_test.cc b/auth/tests/desktop/auth_desktop_test.cc index d261d52147..374fae0d34 100644 --- a/auth/tests/desktop/auth_desktop_test.cc +++ b/auth/tests/desktop/auth_desktop_test.cc @@ -271,7 +271,8 @@ class AuthDesktopTest : public ::testing::Test { InitializeSignInWithProviderFakes(CreateGetAccountInfoFake()); provider->SetProviderData(GetFakeOAuthProviderData()); provider->SetAuthHandler(handler); - Future future = firebase_auth_->SignInWithProvider(provider); + Future future = + firebase_auth_->SignInWithProvider_DEPRECATED(provider); if (trigger_sign_in) { handler->TriggerSignInComplete(); } @@ -287,7 +288,8 @@ class AuthDesktopTest : public ::testing::Test { TEST_F(AuthDesktopTest, TestSignInWithProviderReturnsUnsupportedError) { FederatedOAuthProvider provider; - Future future = firebase_auth_->SignInWithProvider(&provider); + Future future = + firebase_auth_->SignInWithProvider_DEPRECATED(&provider); EXPECT_EQ(future.result()->user, nullptr); EXPECT_EQ(future.error(), kAuthErrorUnimplemented); EXPECT_EQ(std::string(future.error_message()), @@ -300,7 +302,8 @@ TEST_F(AuthDesktopTest, OAuthProviderTestHandler handler(/*extra_integrity_checks_=*/true); InitializeSuccessfulSignInWithProviderFlow(&provider, &handler); - Future future = firebase_auth_->SignInWithProvider(&provider); + Future future = + firebase_auth_->SignInWithProvider_DEPRECATED(&provider); handler.TriggerSignInComplete(); SignInResult sign_in_result = WaitForFuture(future); } @@ -316,9 +319,11 @@ TEST_F(AuthDesktopTest, OAuthProviderTestHandler handler2; provider2.SetAuthHandler(&handler2); - Future future1 = firebase_auth_->SignInWithProvider(&provider1); + Future future1 = + firebase_auth_->SignInWithProvider_DEPRECATED(&provider1); EXPECT_EQ(future1.status(), kFutureStatusPending); - Future future2 = firebase_auth_->SignInWithProvider(&provider2); + Future future2 = + firebase_auth_->SignInWithProvider_DEPRECATED(&provider2); VerifySignInResult(future2, kAuthErrorFederatedProviderAreadyInUse); handler1.TriggerSignInComplete(); const SignInResult sign_in_result = WaitForFuture(future1); @@ -499,8 +504,8 @@ TEST_F(AuthDesktopTest, CompleteSignInWithFailedResponse) { auth_state_listener.ExpectChanges(1); // Call the function and verify results. - const User* const user = - WaitForFuture(firebase_auth_->SignInAnonymously(), kAuthErrorFailure); + const User* const user = WaitForFuture( + firebase_auth_->SignInAnonymously_DEPRECATED(), kAuthErrorFailure); EXPECT_EQ(nullptr, user); } @@ -525,8 +530,8 @@ TEST_F(AuthDesktopTest, CompleteSignInWithGetAccountInfoFailure) { auth_state_listener.ExpectChanges(1); // Call the function and verify results. - const User* const user = - WaitForFuture(firebase_auth_->SignInAnonymously(), kAuthErrorFailure); + const User* const user = WaitForFuture( + firebase_auth_->SignInAnonymously_DEPRECATED(), kAuthErrorFailure); EXPECT_EQ(nullptr, user); } @@ -556,7 +561,8 @@ TEST_F(AuthDesktopTest, TestSignInAnonymously) { id_token_listener.ExpectChanges(2); auth_state_listener.ExpectChanges(2); - const User* const user = WaitForFuture(firebase_auth_->SignInAnonymously()); + const User* const user = + WaitForFuture(firebase_auth_->SignInAnonymously_DEPRECATED()); EXPECT_TRUE(user->is_anonymous()); EXPECT_EQ("localid123", user->uid()); EXPECT_EQ("", user->email()); @@ -585,14 +591,15 @@ TEST_F(AuthDesktopTest, TestSignInWithEmailAndPassword) { auth_state_listener.ExpectChanges(2); // Call the function and verify results. - const Future future = firebase_auth_->SignInWithEmailAndPassword( - "testsignin@example.com", "testsignin"); + const Future future = + firebase_auth_->SignInWithEmailAndPassword_DEPRECATED( + "testsignin@example.com", "testsignin"); const User* const user = WaitForFuture(future); EXPECT_FALSE(user->is_anonymous()); VerifyUser(*user); } -// Test Auth::CreateUserWithEmailAndPassword. +// Test Auth::CreateUserWithEmailAndPassword_DEPRECATED. TEST_F(AuthDesktopTest, TestCreateUserWithEmailAndPassword) { FakeSetT fakes; @@ -620,8 +627,9 @@ TEST_F(AuthDesktopTest, TestCreateUserWithEmailAndPassword) { id_token_listener.ExpectChanges(2); auth_state_listener.ExpectChanges(2); - const Future future = firebase_auth_->CreateUserWithEmailAndPassword( - "testsignin@example.com", "testsignin"); + const Future future = + firebase_auth_->CreateUserWithEmailAndPassword_DEPRECATED( + "testsignin@example.com", "testsignin"); const User* const user = WaitForFuture(future); EXPECT_FALSE(user->is_anonymous()); VerifyUser(*user); @@ -643,8 +651,8 @@ TEST_F(AuthDesktopTest, TestSignInWithCustomToken) { id_token_listener.ExpectChanges(2); auth_state_listener.ExpectChanges(2); - const User* const user = - WaitForFuture(firebase_auth_->SignInWithCustomToken("fake_custom_token")); + const User* const user = WaitForFuture( + firebase_auth_->SignInWithCustomToken_DEPRECATED("fake_custom_token")); EXPECT_FALSE(user->is_anonymous()); VerifyUser(*user); } @@ -659,8 +667,8 @@ TEST_F(AuthDesktopTest, TestSignInWithCredential_GoogleIdToken) { const Credential credential = GoogleAuthProvider::GetCredential("fake_id_token", ""); - const User* const user = - WaitForFuture(firebase_auth_->SignInWithCredential(credential)); + const User* const user = WaitForFuture( + firebase_auth_->SignInWithCredential_DEPRECATED(credential)); EXPECT_FALSE(user->is_anonymous()); VerifyUser(*user); } @@ -673,8 +681,8 @@ TEST_F(AuthDesktopTest, TestSignInWithCredential_GoogleAccessToken) { const Credential credential = GoogleAuthProvider::GetCredential("", "fake_access_token"); - const User* const user = - WaitForFuture(firebase_auth_->SignInWithCredential(credential)); + const User* const user = WaitForFuture( + firebase_auth_->SignInWithCredential_DEPRECATED(credential)); EXPECT_FALSE(user->is_anonymous()); VerifyUser(*user); } @@ -691,8 +699,9 @@ TEST_F(AuthDesktopTest, const Credential credential = GoogleAuthProvider::GetCredential("", "fake_access_token"); - const User* const user = WaitForFuture( - firebase_auth_->SignInWithCredential(credential), kAuthErrorFailure); + const User* const user = + WaitForFuture(firebase_auth_->SignInWithCredential_DEPRECATED(credential), + kAuthErrorFailure); EXPECT_EQ(nullptr, user); } @@ -709,8 +718,9 @@ TEST_F(AuthDesktopTest, const Credential credential = GoogleAuthProvider::GetCredential("", "fake_access_token"); - const User* const user = WaitForFuture( - firebase_auth_->SignInWithCredential(credential), kAuthErrorFailure); + const User* const user = + WaitForFuture(firebase_auth_->SignInWithCredential_DEPRECATED(credential), + kAuthErrorFailure); EXPECT_EQ(nullptr, user); } @@ -726,7 +736,7 @@ TEST_F(AuthDesktopTest, TestSignInWithCredential_NeedsConfirmation) { const Credential credential = GoogleAuthProvider::GetCredential("fake_id_token", ""); - WaitForFuture(firebase_auth_->SignInWithCredential(credential), + WaitForFuture(firebase_auth_->SignInWithCredential_DEPRECATED(credential), kAuthErrorAccountExistsWithDifferentCredentials); } @@ -744,7 +754,8 @@ TEST_F(AuthDesktopTest, TestSignInAndRetrieveDataWithCredential_GitHub) { const Credential credential = GitHubAuthProvider::GetCredential("fake_access_token"); const SignInResult sign_in_result = WaitForFuture( - firebase_auth_->SignInAndRetrieveDataWithCredential(credential)); + firebase_auth_->SignInAndRetrieveDataWithCredential_DEPRECATED( + credential)); EXPECT_FALSE(sign_in_result.user->is_anonymous()); VerifyUser(*sign_in_result.user); @@ -773,7 +784,8 @@ TEST_F(AuthDesktopTest, TestSignInAndRetrieveDataWithCredential_Twitter) { const Credential credential = TwitterAuthProvider::GetCredential( "fake_access_token", "fake_oauth_token"); const SignInResult sign_in_result = WaitForFuture( - firebase_auth_->SignInAndRetrieveDataWithCredential(credential)); + firebase_auth_->SignInAndRetrieveDataWithCredential_DEPRECATED( + credential)); EXPECT_FALSE(sign_in_result.user->is_anonymous()); VerifyUser(*sign_in_result.user); @@ -793,7 +805,8 @@ TEST_F(AuthDesktopTest, const Credential credential = TwitterAuthProvider::GetCredential( "fake_access_token", "fake_oauth_token"); const SignInResult sign_in_result = WaitForFuture( - firebase_auth_->SignInAndRetrieveDataWithCredential(credential)); + firebase_auth_->SignInAndRetrieveDataWithCredential_DEPRECATED( + credential)); EXPECT_FALSE(sign_in_result.user->is_anonymous()); VerifyUser(*sign_in_result.user); @@ -816,7 +829,8 @@ TEST_F(AuthDesktopTest, const Credential credential = TwitterAuthProvider::GetCredential( "fake_access_token", "fake_oauth_token"); const SignInResult sign_in_result = WaitForFuture( - firebase_auth_->SignInAndRetrieveDataWithCredential(credential)); + firebase_auth_->SignInAndRetrieveDataWithCredential_DEPRECATED( + credential)); EXPECT_FALSE(sign_in_result.user->is_anonymous()); VerifyUser(*sign_in_result.user); diff --git a/auth/tests/desktop/user_desktop_test.cc b/auth/tests/desktop/user_desktop_test.cc index bd466efe23..b42260081e 100644 --- a/auth/tests/desktop/user_desktop_test.cc +++ b/auth/tests/desktop/user_desktop_test.cc @@ -276,10 +276,10 @@ class UserDesktopTest : public ::testing::Test { id_token_listener.ExpectChanges(2); auth_state_listener.ExpectChanges(2); - Future future = firebase_auth_->SignInAnonymously(); + Future future = firebase_auth_->SignInAnonymously_DEPRECATED(); while (future.status() == kFutureStatusPending) { } - firebase_user_ = firebase_auth_->current_user(); + firebase_user_ = firebase_auth_->current_user_DEPRECATED(); EXPECT_NE(nullptr, firebase_user_); // Reset listeners before tests are run. @@ -311,7 +311,8 @@ class UserDesktopTest : public ::testing::Test { FederatedOAuthProvider* provider, OAuthProviderTestHandler* handler, bool trigger_link) { InitializeSuccessfulAuthenticateWithProviderFlow(provider, handler); - Future future = firebase_user_->LinkWithProvider(provider); + Future future = + firebase_user_->LinkWithProvider_DEPRECATED(provider); if (trigger_link) { handler->TriggerLinkComplete(); } @@ -323,7 +324,7 @@ class UserDesktopTest : public ::testing::Test { bool trigger_reauthenticate) { InitializeSuccessfulAuthenticateWithProviderFlow(provider, handler); Future future = - firebase_user_->ReauthenticateWithProvider(provider); + firebase_user_->ReauthenticateWithProvider_DEPRECATED(provider); if (trigger_reauthenticate) { handler->TriggerReauthenticateComplete(); } @@ -342,9 +343,12 @@ class UserDesktopTest : public ::testing::Test { // Test that metadata is correctly being populated and exposed TEST_F(UserDesktopTest, TestAccountMetadata) { - EXPECT_EQ(123, - firebase_auth_->current_user()->metadata().last_sign_in_timestamp); - EXPECT_EQ(456, firebase_auth_->current_user()->metadata().creation_timestamp); + EXPECT_EQ(123, firebase_auth_->current_user_DEPRECATED() + ->metadata() + .last_sign_in_timestamp); + EXPECT_EQ( + 456, + firebase_auth_->current_user_DEPRECATED()->metadata().creation_timestamp); } TEST_F(UserDesktopTest, TestGetToken) { @@ -531,7 +535,7 @@ TEST_F(UserDesktopTest, TestUnlink) { auth_state_listener.ExpectChanges(0); WaitForFuture(firebase_user_->Reload()); - WaitForFuture(firebase_user_->Unlink("fake_provider_id")); + WaitForFuture(firebase_user_->Unlink_DEPRECATED("fake_provider_id")); VerifyProviderData(*firebase_user_); } @@ -542,7 +546,7 @@ TEST_F(UserDesktopTest, TestUnlink_NonLinkedProvider) { id_token_listener.ExpectChanges(0); auth_state_listener.ExpectChanges(0); - WaitForFuture(firebase_user_->Unlink("no_such_provider"), + WaitForFuture(firebase_user_->Unlink_DEPRECATED("no_such_provider"), kAuthErrorNoSuchProvider); } @@ -557,7 +561,7 @@ TEST_F(UserDesktopTest, TestLinkWithCredential_OauthCredential) { const Credential credential = GoogleAuthProvider::GetCredential("fake_id_token", ""); const User* const user = - WaitForFuture(firebase_user_->LinkWithCredential(credential)); + WaitForFuture(firebase_user_->LinkWithCredential_DEPRECATED(credential)); EXPECT_FALSE(user->is_anonymous()); VerifyUser(*user); } @@ -577,7 +581,7 @@ TEST_F(UserDesktopTest, TestLinkWithCredential_EmailCredential) { EXPECT_TRUE(firebase_user_->is_anonymous()); const Credential credential = EmailAuthProvider::GetCredential(new_email.c_str(), "fake_password"); - WaitForFuture(firebase_user_->LinkWithCredential(credential)); + WaitForFuture(firebase_user_->LinkWithCredential_DEPRECATED(credential)); EXPECT_EQ(new_email, firebase_user_->email()); EXPECT_FALSE(firebase_user_->is_anonymous()); } @@ -594,7 +598,7 @@ TEST_F(UserDesktopTest, TestLinkWithCredential_NeedsConfirmation) { const Credential credential = GoogleAuthProvider::GetCredential("fake_id_token", ""); - WaitForFuture(firebase_user_->LinkWithCredential(credential), + WaitForFuture(firebase_user_->LinkWithCredential_DEPRECATED(credential), kAuthErrorAccountExistsWithDifferentCredentials); } @@ -624,11 +628,13 @@ TEST_F(UserDesktopTest, TestLinkWithCredential_ChecksAlreadyLinkedProviders) { const Credential google_credential = GoogleAuthProvider::GetCredential("fake_id_token", ""); - WaitForFuture(firebase_user_->LinkWithCredential(google_credential)); + WaitForFuture( + firebase_user_->LinkWithCredential_DEPRECATED(google_credential)); // The same provider shouldn't be linked twice. - WaitForFuture(firebase_user_->LinkWithCredential(google_credential), - kAuthErrorProviderAlreadyLinked); + WaitForFuture( + firebase_user_->LinkWithCredential_DEPRECATED(google_credential), + kAuthErrorProviderAlreadyLinked); id_token_listener.VerifyAndReset(); auth_state_listener.VerifyAndReset(); @@ -662,14 +668,17 @@ TEST_F(UserDesktopTest, TestLinkWithCredential_ChecksAlreadyLinkedProviders) { // Should be able to link a different provider. const Credential facebook_credential = FacebookAuthProvider::GetCredential("fake_access_token"); - WaitForFuture(firebase_user_->LinkWithCredential(facebook_credential)); + WaitForFuture( + firebase_user_->LinkWithCredential_DEPRECATED(facebook_credential)); // The same provider shouldn't be linked twice. - WaitForFuture(firebase_user_->LinkWithCredential(facebook_credential), - kAuthErrorProviderAlreadyLinked); + WaitForFuture( + firebase_user_->LinkWithCredential_DEPRECATED(facebook_credential), + kAuthErrorProviderAlreadyLinked); // Check that the previously linked provider wasn't overridden. - WaitForFuture(firebase_user_->LinkWithCredential(google_credential), - kAuthErrorProviderAlreadyLinked); + WaitForFuture( + firebase_user_->LinkWithCredential_DEPRECATED(google_credential), + kAuthErrorProviderAlreadyLinked); } TEST_F(UserDesktopTest, TestLinkWithCredentialAndRetrieveData) { @@ -726,8 +735,8 @@ TEST_F(UserDesktopTest, TestReauthenticateAndRetrieveData) { const Credential credential = GoogleAuthProvider::GetCredential("fake_id_token", ""); - const SignInResult sign_in_result = - WaitForFuture(firebase_user_->ReauthenticateAndRetrieveData(credential)); + const SignInResult sign_in_result = WaitForFuture( + firebase_user_->ReauthenticateAndRetrieveData_DEPRECATED(credential)); EXPECT_FALSE(sign_in_result.user->is_anonymous()); VerifyUser(*sign_in_result.user); } @@ -830,7 +839,7 @@ TEST_F(UserDesktopTestSignOutOnError, Unlink) { GetUrlForApi(API_KEY, "setAccountInfo"), "USER_NOT_FOUND", kAuthErrorUserNotFound, [&] { sem_.Post(); - return firebase_user_->Unlink("fake_provider_id"); + return firebase_user_->Unlink_DEPRECATED("fake_provider_id"); }); sem_.Wait(); } @@ -840,7 +849,7 @@ TEST_F(UserDesktopTestSignOutOnError, LinkWithEmail) { GetUrlForApi(API_KEY, "setAccountInfo"), "USER_NOT_FOUND", kAuthErrorUserNotFound, [&] { sem_.Post(); - return firebase_user_->LinkWithCredential( + return firebase_user_->LinkWithCredential_DEPRECATED( EmailAuthProvider::GetCredential("fake_email@example.com", "fake_password")); }); @@ -852,7 +861,7 @@ TEST_F(UserDesktopTestSignOutOnError, LinkWithOauthCredential) { GetUrlForApi(API_KEY, "verifyAssertion"), "USER_NOT_FOUND", kAuthErrorUserNotFound, [&] { sem_.Post(); - return firebase_user_->LinkWithCredential( + return firebase_user_->LinkWithCredential_DEPRECATED( GoogleAuthProvider::GetCredential("fake_id_token", "")); }); sem_.Wait(); @@ -890,13 +899,14 @@ TEST_F(UserDesktopTest, TestRaceCondition_SetAccountInfoAndSignOut) { } EXPECT_THAT(future.error(), AnyOf(kAuthErrorNone, kAuthErrorNoSignedInUser)); - EXPECT_EQ(nullptr, firebase_auth_->current_user()); + EXPECT_EQ(nullptr, firebase_auth_->current_user_DEPRECATED()); } // LinkWithProvider tests. TEST_F(UserDesktopTest, TestLinkWithProviderReturnsUnsupportedError) { FederatedOAuthProvider provider; - Future future = firebase_user_->LinkWithProvider(&provider); + Future future = + firebase_user_->LinkWithProvider_DEPRECATED(&provider); EXPECT_EQ(future.result()->user, nullptr); EXPECT_EQ(future.error(), kAuthErrorUnimplemented); EXPECT_EQ(std::string(future.error_message()), @@ -911,7 +921,8 @@ TEST_F(UserDesktopTest, test::OAuthProviderTestHandler handler(/*extra_integrity_checks_=*/true); InitializeSuccessfulAuthenticateWithProviderFlow(&provider, &handler); - Future future = firebase_user_->LinkWithProvider(&provider); + Future future = + firebase_user_->LinkWithProvider_DEPRECATED(&provider); handler.TriggerLinkComplete(); SignInResult sign_in_result = WaitForFuture(future); } @@ -927,9 +938,11 @@ TEST_F(UserDesktopTest, OAuthProviderTestHandler handler2; provider2.SetAuthHandler(&handler2); - Future future1 = firebase_user_->LinkWithProvider(&provider1); + Future future1 = + firebase_user_->LinkWithProvider_DEPRECATED(&provider1); EXPECT_EQ(future1.status(), kFutureStatusPending); - Future future2 = firebase_user_->LinkWithProvider(&provider2); + Future future2 = + firebase_user_->LinkWithProvider_DEPRECATED(&provider2); VerifySignInResult(future2, kAuthErrorFederatedProviderAreadyInUse); handler1.TriggerLinkComplete(); const SignInResult sign_in_result = WaitForFuture(future1); @@ -1056,7 +1069,7 @@ TEST_F(UserDesktopTest, DISABLED_TestLinkCompleteNullErrorMessageFails) { TEST_F(UserDesktopTest, TestReauthentciateWithProviderReturnsUnsupportedError) { FederatedOAuthProvider provider; Future future = - firebase_user_->ReauthenticateWithProvider(&provider); + firebase_user_->ReauthenticateWithProvider_DEPRECATED(&provider); EXPECT_EQ(future.result()->user, nullptr); EXPECT_EQ(future.error(), kAuthErrorUnimplemented); EXPECT_EQ(std::string(future.error_message()), @@ -1073,7 +1086,7 @@ TEST_F( InitializeSuccessfulAuthenticateWithProviderFlow(&provider, &handler); Future future = - firebase_user_->ReauthenticateWithProvider(&provider); + firebase_user_->ReauthenticateWithProvider_DEPRECATED(&provider); handler.TriggerReauthenticateComplete(); SignInResult sign_in_result = WaitForFuture(future); } @@ -1090,10 +1103,10 @@ TEST_F(UserDesktopTest, OAuthProviderTestHandler handler2; provider2.SetAuthHandler(&handler2); Future future1 = - firebase_user_->ReauthenticateWithProvider(&provider1); + firebase_user_->ReauthenticateWithProvider_DEPRECATED(&provider1); EXPECT_EQ(future1.status(), kFutureStatusPending); Future future2 = - firebase_user_->ReauthenticateWithProvider(&provider2); + firebase_user_->ReauthenticateWithProvider_DEPRECATED(&provider2); VerifySignInResult(future2, kAuthErrorFederatedProviderAreadyInUse); handler1.TriggerReauthenticateComplete(); const SignInResult sign_in_result = WaitForFuture(future1); diff --git a/auth/tests/user_test.cc b/auth/tests/user_test.cc index c2e9176837..cb25630126 100644 --- a/auth/tests/user_test.cc +++ b/auth/tests/user_test.cc @@ -167,9 +167,9 @@ class UserTest : public ::testing::Test { "}"); firebase_app_ = testing::CreateApp(); firebase_auth_ = Auth::GetAuth(firebase_app_); - Future result = firebase_auth_->SignInAnonymously(); + Future result = firebase_auth_->SignInAnonymously_DEPRECATED(); MaybeWaitForFuture(result); - firebase_user_ = firebase_auth_->current_user(); + firebase_user_ = firebase_auth_->current_user_DEPRECATED(); EXPECT_NE(nullptr, firebase_user_); } @@ -342,7 +342,7 @@ TEST_F(UserTest, TestReauthenticate) { Credential credential = EmailAuthProvider::GetCredential("i@email.com", "pw"); Future sign_in_result = - firebase_auth_->SignInWithCredential(credential); + firebase_auth_->SignInWithCredential_DEPRECATED(credential); Verify(sign_in_result); Future reauthenticate_result = @@ -368,8 +368,9 @@ TEST_F(UserTest, TestReauthenticateAndRetrieveData) { "}"; firebase::testing::cppsdk::ConfigSet(config.c_str()); - Future result = firebase_user_->ReauthenticateAndRetrieveData( - EmailAuthProvider::GetCredential("i@email.com", "pw")); + Future result = + firebase_user_->ReauthenticateAndRetrieveData_DEPRECATED( + EmailAuthProvider::GetCredential("i@email.com", "pw")); Verify(result); } #endif // !defined(__APPLE__) && !defined(FIREBASE_WAIT_ASYNC_IN_TEST) @@ -414,7 +415,7 @@ TEST_F(UserTest, TestLinkWithCredential) { "}"; firebase::testing::cppsdk::ConfigSet(config.c_str()); - Future result = firebase_user_->LinkWithCredential( + Future result = firebase_user_->LinkWithCredential_DEPRECATED( EmailAuthProvider::GetCredential("i@email.com", "pw")); Verify(result); } @@ -422,7 +423,7 @@ TEST_F(UserTest, TestLinkWithCredential) { #if !defined(__APPLE__) && !defined(FIREBASE_WAIT_ASYNC_IN_TEST) TEST_F(UserTest, TestLinkAndRetrieveDataWithCredential) { // Test link and retrieve data with credential. This calls the same native SDK - // function as LinkWithCredential(). + // function as LinkWithCredential_DEPRECATED(). firebase::testing::cppsdk::ConfigSet( "{" " config:[" @@ -461,7 +462,7 @@ TEST_F(UserTest, TestUnlink) { // MaybeWaitForFuture because to Reload will return immediately for mobile // wrappers, and Verify expects at least a single "tick". MaybeWaitForFuture(firebase_user_->Reload()); - Future result = firebase_user_->Unlink("provider"); + Future result = firebase_user_->Unlink_DEPRECATED("provider"); Verify(result); // For desktop, the provider must have been removed. For mobile wrappers, the // whole flow must have been a no-op, and the provider list was empty to begin diff --git a/database/integration_test/src/integration_test.cc b/database/integration_test/src/integration_test.cc index 211c0d3b5b..6d0af2101e 100644 --- a/database/integration_test/src/integration_test.cc +++ b/database/integration_test/src/integration_test.cc @@ -315,13 +315,13 @@ void FirebaseDatabaseTest::TerminateDatabase() { } void FirebaseDatabaseTest::SignIn() { - if (shared_auth_->current_user() != nullptr) { + if (shared_auth_->current_user_DEPRECATED() != nullptr) { // Already signed in. return; } LogDebug("Signing in."); firebase::Future sign_in_future = - shared_auth_->SignInAnonymously(); + shared_auth_->SignInAnonymously_DEPRECATED(); WaitForCompletion(sign_in_future, "SignInAnonymously"); if (sign_in_future.error() != 0) { FAIL() << "Ensure your application has the Anonymous sign-in provider " @@ -335,13 +335,13 @@ void FirebaseDatabaseTest::SignOut() { // Auth is not set up. return; } - if (shared_auth_->current_user() == nullptr) { + if (shared_auth_->current_user_DEPRECATED() == nullptr) { // Already signed out. return; } - if (shared_auth_->current_user()->is_anonymous()) { + if (shared_auth_->current_user_DEPRECATED()->is_anonymous()) { // If signed in anonymously, delete the anonymous user. - WaitForCompletion(shared_auth_->current_user()->Delete(), + WaitForCompletion(shared_auth_->current_user_DEPRECATED()->Delete(), "DeleteAnonymousUser"); } else { // If not signed in anonymously (e.g. if the tests were modified to sign in @@ -349,11 +349,11 @@ void FirebaseDatabaseTest::SignOut() { shared_auth_->SignOut(); // Wait for the sign-out to finish. - while (shared_auth_->current_user() != nullptr) { + while (shared_auth_->current_user_DEPRECATED() != nullptr) { if (ProcessEvents(100)) break; } } - EXPECT_EQ(shared_auth_->current_user(), nullptr); + EXPECT_EQ(shared_auth_->current_user_DEPRECATED(), nullptr); } firebase::database::DatabaseReference FirebaseDatabaseTest::CreateWorkingPath( @@ -371,7 +371,7 @@ TEST_F(FirebaseDatabaseTest, TestInitializeAndTerminate) { } TEST_F(FirebaseDatabaseTest, TestSignIn) { - EXPECT_NE(shared_auth_->current_user(), nullptr); + EXPECT_NE(shared_auth_->current_user_DEPRECATED(), nullptr); } TEST_F(FirebaseDatabaseTest, TestCreateWorkingPath) { diff --git a/firestore/integration_test/src/integration_test.cc b/firestore/integration_test/src/integration_test.cc index 6d63ba8c01..6e08b503e2 100644 --- a/firestore/integration_test/src/integration_test.cc +++ b/firestore/integration_test/src/integration_test.cc @@ -272,13 +272,13 @@ void FirebaseFirestoreBasicTest::TerminateFirestore() { } void FirebaseFirestoreBasicTest::SignIn() { - if (shared_auth_->current_user() != nullptr) { + if (shared_auth_->current_user_DEPRECATED() != nullptr) { // Already signed in. return; } LogDebug("Signing in."); firebase::Future sign_in_future = - shared_auth_->SignInAnonymously(); + shared_auth_->SignInAnonymously_DEPRECATED(); WaitForCompletion(sign_in_future, "SignInAnonymously"); if (sign_in_future.error() != 0) { FAIL() << "Ensure your application has the Anonymous sign-in provider " @@ -292,14 +292,14 @@ void FirebaseFirestoreBasicTest::SignOut() { // Auth is not set up. return; } - if (shared_auth_->current_user() == nullptr) { + if (shared_auth_->current_user_DEPRECATED() == nullptr) { // Already signed out. return; } - if (shared_auth_->current_user()->is_anonymous()) { + if (shared_auth_->current_user_DEPRECATED()->is_anonymous()) { // If signed in anonymously, delete the anonymous user. - WaitForCompletion(shared_auth_->current_user()->Delete(), + WaitForCompletion(shared_auth_->current_user_DEPRECATED()->Delete(), "DeleteAnonymousUser"); } else { // If not signed in anonymously (e.g. if the tests were modified to sign in @@ -307,11 +307,11 @@ void FirebaseFirestoreBasicTest::SignOut() { shared_auth_->SignOut(); // Wait for the sign-out to finish. - while (shared_auth_->current_user() != nullptr) { + while (shared_auth_->current_user_DEPRECATED() != nullptr) { if (ProcessEvents(100)) break; } } - EXPECT_EQ(shared_auth_->current_user(), nullptr); + EXPECT_EQ(shared_auth_->current_user_DEPRECATED(), nullptr); } firebase::firestore::CollectionReference @@ -345,7 +345,7 @@ TEST_F(FirebaseFirestoreBasicTest, TestInitializeAndTerminate) { } TEST_F(FirebaseFirestoreBasicTest, TestSignIn) { - EXPECT_NE(shared_auth_->current_user(), nullptr); + EXPECT_NE(shared_auth_->current_user_DEPRECATED(), nullptr); } TEST_F(FirebaseFirestoreBasicTest, TestAppAndSettings) { diff --git a/firestore/integration_test_internal/src/firestore_test.cc b/firestore/integration_test_internal/src/firestore_test.cc index 0569448f7d..ee6b6b44cb 100644 --- a/firestore/integration_test_internal/src/firestore_test.cc +++ b/firestore/integration_test_internal/src/firestore_test.cc @@ -1537,7 +1537,7 @@ TEST_F(FirestoreIntegrationTest, AuthWorks) { WriteDocument(doc, MapFieldValue{{"foo", FieldValue::Integer(42)}}); // Signing in should trigger an AuthStateListener event. - auto signin = auth->SignInAnonymously(); + auto signin = auth->SignInAnonymously_DEPRECATED(); Stopwatch stopwatch; Await(signin); stopwatch.stop(); diff --git a/firestore/integration_test_internal/src/integration_test.cc b/firestore/integration_test_internal/src/integration_test.cc index 13b36d59f6..c3889cdc68 100644 --- a/firestore/integration_test_internal/src/integration_test.cc +++ b/firestore/integration_test_internal/src/integration_test.cc @@ -275,13 +275,13 @@ void FirebaseFirestoreBasicTest::TerminateFirestore() { } void FirebaseFirestoreBasicTest::SignIn() { - if (shared_auth_->current_user() != nullptr) { + if (shared_auth_->current_user_DEPRECATED() != nullptr) { // Already signed in. return; } LogDebug("Signing in."); firebase::Future sign_in_future = - shared_auth_->SignInAnonymously(); + shared_auth_->SignInAnonymously_DEPRECATED(); WaitForCompletion(sign_in_future, "SignInAnonymously"); if (sign_in_future.error() != 0) { FAIL() << "Ensure your application has the Anonymous sign-in provider " @@ -295,14 +295,14 @@ void FirebaseFirestoreBasicTest::SignOut() { // Auth is not set up. return; } - if (shared_auth_->current_user() == nullptr) { + if (shared_auth_->current_user_DEPRECATED() == nullptr) { // Already signed out. return; } - if (shared_auth_->current_user()->is_anonymous()) { + if (shared_auth_->current_user_DEPRECATED()->is_anonymous()) { // If signed in anonymously, delete the anonymous user. - WaitForCompletion(shared_auth_->current_user()->Delete(), + WaitForCompletion(shared_auth_->current_user_DEPRECATED()->Delete(), "DeleteAnonymousUser"); } else { // If not signed in anonymously (e.g. if the tests were modified to sign in @@ -310,11 +310,11 @@ void FirebaseFirestoreBasicTest::SignOut() { shared_auth_->SignOut(); // Wait for the sign-out to finish. - while (shared_auth_->current_user() != nullptr) { + while (shared_auth_->current_user_DEPRECATED() != nullptr) { if (ProcessEvents(100)) break; } } - EXPECT_EQ(shared_auth_->current_user(), nullptr); + EXPECT_EQ(shared_auth_->current_user_DEPRECATED(), nullptr); } firebase::firestore::CollectionReference @@ -349,7 +349,7 @@ TEST_F(FirebaseFirestoreBasicTest, TestInitializeAndTerminate) { TEST_F(FirebaseFirestoreBasicTest, TestSignIn) { SKIP_TEST_ON_QUICK_CHECK; - EXPECT_NE(shared_auth_->current_user(), nullptr); + EXPECT_NE(shared_auth_->current_user_DEPRECATED(), nullptr); } TEST_F(FirebaseFirestoreBasicTest, TestAppAndSettings) { diff --git a/functions/integration_test/src/integration_test.cc b/functions/integration_test/src/integration_test.cc index 3759cfdcec..5f8ea23f1c 100644 --- a/functions/integration_test/src/integration_test.cc +++ b/functions/integration_test/src/integration_test.cc @@ -185,7 +185,7 @@ void FirebaseFunctionsTest::Terminate() { void FirebaseFunctionsTest::SignIn() { LogDebug("Signing in."); firebase::Future sign_in_future = - auth_->SignInAnonymously(); + auth_->SignInAnonymously_DEPRECATED(); WaitForCompletion(sign_in_future, "SignInAnonymously"); if (sign_in_future.error() != 0) { FAIL() << "Ensure your application has the Anonymous sign-in provider " @@ -252,7 +252,7 @@ TEST_F(FirebaseFunctionsTest, TestInitializeAndTerminate) { TEST_F(FirebaseFunctionsTest, TestSignIn) { SignIn(); - EXPECT_NE(auth_->current_user(), nullptr); + EXPECT_NE(auth_->current_user_DEPRECATED(), nullptr); } TEST_F(FirebaseFunctionsTest, TestFunction) { diff --git a/storage/integration_test/src/integration_test.cc b/storage/integration_test/src/integration_test.cc index 05632798c8..1921488e35 100644 --- a/storage/integration_test/src/integration_test.cc +++ b/storage/integration_test/src/integration_test.cc @@ -271,13 +271,13 @@ void FirebaseStorageTest::TerminateStorage() { } void FirebaseStorageTest::SignIn() { - if (shared_auth_->current_user() != nullptr) { + if (shared_auth_->current_user_DEPRECATED() != nullptr) { // Already signed in. return; } LogDebug("Signing in."); firebase::Future sign_in_future = - shared_auth_->SignInAnonymously(); + shared_auth_->SignInAnonymously_DEPRECATED(); WaitForCompletion(sign_in_future, "SignInAnonymously"); if (sign_in_future.error() != 0) { FAIL() << "Ensure your application has the Anonymous sign-in provider " @@ -291,13 +291,13 @@ void FirebaseStorageTest::SignOut() { // Auth is not set up. return; } - if (shared_auth_->current_user() == nullptr) { + if (shared_auth_->current_user_DEPRECATED() == nullptr) { // Already signed out. return; } - if (shared_auth_->current_user()->is_anonymous()) { + if (shared_auth_->current_user_DEPRECATED()->is_anonymous()) { // If signed in anonymously, delete the anonymous user. - WaitForCompletion(shared_auth_->current_user()->Delete(), + WaitForCompletion(shared_auth_->current_user_DEPRECATED()->Delete(), "DeleteAnonymousUser"); } else { // If not signed in anonymously (e.g. if the tests were modified to sign in @@ -305,11 +305,11 @@ void FirebaseStorageTest::SignOut() { shared_auth_->SignOut(); // Wait for the sign-out to finish. - while (shared_auth_->current_user() != nullptr) { + while (shared_auth_->current_user_DEPRECATED() != nullptr) { if (ProcessEvents(100)) break; } } - EXPECT_EQ(shared_auth_->current_user(), nullptr); + EXPECT_EQ(shared_auth_->current_user_DEPRECATED(), nullptr); } firebase::storage::StorageReference FirebaseStorageTest::CreateFolder() { @@ -330,7 +330,7 @@ TEST_F(FirebaseStorageTest, TestInitializeAndTerminate) { } TEST_F(FirebaseStorageTest, TestSignIn) { - EXPECT_NE(shared_auth_->current_user(), nullptr); + EXPECT_NE(shared_auth_->current_user_DEPRECATED(), nullptr); } TEST_F(FirebaseStorageTest, TestCreateWorkingFolder) {