Skip to content

Commit 6c1ac8c

Browse files
authored
Add the new method to update Auth Users Email (firebase#1544)
* Add the new method to update Auth Users Email * Update integration_test.cc
1 parent 3fd90d5 commit 6c1ac8c

File tree

12 files changed

+166
-2
lines changed

12 files changed

+166
-2
lines changed

auth/integration_test/src/integration_test.cc

+23
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,12 @@ TEST_F(FirebaseAuthTest, TestOperationsOnInvalidUser) {
816816
WaitForCompletionOrInvalidStatus(void_future, "SendEmailVerification");
817817
EXPECT_NE(void_future.error(), firebase::auth::kAuthErrorNone);
818818

819+
void_future = invalid_user.SendEmailVerificationBeforeUpdatingEmail(
820+
GenerateEmailAddress().c_str());
821+
WaitForCompletionOrInvalidStatus(void_future,
822+
"SendEmailVerificationBeforeUpdatingEmail");
823+
EXPECT_NE(void_future.error(), firebase::auth::kAuthErrorNone);
824+
819825
firebase::auth::User::UserProfile profile;
820826
void_future = invalid_user.UpdateUserProfile(profile);
821827
WaitForCompletionOrInvalidStatus(void_future, "UpdateUserProfile");
@@ -947,6 +953,23 @@ TEST_F(FirebaseAuthTest, TestUpdateEmailAndPassword_DEPRECATED) {
947953
DeleteUser_DEPRECATED();
948954
}
949955

956+
TEST_F(FirebaseAuthTest, TestVerifyBeforeUpdatingEmail) {
957+
std::string email = GenerateEmailAddress();
958+
WaitForCompletion(
959+
auth_->CreateUserWithEmailAndPassword(email.c_str(), kTestPassword),
960+
"CreateUserWithEmailAndPassword");
961+
firebase::auth::User user = auth_->current_user();
962+
EXPECT_TRUE(user.is_valid());
963+
964+
// Update the user's email and password.
965+
const std::string new_email = "new_" + email;
966+
WaitForCompletion(
967+
user.SendEmailVerificationBeforeUpdatingEmail(new_email.c_str()),
968+
"SendEmailVerificationBeforeUpdatingEmail");
969+
EXPECT_TRUE(user.is_valid());
970+
DeleteUser();
971+
}
972+
950973
TEST_F(FirebaseAuthTest, TestLinkAnonymousUserWithEmailCredential) {
951974
FLAKY_TEST_SECTION_BEGIN();
952975

auth/src/android/user_android.cc

+24
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ METHOD_LOOKUP_DEFINITION(tokenresult,
4343
X(ProviderData, "getProviderData", "()Ljava/util/List;"), \
4444
X(UpdateEmail, "updateEmail", "(Ljava/lang/String;)" \
4545
"Lcom/google/android/gms/tasks/Task;"), \
46+
X(VerifyBeforeUpdateEmail, "verifyBeforeUpdateEmail", \
47+
"(Ljava/lang/String;)Lcom/google/android/gms/tasks/Task;"), \
4648
X(UpdatePassword, "updatePassword", "(Ljava/lang/String;)" \
4749
"Lcom/google/android/gms/tasks/Task;"), \
4850
X(UpdateUserProfile, "updateProfile", \
@@ -782,6 +784,28 @@ Future<void> User::SendEmailVerification() {
782784
return MakeFuture(&futures, handle);
783785
}
784786

787+
Future<void> User::SendEmailVerificationBeforeUpdatingEmail(const char* email) {
788+
if (!ValidUser(auth_data_)) {
789+
return Future<void>();
790+
}
791+
ReferenceCountedFutureImpl& futures = auth_data_->future_impl;
792+
const auto handle =
793+
futures.SafeAlloc<void>(kUserFn_SendEmailVerificationBeforeUpdatingEmail);
794+
JNIEnv* env = Env(auth_data_);
795+
796+
jstring j_email = env->NewStringUTF(email);
797+
jobject pending_result = env->CallObjectMethod(
798+
UserImpl(auth_data_), user::GetMethodId(user::kVerifyBeforeUpdateEmail),
799+
j_email);
800+
env->DeleteLocalRef(j_email);
801+
802+
if (!CheckAndCompleteFutureOnError(env, &futures, handle)) {
803+
RegisterCallback(pending_result, handle, auth_data_, nullptr);
804+
env->DeleteLocalRef(pending_result);
805+
}
806+
return MakeFuture(&futures, handle);
807+
}
808+
785809
Future<void> User::Delete() {
786810
if (!ValidUser(auth_data_)) {
787811
return Future<void>();

auth/src/data.h

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ enum AuthApiFunction {
5656
kUserFn_ReauthenticateAndRetrieveData,
5757
kUserFn_ReauthenticateAndRetrieveData_DEPRECATED,
5858
kUserFn_SendEmailVerification,
59+
kUserFn_SendEmailVerificationBeforeUpdatingEmail,
5960
kUserFn_ConfirmEmailVerification,
6061
kUserFn_UpdateUserProfile,
6162
kUserFn_LinkWithCredential,

auth/src/desktop/rpcs/get_oob_confirmation_code_request.cc

+19
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,25 @@ GetOobConfirmationCodeRequest::CreateSendEmailVerificationRequest(
4747
return request;
4848
}
4949

50+
std::unique_ptr<GetOobConfirmationCodeRequest> GetOobConfirmationCodeRequest::
51+
CreateSendEmailVerificationBeforeUpdatingEmailRequest(
52+
::firebase::App& app, const char* api_key, const char* email,
53+
const char* language_code) {
54+
auto request = std::unique_ptr<GetOobConfirmationCodeRequest>( // NOLINT
55+
new GetOobConfirmationCodeRequest(app, api_key));
56+
request->application_data_->requestType = "VERIFY_AND_CHANGE_EMAIL";
57+
if (language_code != nullptr) {
58+
request->add_header(kHeaderFirebaseLocale, language_code);
59+
}
60+
if (email) {
61+
request->application_data_->newEmail = email;
62+
} else {
63+
LogError("No email token given.");
64+
}
65+
request->UpdatePostFields();
66+
return request;
67+
}
68+
5069
std::unique_ptr<GetOobConfirmationCodeRequest>
5170
GetOobConfirmationCodeRequest::CreateSendPasswordResetEmailRequest(
5271
::firebase::App& app, const char* api_key, const char* email,

auth/src/desktop/rpcs/get_oob_confirmation_code_request.h

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ class GetOobConfirmationCodeRequest : public AuthRequest {
3434
CreateSendEmailVerificationRequest(::firebase::App& app, const char* api_key,
3535
const char* language_code = nullptr);
3636

37+
static std::unique_ptr<GetOobConfirmationCodeRequest>
38+
CreateSendEmailVerificationBeforeUpdatingEmailRequest(
39+
::firebase::App& app, const char* api_key, const char* email,
40+
const char* language_code = nullptr);
41+
3742
static std::unique_ptr<GetOobConfirmationCodeRequest>
3843
CreateSendPasswordResetEmailRequest(::firebase::App& app, const char* api_key,
3944
const char* email,

auth/src/desktop/rpcs/request.fbs

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ table Request {
5757
deleteProvider:[string];
5858

5959
nonce:string;
60+
61+
newEmail:string;
6062
}
6163

6264
root_type Request;

auth/src/desktop/user_desktop.cc

+32
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,38 @@ Future<void> User::SendEmailVerification() {
953953
callback);
954954
}
955955

956+
Future<void> User::SendEmailVerificationBeforeUpdatingEmail(const char* email) {
957+
Promise<void> promise(&auth_data_->future_impl,
958+
kUserFn_SendEmailVerificationBeforeUpdatingEmail);
959+
if (!ValidateCurrentUser(&promise, auth_data_)) {
960+
return promise.LastResult();
961+
}
962+
963+
const char* language_code = nullptr;
964+
auto auth_impl = static_cast<AuthImpl*>(auth_data_->auth_impl);
965+
if (!auth_impl->language_code.empty()) {
966+
language_code = auth_impl->language_code.c_str();
967+
}
968+
969+
typedef GetOobConfirmationCodeRequest RequestT;
970+
auto request =
971+
RequestT::CreateSendEmailVerificationBeforeUpdatingEmailRequest(
972+
*auth_data_->app, GetApiKey(*auth_data_), email, language_code);
973+
974+
const auto callback = [](AuthDataHandle<void, RequestT>* const handle) {
975+
const auto response =
976+
GetResponse<GetOobConfirmationCodeResponse>(*handle->request);
977+
if (response.IsSuccessful()) {
978+
handle->promise.Complete();
979+
} else {
980+
FailPromise(&handle->promise, response.error_code());
981+
}
982+
};
983+
984+
return CallAsyncWithFreshToken(auth_data_, promise, std::move(request),
985+
callback);
986+
}
987+
956988
Future<void> User::Reload() {
957989
Promise<void> promise(&auth_data_->future_impl, kUserFn_Reload);
958990
if (!ValidateCurrentUser(&promise, auth_data_)) {

auth/src/include/firebase/auth/user.h

+15-2
Original file line numberDiff line numberDiff line change
@@ -255,14 +255,19 @@ class User : public UserInfoInterface {
255255
FIREBASE_DEPRECATED const std::vector<UserInfoInterface*>&
256256
provider_data_DEPRECATED() const;
257257

258+
/// @deprecated This is a deprecated method. Please use
259+
/// SendEmailVerificationBeforeUpdatingEmail(email) instead.
260+
///
258261
/// Sets the email address for the user.
259262
///
260263
/// May fail if there is already an email/password-based account for the same
261264
/// email address.
262-
Future<void> UpdateEmail(const char* email);
265+
FIREBASE_DEPRECATED Future<void> UpdateEmail(const char* email);
263266

267+
/// @deprecated
268+
///
264269
/// Get results of the most recent call to UpdateEmail.
265-
Future<void> UpdateEmailLastResult() const;
270+
FIREBASE_DEPRECATED Future<void> UpdateEmailLastResult() const;
266271

267272
/// Attempts to change the password for the current user.
268273
///
@@ -381,6 +386,14 @@ class User : public UserInfoInterface {
381386
/// Get results of the most recent call to SendEmailVerification.
382387
Future<void> SendEmailVerificationLastResult() const;
383388

389+
/// Send an email to verify the ownership of the account, then update
390+
/// to the new email.
391+
Future<void> SendEmailVerificationBeforeUpdatingEmail(const char* email);
392+
393+
/// Get results of the most recent call to
394+
/// SendEmailVerificationBeforeUpdatingEmail.
395+
Future<void> SendEmailVerificationBeforeUpdatingEmailLastResult() const;
396+
384397
/// Updates a subset of user profile information.
385398
Future<void> UpdateUserProfile(const UserProfile& profile);
386399

auth/src/ios/user_ios.mm

+15
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,21 @@ explicit IOSWrappedUserInfo(id<FIRUserInfo> user_info) : user_info_(user_info) {
188188
return MakeFuture(&futures, handle);
189189
}
190190

191+
Future<void> User::SendEmailVerificationBeforeUpdatingEmail(const char *email) {
192+
if (!ValidUser(auth_data_)) {
193+
return Future<void>();
194+
}
195+
ReferenceCountedFutureImpl &futures = auth_data_->future_impl;
196+
const auto handle = futures.SafeAlloc<void>(kUserFn_SendEmailVerificationBeforeUpdatingEmail);
197+
[UserImpl(auth_data_)
198+
sendEmailVerificationBeforeUpdatingEmail:@(email)
199+
completion:^(NSError *_Nullable error) {
200+
futures.Complete(handle, AuthErrorFromNSError(error),
201+
[error.localizedDescription UTF8String]);
202+
}];
203+
return MakeFuture(&futures, handle);
204+
}
205+
191206
Future<AuthResult> User::LinkWithCredential(const Credential &credential) {
192207
if (!ValidUser(auth_data_)) {
193208
return Future<AuthResult>();

auth/src/user.cc

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ AUTH_RESULT_FN(User, LinkWithCredential, AuthResult)
2626
AUTH_RESULT_FN(User, Reauthenticate, void)
2727
AUTH_RESULT_FN(User, ReauthenticateAndRetrieveData, AuthResult)
2828
AUTH_RESULT_FN(User, SendEmailVerification, void)
29+
AUTH_RESULT_FN(User, SendEmailVerificationBeforeUpdatingEmail, void)
2930
AUTH_RESULT_FN(User, Unlink, AuthResult)
3031
AUTH_RESULT_FN(User, UpdateUserProfile, void)
3132
AUTH_RESULT_FN(User, Reload, void)

auth/tests/user_test.cc

+27
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,33 @@ TEST_F(UserTest, TestSendEmailVerification) {
401401
Verify(result);
402402
}
403403

404+
TEST_F(UserTest, TestSendEmailVerificationBeforeUpdatingEmail) {
405+
// Test send email verification before updating.
406+
firebase::testing::cppsdk::ConfigSet(
407+
"{"
408+
" config:["
409+
" {fake:'FirebaseUser.sendEmailVerification',"
410+
" futuregeneric:{ticker:1}},"
411+
" {fake:'FIRUser.sendEmailVerificationWithCompletion:',"
412+
" futuregeneric:{ticker:1}},"
413+
" {"
414+
" fake: 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/"
415+
"getOobConfirmationCode?key=not_a_real_api_key',"
416+
" httpresponse: {"
417+
" header: ['HTTP/1.1 200 Ok','Server:mock server 101'],"
418+
" body: ['{"
419+
" \"kind\": \"identitytoolkit#GetOobConfirmationCodeResponse\","
420+
" \"email\": \"fake_email@fake_domain.com\""
421+
" }']"
422+
" }"
423+
" }"
424+
" ]"
425+
"}");
426+
Future<void> result =
427+
firebase_user_->SendEmailVerificationBeforeUpdatingEmail("[email protected]");
428+
Verify(result);
429+
}
430+
404431
TEST_F(UserTest, TestLinkWithCredential) {
405432
// Under the hood, since this is linking an email/password,
406433
// it is expecting a signUp call, followed by a getAccountInfo.

release_build_files/readme.md

+2
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,8 @@ code.
634634
### Upcoming Release
635635
- Changes
636636
- General (Android): Update to Firebase Android BoM version 32.7.2.
637+
- Auth: Add User::SendEmailVerificationBeforeUpdatingEmail, and deprecate
638+
the older method of updating emails, User::UpdateEmail.
637639

638640
### 11.8.0
639641
- Changes

0 commit comments

Comments
 (0)