Skip to content

Commit c208b23

Browse files
authored
iOS support for multiple User objects (#1242)
Update auth internals to support returning Future object for the new API while also support returning Future<User*> objects for the deprecated API on iOS. Changes does not include the new Future methods.
1 parent b247244 commit c208b23

File tree

15 files changed

+1141
-373
lines changed

15 files changed

+1141
-373
lines changed

auth/integration_test/src/integration_test.cc

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ void FirebaseAuthTest::Initialize() {
162162

163163
::firebase::ModuleInitializer initializer;
164164
initializer.Initialize(app_, &auth_, [](::firebase::App* app, void* target) {
165-
LogDebug("Try to initialize Firebase Auth");
166165
firebase::InitResult result;
167166
firebase::auth::Auth** auth_ptr =
168167
reinterpret_cast<firebase::auth::Auth**>(target);
@@ -176,8 +175,6 @@ void FirebaseAuthTest::Initialize() {
176175
ASSERT_EQ(initializer.InitializeLastResult().error(), 0)
177176
<< initializer.InitializeLastResult().error_message();
178177

179-
LogDebug("Successfully initialized Firebase Auth.");
180-
181178
initialized_ = true;
182179
}
183180

@@ -516,8 +513,9 @@ TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential) {
516513
firebase::auth::Credential credential =
517514
firebase::auth::EmailAuthProvider::GetCredential(email.c_str(),
518515
kTestPassword);
519-
WaitForCompletion(user->LinkAndRetrieveDataWithCredential(credential),
520-
"LinkAndRetrieveDataWithCredential");
516+
WaitForCompletion(
517+
user->LinkAndRetrieveDataWithCredential_DEPRECATED(credential),
518+
"LinkAndRetrieveDataWithCredential_DEPRECATED");
521519
WaitForCompletion(user->Unlink_DEPRECATED(credential.provider().c_str()),
522520
"Unlink");
523521
SignOut();
@@ -768,10 +766,12 @@ TEST_F(FirebaseAuthTest, TestAuthPersistenceWithEmailSignin) {
768766
// Save the old provider ID list so we can make sure it's the same once
769767
// it's loaded again.
770768
std::vector<std::string> prev_provider_data_ids;
771-
for (int i = 0; i < auth_->current_user_DEPRECATED()->provider_data().size();
769+
for (int i = 0;
770+
i < auth_->current_user_DEPRECATED()->provider_data_DEPRECATED().size();
772771
i++) {
773-
prev_provider_data_ids.push_back(
774-
auth_->current_user_DEPRECATED()->provider_data()[i]->provider_id());
772+
prev_provider_data_ids.push_back(auth_->current_user_DEPRECATED()
773+
->provider_data_DEPRECATED()[i]
774+
->provider_id());
775775
}
776776
Terminate();
777777
ProcessEvents(2000);
@@ -782,10 +782,12 @@ TEST_F(FirebaseAuthTest, TestAuthPersistenceWithEmailSignin) {
782782
// Make sure the provider IDs are the same as they were before.
783783
EXPECT_EQ(auth_->current_user_DEPRECATED()->provider_id(), prev_provider_id);
784784
std::vector<std::string> loaded_provider_data_ids;
785-
for (int i = 0; i < auth_->current_user_DEPRECATED()->provider_data().size();
785+
for (int i = 0;
786+
i < auth_->current_user_DEPRECATED()->provider_data_DEPRECATED().size();
786787
i++) {
787-
loaded_provider_data_ids.push_back(
788-
auth_->current_user_DEPRECATED()->provider_data()[i]->provider_id());
788+
loaded_provider_data_ids.push_back(auth_->current_user_DEPRECATED()
789+
->provider_data_DEPRECATED()[i]
790+
->provider_id());
789791
}
790792
EXPECT_TRUE(loaded_provider_data_ids == prev_provider_data_ids);
791793

auth/src/auth.cc

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ Auth* Auth::GetAuth(App* app, InitResult* init_result_out) {
8181

8282
// Create a new Auth and initialize.
8383
Auth* auth = new Auth(app, auth_impl);
84-
LogDebug("Creating Auth %p for App %p", auth, app);
8584

8685
// Stick it in the global map so we remember it, and can delete it on
8786
// shutdown.

auth/src/common.cc

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
namespace firebase {
2222
namespace auth {
2323

24+
const char* kUserNotInitializedErrorMessage =
25+
"Operation attmpted on an invalid User object.";
26+
const char* kPhoneAuthNotSupportedErrorMessage =
27+
"Phone Auth is not supported on this platform.";
28+
2429
// static member variables
2530
const uint32_t PhoneAuthProvider::kMaxTimeoutMs = 3000;
2631

@@ -47,6 +52,59 @@ ReferenceCountedFutureImpl* GetCredentialFutureImpl() {
4752
return future_data->api();
4853
}
4954

55+
void CompleteFuture(int error, const char* error_msg,
56+
SafeFutureHandle<void> handle, FutureData* future_data) {
57+
if (future_data->future_impl.ValidFuture(handle)) {
58+
future_data->future_impl.Complete(handle, error, error_msg);
59+
}
60+
}
61+
62+
void CompleteFuture(int error, const char* error_msg,
63+
SafeFutureHandle<std::string> handle,
64+
FutureData* future_data, const std::string& result) {
65+
if (future_data->future_impl.ValidFuture(handle)) {
66+
future_data->future_impl.CompleteWithResult(handle, error, error_msg,
67+
result);
68+
}
69+
}
70+
71+
void CompleteFuture(int error, const char* error_msg,
72+
SafeFutureHandle<User*> handle, FutureData* future_data,
73+
User* user) {
74+
if (future_data->future_impl.ValidFuture(handle)) {
75+
future_data->future_impl.CompleteWithResult(handle, error, error_msg, user);
76+
}
77+
}
78+
79+
void CompleteFuture(int error, const char* error_msg,
80+
SafeFutureHandle<SignInResult> handle,
81+
FutureData* future_data, SignInResult sign_in_result) {
82+
if (future_data->future_impl.ValidFuture(handle)) {
83+
future_data->future_impl.CompleteWithResult(handle, error, error_msg,
84+
sign_in_result);
85+
}
86+
}
87+
88+
// For calls that aren't asynchronous, we can create and complete at the
89+
// same time.
90+
Future<void> CreateAndCompleteFuture(int fn_idx, int error,
91+
const char* error_msg,
92+
FutureData* future_data) {
93+
SafeFutureHandle<void> handle = CreateFuture<void>(fn_idx, future_data);
94+
CompleteFuture(error, error_msg, handle, future_data);
95+
return MakeFuture(&future_data->future_impl, handle);
96+
}
97+
98+
Future<std::string> CreateAndCompleteFuture(int fn_idx, int error,
99+
const char* error_msg,
100+
FutureData* future_data,
101+
const std::string& result) {
102+
SafeFutureHandle<std::string> handle =
103+
CreateFuture<std::string>(fn_idx, future_data);
104+
CompleteFuture(error, error_msg, handle, future_data, result);
105+
return MakeFuture(&future_data->future_impl, handle);
106+
}
107+
50108
void CleanupCredentialFutureImpl() {
51109
StaticFutureData::CleanupFutureDataForModule(&kCredentialFutureIdentifier);
52110
}

auth/src/common.h

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@
1717
#ifndef FIREBASE_AUTH_SRC_COMMON_H_
1818
#define FIREBASE_AUTH_SRC_COMMON_H_
1919

20+
#include <string>
21+
2022
#include "auth/src/data.h"
2123

2224
namespace firebase {
2325
namespace auth {
2426

27+
// Error messages used for completing futures. These match the error codes in
28+
// the AdErrorCode enumeration in the C++ API.
29+
extern const char* kUserNotInitializedErrorMessage;
30+
extern const char* kPhoneAuthNotSupportedErrorMessage;
31+
2532
// Enumeration for Credential API functions that return a Future.
2633
// This allows us to hold a Future for the most recent call to that API.
2734
enum CredentialApiFunction {
@@ -30,6 +37,59 @@ enum CredentialApiFunction {
3037
kNumCredentialFunctions
3138
};
3239

40+
// Hold backing data for returned Futures.
41+
struct FutureData {
42+
explicit FutureData(int num_functions_that_return_futures)
43+
: future_impl(num_functions_that_return_futures) {}
44+
45+
// Handle calls from Futures that the API returns.
46+
ReferenceCountedFutureImpl future_impl;
47+
};
48+
49+
template <class T>
50+
struct FutureCallbackData {
51+
FutureData* future_data;
52+
SafeFutureHandle<T> future_handle;
53+
};
54+
55+
// Create a future and update the corresponding last result.
56+
template <class T>
57+
SafeFutureHandle<T> CreateFuture(int fn_idx, FutureData* future_data) {
58+
return future_data->future_impl.SafeAlloc<T>(fn_idx);
59+
}
60+
61+
// Mark a Future<void> as complete.
62+
void CompleteFuture(int error, const char* error_msg,
63+
SafeFutureHandle<void> handle, FutureData* future_data);
64+
65+
// Mark a Future<std::string> as complete
66+
void CompleteFuture(int error, const char* error_msg,
67+
SafeFutureHandle<std::string> handle,
68+
FutureData* future_data, const std::string& result);
69+
70+
// Mark a Future<User *> as complete
71+
void CompleteFuture(int error, const char* error_msg,
72+
SafeFutureHandle<User*> handle, FutureData* future_data,
73+
User* user);
74+
75+
// Mark a Future<SignInResult> as complete
76+
void CompleteFuture(int error, const char* error_msg,
77+
SafeFutureHandle<SignInResult> handle,
78+
FutureData* future_data, SignInResult result);
79+
80+
// For calls that aren't asynchronous, create and complete a Future<void> at
81+
// the same time.
82+
Future<void> CreateAndCompleteFuture(int fn_idx, int error,
83+
const char* error_msg,
84+
FutureData* future_data);
85+
86+
// For calls that aren't asynchronous, create and complete a
87+
// Future<std::string> at the same time.
88+
Future<std::string> CreateAndCompleteFuture(int fn_idx, int error,
89+
const char* error_msg,
90+
FutureData* future_data,
91+
const std::string& result);
92+
3393
// Platform-specific method to create the wrapped Auth class.
3494
void* CreatePlatformAuth(App* app);
3595

@@ -62,7 +122,7 @@ void LogHeartbeat(Auth* auth);
62122

63123
// Returns true if `auth_data` has a user that's currently active.
64124
inline bool ValidUser(const AuthData* auth_data) {
65-
return auth_data->user_impl != nullptr;
125+
return auth_data->deprecated_fields.user_deprecated->is_valid();
66126
}
67127

68128
// Notify all the listeners of the state change.

auth/src/data.h

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,20 @@
2727
namespace firebase {
2828
namespace auth {
2929

30+
// @deprecated
31+
//
32+
// Fields that should be removed when the Auth Breaking Changes Deprecation
33+
// window ends.
34+
struct AuthDataDeprecatedFields {
35+
// Used to return User* objects from deprecated methods.
36+
User* user_deprecated;
37+
38+
// Internal implementation of user_deprecated. This object's contains a
39+
// pointer the platform specific user object, which is updated on User
40+
// operations.
41+
UserInternal* user_internal_deprecated;
42+
};
43+
3044
// Enumeration for API functions that return a Future.
3145
// This allows us to hold a Future for the most recent call to that API.
3246
enum AuthApiFunction {
@@ -41,7 +55,15 @@ enum AuthApiFunction {
4155
kAuthFn_CreateUserWithEmailAndPassword_DEPRECATED,
4256
kAuthFn_SendPasswordResetEmail,
4357

44-
// External functions in the User API.
58+
// Internal functions that are still handles, but are only used internally:
59+
kInternalFn_GetTokenForRefresher,
60+
kInternalFn_GetTokenForFunctionRegistry,
61+
62+
kAuthFnCount
63+
};
64+
65+
// Constants representing each User function that returns a Future.
66+
enum UserFn {
4567
kUserFn_GetToken,
4668
kUserFn_UpdateEmail,
4769
kUserFn_UpdatePassword,
@@ -51,19 +73,15 @@ enum AuthApiFunction {
5173
kUserFn_ConfirmEmailVerification,
5274
kUserFn_UpdateUserProfile,
5375
kUserFn_LinkWithCredential_DEPRECATED,
54-
kUserFn_LinkAndRetrieveDataWithCredential,
76+
kUserFn_LinkAndRetrieveDataWithCredential_DEPRECATED,
5577
kUserFn_LinkWithProvider_DEPRECATED,
5678
kUserFn_ReauthenticateWithProvider_DEPRECATED,
5779
kUserFn_Unlink_DEPRECATED,
5880
kUserFn_UpdatePhoneNumberCredential_DEPRECATED,
5981
kUserFn_Reload,
6082
kUserFn_Delete,
6183

62-
// Internal functions that are still handles, but are only used internally:
63-
kInternalFn_GetTokenForRefresher,
64-
kInternalFn_GetTokenForFunctionRegistry,
65-
66-
kNumAuthFunctions
84+
kUserFnCount
6785
};
6886

6987
/// Delete all the user_infos in auth_data and reset the length to zero.
@@ -76,10 +94,8 @@ struct AuthData {
7694
AuthData()
7795
: app(nullptr),
7896
auth(nullptr),
79-
future_impl(kNumAuthFunctions),
80-
current_user(this),
97+
future_impl(kAuthFnCount),
8198
auth_impl(nullptr),
82-
user_impl(nullptr),
8399
listener_impl(nullptr),
84100
id_token_listener_impl(nullptr),
85101
expect_id_token_listener_callback(false),
@@ -96,7 +112,6 @@ struct AuthData {
96112
app = nullptr;
97113
auth = nullptr;
98114
auth_impl = nullptr;
99-
user_impl = nullptr;
100115
listener_impl = nullptr;
101116
id_token_listener_impl = nullptr;
102117
}
@@ -116,23 +131,24 @@ struct AuthData {
116131
/// Backpointer to the external Auth class that holds this internal data.
117132
Auth* auth;
118133

134+
/// @deprecated Remove when Auth deprecation APIs are removed.
135+
///
136+
/// Contains a User object that's updated whenever the current user changes.
137+
/// This is used to return User* values from deprecated Auth and User
138+
/// methods. These methods have been replaced with methods that return
139+
/// Users by value (now that we can copy users.)
140+
AuthDataDeprecatedFields deprecated_fields;
141+
119142
/// Handle calls from Futures that the API returns.
120143
ReferenceCountedFutureImpl future_impl;
121144

122145
/// Identifier used to track futures associated with future_impl.
123146
std::string future_api_id;
124147

125-
/// Unique user for this Auth. Note: we only support one user per Auth.
126-
User current_user;
127-
128148
/// Platform-dependent implementation of Auth (that we're wrapping).
129149
/// For example, on Android `jobject`.
130150
void* auth_impl;
131151

132-
/// Platform-dependent implementation of User (that we're wrapping).
133-
/// For example, on iOS `FIRUser`.
134-
void* user_impl;
135-
136152
/// Platform-dependent implementation of AuthStateListener (that we're
137153
/// wrapping). For example, on Android `jobject`.
138154
void* listener_impl;

auth/src/desktop/user_desktop.h

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,51 @@
2626
namespace firebase {
2727
namespace auth {
2828

29-
// LINT.IfChange
29+
class UserInternal {
30+
public:
31+
// The user's ID, unique to the Firebase project.
32+
std::string uid;
33+
34+
// The associated email, if any.
35+
std::string email;
36+
37+
// The display name, if any.
38+
std::string display_name;
39+
40+
// Associated photo url, if any.
41+
std::string photo_url;
42+
43+
// A provider ID for the user e.g. "Facebook".
44+
std::string provider_id;
45+
46+
// The user's phone number, if any.
47+
std::string phone_number;
48+
49+
// Whether is anonymous.
50+
bool is_anonymous;
51+
52+
// Whether email is verified.
53+
bool is_email_verified;
54+
55+
// Tokens for authentication and authorization.
56+
std::string id_token; // an authorization code or access_token
57+
std::string refresh_token;
58+
std::string access_token;
59+
60+
// The approximate expiration date of the access token.
61+
std::time_t access_token_expiration_date;
62+
63+
// Whether or not the user can be authenticated by provider 'password'.
64+
bool has_email_password_credential;
65+
66+
/// The last sign in UTC timestamp in milliseconds.
67+
/// See https://en.wikipedia.org/wiki/Unix_time for details of UTC.
68+
uint64_t last_sign_in_timestamp;
69+
70+
/// The Firebase user creation UTC timestamp in milliseconds.
71+
uint64_t creation_timestamp;
72+
};
73+
3074
// The desktop-specific UserInfo implementation.
3175
struct UserInfoImpl {
3276
// Note: since Visual Studio 2013 and below don't autogenerate move

0 commit comments

Comments
 (0)