diff --git a/auth/integration_test/src/integration_test.cc b/auth/integration_test/src/integration_test.cc index d7d4abd443..3727bcab9d 100644 --- a/auth/integration_test/src/integration_test.cc +++ b/auth/integration_test/src/integration_test.cc @@ -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; } @@ -516,8 +513,9 @@ TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential) { firebase::auth::Credential credential = firebase::auth::EmailAuthProvider::GetCredential(email.c_str(), kTestPassword); - WaitForCompletion(user->LinkAndRetrieveDataWithCredential(credential), - "LinkAndRetrieveDataWithCredential"); + WaitForCompletion( + user->LinkAndRetrieveDataWithCredential_DEPRECATED(credential), + "LinkAndRetrieveDataWithCredential_DEPRECATED"); WaitForCompletion(user->Unlink_DEPRECATED(credential.provider().c_str()), "Unlink"); SignOut(); @@ -768,10 +766,12 @@ TEST_F(FirebaseAuthTest, TestAuthPersistenceWithEmailSignin) { // 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_DEPRECATED()->provider_data().size(); + 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()[i]->provider_id()); + prev_provider_data_ids.push_back(auth_->current_user_DEPRECATED() + ->provider_data_DEPRECATED()[i] + ->provider_id()); } Terminate(); ProcessEvents(2000); @@ -782,10 +782,12 @@ TEST_F(FirebaseAuthTest, TestAuthPersistenceWithEmailSignin) { // Make sure the provider IDs are the same as they were before. 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_DEPRECATED()->provider_data().size(); + 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()[i]->provider_id()); + 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); diff --git a/auth/src/auth.cc b/auth/src/auth.cc index fe92cd421d..a7bd564e53 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. diff --git a/auth/src/common.cc b/auth/src/common.cc index 70324d4831..510d1f82c0 100644 --- a/auth/src/common.cc +++ b/auth/src/common.cc @@ -21,6 +21,11 @@ namespace firebase { namespace auth { +const char* kUserNotInitializedErrorMessage = + "Operation attmpted on an invalid User object."; +const char* kPhoneAuthNotSupportedErrorMessage = + "Phone Auth is not supported on this platform."; + // static member variables const uint32_t PhoneAuthProvider::kMaxTimeoutMs = 3000; @@ -47,6 +52,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 dc70768108..80674ab2bd 100644 --- a/auth/src/common.h +++ b/auth/src/common.h @@ -17,11 +17,18 @@ #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; + // 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 +37,59 @@ 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; +}; + +template +struct FutureCallbackData { + FutureData* future_data; + SafeFutureHandle future_handle; +}; + +// 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); @@ -62,7 +122,7 @@ void LogHeartbeat(Auth* auth); // 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. diff --git a/auth/src/data.h b/auth/src/data.h index 3d33719879..54a09264c7 100644 --- a/auth/src/data.h +++ b/auth/src/data.h @@ -27,6 +27,20 @@ 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; +}; + // 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 { @@ -41,7 +55,15 @@ enum AuthApiFunction { 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, @@ -51,7 +73,7 @@ enum AuthApiFunction { kUserFn_ConfirmEmailVerification, kUserFn_UpdateUserProfile, kUserFn_LinkWithCredential_DEPRECATED, - kUserFn_LinkAndRetrieveDataWithCredential, + kUserFn_LinkAndRetrieveDataWithCredential_DEPRECATED, kUserFn_LinkWithProvider_DEPRECATED, kUserFn_ReauthenticateWithProvider_DEPRECATED, kUserFn_Unlink_DEPRECATED, @@ -59,11 +81,7 @@ enum AuthApiFunction { 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 +94,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 +112,6 @@ struct AuthData { app = nullptr; auth = nullptr; auth_impl = nullptr; - user_impl = nullptr; listener_impl = nullptr; id_token_listener_impl = nullptr; } @@ -116,23 +131,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; 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 dd5727d09e..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. /// @@ -877,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 @@ -961,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..1627e37f8a 100644 --- a/auth/src/include/firebase/auth/types.h +++ b/auth/src/include/firebase/auth/types.h @@ -428,6 +428,9 @@ enum AuthError { kAuthErrorTokenRefreshUnavailable, #endif // INTERNAL_EXEPERIMENTAL + + /// An operation was attempted on an invalid User. + kAuthErrorInvalidUser, }; /// @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 ce3b4b6340..719446266b 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. /// @@ -332,6 +348,9 @@ class User : public UserInfoInterface { 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 @@ -343,12 +362,15 @@ 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. @@ -363,7 +385,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 LinkWithProvider_DEPRECATED( + FIREBASE_DEPRECATED Future LinkWithProvider_DEPRECATED( FederatedAuthProvider* provider) const; /// @deprecated This is a deprecated method. Please use @ref Unlink(const @@ -371,12 +393,12 @@ class User : public UserInfoInterface { /// /// 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_DEPRECATED(const char* provider); + FIREBASE_DEPRECATED Future Unlink_DEPRECATED(const char* provider); /// @deprecated /// /// Get results of the most recent call to @ref Unlink. - Future UnlinkLastResult_DEPRECATED() const; + FIREBASE_DEPRECATED Future UnlinkLastResult_DEPRECATED() const; /// @deprecated This is a deprecated method. Please use /// @ref UpdatePhoneNumberCredential(const PhoneAuthCredential&) instead. @@ -386,7 +408,7 @@ class User : public UserInfoInterface { /// shortcut to calling Unlink_DEPRECATED(phone_credential.provider().c_str()) /// and then LinkWithCredential_DEPRECATED(phone_credential). `credential` /// must have been created with @ref PhoneAuthProvider. - Future UpdatePhoneNumberCredential_DEPRECATED( + FIREBASE_DEPRECATED Future UpdatePhoneNumberCredential_DEPRECATED( const Credential& credential); /// @deprecated @@ -501,16 +523,17 @@ class User : public UserInfoInterface { virtual std::string phone_number() const; private: + // @deprecated User references to auth_data should only be needed during + // the Google I/O 23 breaking changes deprecation window. + // + // Internal only. + // + // 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. @@ -525,6 +548,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 c004c595ff..428f3ab80b 100644 --- a/auth/src/ios/auth_ios.mm +++ b/auth/src/ios/auth_ios.mm @@ -156,6 +156,13 @@ void UpdateCurrentUser(AuthData *auth_data) { // 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; @@ -218,6 +225,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; @@ -255,18 +269,19 @@ void LogHeartbeat(Auth *auth) { return MakeFuture(&futures, 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. +// 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; + 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) { @@ -276,8 +291,7 @@ void LogHeartbeat(Auth *auth) { 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 { @@ -315,27 +329,31 @@ AuthError AuthErrorFromNSError(NSError *_Nullable error) { } void SignInCallback(FIRUser *_Nullable user, NSError *_Nullable error, - SafeFutureHandle handle, AuthData *auth_data) { + SafeFutureHandle 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(handle)) { + // Finish off the asynchronous call so that the caller can read it. + future_impl.CompleteWithResult(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 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, handle, future_impl, auth_data); } void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error, - SafeFutureHandle handle, AuthData *auth_data) { + SafeFutureHandle handle, + ReferenceCountedFutureImpl &future_impl, AuthData *auth_data) { User *user = AssignUser(auth_result.user, auth_data); SignInResult result; @@ -355,9 +373,11 @@ 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(handle)) { + future_impl.CompleteWithResult(handle, AuthErrorFromNSError(error), + util::NSStringToString(error.localizedDescription).c_str(), + result); + } } Future Auth::SignInWithCustomToken_DEPRECATED(const char *token) { @@ -367,7 +387,7 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu [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, handle, futures, auth_data_); }]; return MakeFuture(&futures, handle); @@ -380,7 +400,7 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu [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, handle, futures, auth_data_); }]; return MakeFuture(&futures, handle); @@ -395,7 +415,7 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu [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, handle, futures, auth_data_); }]; return MakeFuture(&futures, handle); @@ -413,7 +433,7 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu [AuthImpl(auth_data_) signInAnonymouslyWithCompletion:^(FIRAuthDataResult *_Nullable auth_result, NSError *_Nullable error) { - SignInCallback(auth_result.user, error, handle, auth_data_); + SignInCallback(auth_result.user, error, handle, futures, auth_data_); }]; return MakeFuture(&futures, handle); @@ -433,7 +453,7 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu 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, handle, futures, auth_data_); }]; } return MakeFuture(&futures, handle); @@ -453,7 +473,7 @@ void SignInResultCallback(FIRAuthDataResult *_Nullable auth_result, NSError *_Nu 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, handle, futures, auth_data_); }]; } return MakeFuture(&futures, handle); diff --git a/auth/src/ios/common_ios.h b/auth/src/ios/common_ios.h index d6d471e811..f5d8809752 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; @@ -50,25 +54,118 @@ struct AuthDataIos { 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)); -} +// 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; + + Future LinkAndRetrieveDataWithCredential_DEPRECATED(AuthData *auth_data_, + const Credential &credential); + Future LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED() const; + + Future LinkWithProvider_DEPRECATED(AuthData *auth_data, + FederatedAuthProvider *provider); + Future LinkWithProviderLastResult_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 Unlink_DEPRECATED(AuthData *auth_data, const char *provider); + Future UnlinkLastResult_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 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 the creation and deletion of the vector of UserInfoInterface* + // allocations in provider_data_DEPRECATED(). + Mutex user_info_mutex_deprecated_; + + // 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); - } +/// 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 +184,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 +200,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 e256956f34..8a6daaaba7 100644 --- a/auth/src/ios/credential_ios.mm +++ b/auth/src/ios/credential_ios.mm @@ -408,21 +408,20 @@ explicit PhoneAuthProviderData(FIRPhoneAuthProvider* objc_provider) void LinkWithProviderGetCredentialCallback(FIRAuthCredential* _Nullable credential, NSError* _Nullable error, SafeFutureHandle handle, - AuthData* auth_data, + 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(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, handle, future_impl, + auth_data, ios_auth_provider); + }]; } } @@ -432,22 +431,22 @@ void LinkWithProviderGetCredentialCallback(FIRAuthCredential* _Nullable credenti void ReauthenticateWithProviderGetCredentialCallback(FIRAuthCredential* _Nullable credential, NSError* _Nullable error, SafeFutureHandle handle, - AuthData* auth_data, + 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(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, handle, + future_impl, auth_data, + ios_auth_provider); + }]; } } @@ -466,7 +465,7 @@ void ReauthenticateWithProviderGetCredentialCallback(FIRAuthCredential* _Nullabl signInWithProvider:ios_provider UIDelegate:nullptr completion:^(FIRAuthDataResult* _Nullable auth_result, NSError* _Nullable error) { - SignInResultWithProviderCallback(auth_result, error, handle, auth_data, + SignInResultWithProviderCallback(auth_result, error, handle, futures, auth_data, ios_provider); }]; return MakeFuture(&futures, handle); @@ -478,11 +477,12 @@ void ReauthenticateWithProviderGetCredentialCallback(FIRAuthCredential* _Nullabl } } -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_DEPRECATED, SignInResult()); + assert(user_internal); + auto handle = user_internal->future_data_.future_impl.SafeAlloc( + kUserFn_LinkWithProvider_DEPRECATED, SignInResult()); #if FIREBASE_PLATFORM_IOS FIROAuthProvider* ios_provider = (FIROAuthProvider*)[FIROAuthProvider providerWithProviderID:@(provider_data_.provider_id.c_str()) @@ -490,34 +490,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); - }]; - return MakeFuture(&futures, handle); + [ios_provider + getCredentialWithUIDelegate:nullptr + completion:^(FIRAuthCredential* _Nullable credential, + NSError* _Nullable error) { + LinkWithProviderGetCredentialCallback( + credential, error, handle, user_internal->future_data_.future_impl, + auth_data, user, ios_provider); + }]; + return MakeFuture(&user_internal->future_data_.future_impl, handle); } else { - Future future = MakeFuture(&futures, handle); - futures.CompleteWithResult(handle, kAuthErrorFailure, "Internal error constructing provider.", - SignInResult()); + Future future = MakeFuture(&user_internal->future_data_.future_impl, handle); + user_internal->future_data_.future_impl.CompleteWithResult( + handle, kAuthErrorFailure, "Internal error constructing provider.", SignInResult()); return future; } #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 future = MakeFuture(&user_internal->future_data_.future_impl, handle); + user_internal->future_data_.future_impl.Complete( + handle, kAuthErrorApiNotAvailable, + "OAuth provider linking is not supported on non-iOS Apple platforms."); #endif // FIREBASE_PLATFORM_IOS } -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_DEPRECATED, SignInResult()); + assert(user_internal); + auto handle = user_internal->future_data_.future_impl.SafeAlloc( + kUserFn_LinkWithProvider_DEPRECATED, SignInResult()); #if FIREBASE_PLATFORM_IOS FIROAuthProvider* ios_provider = (FIROAuthProvider*)[FIROAuthProvider providerWithProviderID:@(provider_data_.provider_id.c_str()) @@ -525,26 +530,30 @@ 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); - }]; - return MakeFuture(&futures, handle); + [ios_provider + getCredentialWithUIDelegate:nullptr + completion:^(FIRAuthCredential* _Nullable credential, + NSError* _Nullable error) { + ReauthenticateWithProviderGetCredentialCallback( + credential, error, handle, user_internal->future_data_.future_impl, + auth_data, user, ios_provider); + }]; + return MakeFuture(&user_internal->future_data_.future_impl, handle); } else { - Future future = MakeFuture(&futures, handle); - futures.CompleteWithResult(handle, kAuthErrorFailure, "Internal error constructing provider.", - SignInResult()); + Future future = MakeFuture(&user_internal->future_data_.future_impl, handle); + user_internal->future_data_.future_impl.CompleteWithResult( + handle, kAuthErrorFailure, "Internal error constructing provider.", SignInResult()); return future; } #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 future = MakeFuture(&user_internal->future_data_.future_impl, handle); + user_internal->future_data_.future_impl.Complete( + handle, kAuthErrorApiNotAvailable, + "OAuth reauthentication is not supported on non-iOS Apple platforms."); #endif // FIREBASE_PLATFORM_IOS } diff --git a/auth/src/ios/user_ios.mm b/auth/src/ios/user_ios.mm index 56d507ab29..80d48c20c4 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,407 @@ 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); + 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; + } + auth_data_ = auth_data; +} + +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) const { + 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() { + user_ = nil; + { + MutexLock user_info_lock(user_info_mutex_deprecated_); + clear_user_infos(); + } // 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); } } -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; } - 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); + 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]); + } + } + return local_user_infos; +} + +const std::vector &UserInternal::provider_data_DEPRECATED() { + MutexLock user_info_lock(user_info_mutex_deprecated_); + 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,174 +443,311 @@ 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 User::LinkWithCredential_DEPRECATED(const Credential &credential) { - if (!ValidUser(auth_data_)) { - return Future(); +Future UserInternal::SendEmailVerificationLastResult() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_SendEmailVerification)); +} + +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_DEPRECATED); - [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()) { + printf("DEDB LinkAndRetrieveDataWithCredential_DEPRECATED user is not valid\n"); + 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) { + NSLog(@"DEDB Completion auth_result: %p error: %p\n", auth_result, error); + SignInResultCallback(auth_result, error, callback_data->future_handle, + callback_data->future_data->future_impl, auth_data); + NSLog(@"DEDB Completion SignInResultCallback returned\n"); + // delete callback_data; + }]; + return future; } -Future User::LinkWithProvider_DEPRECATED(FederatedAuthProvider *provider) const { +Future UserInternal::LinkAndRetrieveDataWithCredentialLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_LinkAndRetrieveDataWithCredential_DEPRECATED)); +} + +Future UserInternal::LinkWithProvider_DEPRECATED(AuthData *auth_data, + FederatedAuthProvider *provider) { FIREBASE_ASSERT_RETURN(Future(), provider); - return provider->Link(auth_data_); + return provider->Link(auth_data, this); } -Future User::Unlink_DEPRECATED(const char *provider) { - 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_Unlink_DEPRECATED); - [UserImpl(auth_data_) unlinkFromProvider:@(provider) - completion:^(FIRUser *_Nullable user, NSError *_Nullable error) { - SignInCallback(user, error, handle, auth_data_); - }]; - return MakeFuture(&futures, handle); + + 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 User::UpdatePhoneNumberCredential_DEPRECATED(const Credential &credential) { - if (!ValidUser(auth_data_)) { - return Future(); - } - ReferenceCountedFutureImpl &futures = auth_data_->future_impl; - const auto handle = futures.SafeAlloc(kUserFn_UpdatePhoneNumberCredential_DEPRECATED); +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, kInvalidCredentialMessage, + callback_data->future_handle, &future_data_, (User *)nullptr); } + return future; #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); + return future; #endif // FIREBASE_PLATFORM_IOS - - return MakeFuture(&futures, handle); } -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 User::ReauthenticateAndRetrieveData_DEPRECATED(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( + 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_DEPRECATED, 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_DEPRECATED( - FederatedAuthProvider *provider) const { +Future UserInternal::ReauthenticateAndRetrieveDataLastResult_DEPRECATED() const { + return static_cast &>( + future_data_.future_impl.LastResult(kUserFn_ReauthenticateAndRetrieveData_DEPRECATED)); +} + +Future UserInternal::ReauthenticateWithProvider_DEPRECATED( + AuthData *auth_data, FederatedAuthProvider *provider) { FIREBASE_ASSERT_RETURN(Future(), provider); - return provider->Reauthenticate(auth_data_); + return provider->Reauthenticate(auth_data, this); } -Future User::Delete() { - if (!ValidUser(auth_data_)) { - return Future(); +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; @@ -323,36 +760,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 52693c0b6a..946a565c3e 100644 --- a/auth/src/user.cc +++ b/auth/src/user.cc @@ -19,20 +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, SendEmailVerification, void) -AUTH_RESULT_FN(User, UpdateUserProfile, void) -AUTH_RESULT_FN(User, LinkAndRetrieveDataWithCredential, SignInResult) -AUTH_RESULT_FN(User, Reload, void) -AUTH_RESULT_FN(User, Delete, void) - -AUTH_RESULT_DEPRECATED_FN(User, ReauthenticateAndRetrieveData, SignInResult) -AUTH_RESULT_DEPRECATED_FN(User, LinkWithCredential, User*) -AUTH_RESULT_DEPRECATED_FN(User, Unlink, User*) -AUTH_RESULT_DEPRECATED_FN(User, UpdatePhoneNumberCredential, User*) +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