Skip to content

Commit

Permalink
feat: add verifyBeforeUpdateEmail method (#741)
Browse files Browse the repository at this point in the history
* Added verifyBeforeUpdateEmail method to web, iOS, Android. Updated documents to include the new method.

* Updated README from wrong version to latest.

* Handle success and failure callbacks for Java. Alphabetize iOS method ordering. Update version number.

* Updated README definition for newEmail and added example.

* Added result callback to method that handles errors and success

* Fix prettier issues

* EmptyResultCallback change

* Added changeset

* Update packages/authentication/src/definitions.ts

---------

Co-authored-by: Robin Genz <[email protected]>
  • Loading branch information
ewwwgiddings and robingenz authored Oct 23, 2024
1 parent 2665fa9 commit 7af2032
Show file tree
Hide file tree
Showing 9 changed files with 191 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/tall-eagles-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@capacitor-firebase/authentication': minor
---

feat: add `verifyBeforeUpdateEmail` method
47 changes: 47 additions & 0 deletions packages/authentication/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,28 @@ const useEmulator = async () => {
port: 9099,
});
};

const verifyBeforeUpdateEmail = async () => {
const currentUser = await getCurrentUser();
if (!currentUser) {
return;
}
await FirebaseAuthentication.verifyBeforeUpdateEmail({
newEmail: '[email protected]',
actionCodeSettings: {
url: 'https://www.example.com/[email protected]&cartId=123',
iOS: {
bundleId: 'com.example.ios'
},
android: {
packageName: 'com.example.android',
installApp: true,
minimumVersion: '12'
},
handleCodeInApp: true
}
});
};
```

## API
Expand Down Expand Up @@ -457,6 +479,7 @@ const useEmulator = async () => {
* [`signOut()`](#signout)
* [`unlink(...)`](#unlink)
* [`updateEmail(...)`](#updateemail)
* [`verifyBeforeUpdateEmail(...)`](#verifyBeforeUpdateEmail)
* [`updatePassword(...)`](#updatepassword)
* [`updateProfile(...)`](#updateprofile)
* [`useAppLanguage()`](#useapplanguage)
Expand Down Expand Up @@ -1450,6 +1473,22 @@ Updates the email address of the currently signed in user.

--------------------

### verifyBeforeUpdateEmail(...)

```typescript
verifyBeforeUpdateEmail(options: VerifyBeforeUpdateEmailOptions) => Promise<void>
```

Verifies the email before updating the email address of the currently signed in user.

| Param | Type |
| ------------- | ----------------------------------------------------------------- |
| **`options`** | <code><a href="#verifybeforeupdateemailoptions">VerifyBeforeUpdateEmailOptions</a></code> |

**Since:** 6.2.0

--------------------


### updatePassword(...)

Expand Down Expand Up @@ -1953,6 +1992,14 @@ An interface covering the possible persistence mechanism types.
| **`newEmail`** | <code>string</code> | The new email address. | 0.2.2 |


#### VerifyBeforeUpdateEmailOptions

| Prop | Type | Description | Since |
| -------------- | ------------------- | ---------------------- | ----- |
| **`newEmail`** | <code>string</code> | The new email address to be verified before update. | 0.2.2 |
| **`actionCodeSettings`** | <code><a href="#actioncodesettings">ActionCodeSettings</a></code> | Structure that contains the required continue/state URL with optional Android and iOS bundle identifiers. | 1.1.0 |


#### UpdatePasswordOptions

| Prop | Type | Description | Since |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,18 @@ public void updateEmail(FirebaseUser user, @NonNull String newEmail, @NonNull Ru
);
}

public void verifyBeforeUpdateEmail(
FirebaseUser user,
@NonNull String newEmail,
@NonNull ActionCodeSettings actionCodeSettings,
@NonNull EmptyResultCallback callback
) {
user
.verifyBeforeUpdateEmail(newEmail, actionCodeSettings)
.addOnSuccessListener(unused -> callback.success())
.addOnFailureListener(exception -> callback.error(exception));
}

public void updatePassword(FirebaseUser user, @NonNull String newPassword, @NonNull Runnable callback) {
user
.updatePassword(newPassword)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,50 @@ public void updateEmail(PluginCall call) {
}
}

@PluginMethod
public void verifyBeforeUpdateEmail(PluginCall call) {
try {
String newEmail = call.getString("newEmail");
if (newEmail == null) {
call.reject(ERROR_NEW_EMAIL_MISSING);
return;
}

FirebaseUser user = implementation.getCurrentUser();
if (user == null) {
call.reject(ERROR_NO_USER_SIGNED_IN);
return;
}

JSObject settings = call.getObject("actionCodeSettings");
if (settings == null) {
call.reject(ERROR_ACTION_CODE_SETTINGS_MISSING);
return;
}
ActionCodeSettings actionCodeSettings = FirebaseAuthenticationHelper.createActionCodeSettings(settings);

EmptyResultCallback callback = new EmptyResultCallback() {
@Override
public void success() {
call.resolve();
}

@Override
public void error(Exception exception) {
Logger.error(TAG, exception.getMessage(), exception);
String code = FirebaseAuthenticationHelper.createErrorCode(exception);
call.reject(exception.getMessage(), code);
}
};

implementation.verifyBeforeUpdateEmail(user, newEmail, actionCodeSettings, callback);
} catch (Exception exception) {
Logger.error(TAG, exception.getMessage(), exception);
String code = FirebaseAuthenticationHelper.createErrorCode(exception);
call.reject(exception.getMessage(), code);
}
}

@PluginMethod
public void updatePassword(PluginCall call) {
try {
Expand Down
13 changes: 13 additions & 0 deletions packages/authentication/ios/Plugin/FirebaseAuthentication.swift
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,19 @@ public typealias AuthStateChangedObserver = () -> Void
}
}

@objc func verifyBeforeUpdateEmail(_ newEmail: String, actionCodeSettings: ActionCodeSettings, completion: @escaping (Error?) -> Void) {
guard let user = self.getCurrentUser() else {
completion(RuntimeError(plugin.errorNoUserSignedIn))
return
}

let completion: (Error?) -> Void = { error in
completion(error)
}

user.sendEmailVerification(beforeUpdatingEmail: newEmail, actionCodeSettings: actionCodeSettings, completion: completion)
}

@objc func sendPasswordResetEmail(_ options: SendPasswordResetEmailOptions, completion: @escaping (Error?) -> Void) {
let email = options.getEmail()
let actionCodeSettings = options.getActionCodeSettings()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,5 @@
CAP_PLUGIN_METHOD(updateProfile, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(useAppLanguage, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(useEmulator, CAPPluginReturnPromise);
CAP_PLUGIN_METHOD(verifyBeforeUpdateEmail, CAPPluginReturnPromise);
)
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,32 @@ public class FirebaseAuthenticationPlugin: CAPPlugin {
})
}

@objc func verifyBeforeUpdateEmail(_ call: CAPPluginCall) {
guard let newEmail = call.getString("newEmail") else {
call.reject(errorNewEmailMissing)
return
}

guard let actionCodeSettingsDict = call.getObject("actionCodeSettings") else {
call.reject(errorActionCodeSettingsMissing)
return
}
guard let actionCodeSettings = FirebaseAuthenticationHelper.createActionCodeSettings(actionCodeSettingsDict) else {
call.reject(errorActionCodeSettingsMissing)
return
}

implementation?.verifyBeforeUpdateEmail(newEmail, actionCodeSettings: actionCodeSettings, completion: { error in
if let error = error {
CAPLog.print("[", self.tag, "] ", error)
let code = FirebaseAuthenticationHelper.createErrorCode(error: error)
call.reject(error.localizedDescription, code)
return
}
call.resolve()
})
}

@objc func updatePassword(_ call: CAPPluginCall) {
guard let newPassword = call.getString("newPassword") else {
call.reject(errorNewPasswordMissing)
Expand Down
26 changes: 26 additions & 0 deletions packages/authentication/src/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,14 @@ export interface FirebaseAuthenticationPlugin {
* @since 0.2.0
*/
useEmulator(options: UseEmulatorOptions): Promise<void>;
/**
* Verifies the new email address before updating the email address of the currently signed in user.
*
* @since 6.3.0
*/
verifyBeforeUpdateEmail(
options: VerifyBeforeUpdateEmailOptions,
): Promise<void>;
/**
* Listen for the user's sign-in state changes.
*
Expand Down Expand Up @@ -780,6 +788,24 @@ export interface UpdateEmailOptions {
newEmail: string;
}

/**
* @since 6.3.0
*/
export interface VerifyBeforeUpdateEmailOptions {
/**
* The new email address to be verified before update.
*
* @since 6.3.0
*/
newEmail: string;
/**
* The action code settings
*
* @since 6.3.0
*/
actionCodeSettings: ActionCodeSettings;
}

/**
* @since 0.2.2
*/
Expand Down
17 changes: 17 additions & 0 deletions packages/authentication/src/web.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
updateEmail,
updatePassword,
updateProfile,
verifyBeforeUpdateEmail,
} from 'firebase/auth';

import type {
Expand Down Expand Up @@ -102,6 +103,7 @@ import type {
User,
UserInfo,
UserMetadata,
VerifyBeforeUpdateEmailOptions,
} from './definitions';
import { Persistence, ProviderId } from './definitions';

Expand Down Expand Up @@ -761,6 +763,21 @@ export class FirebaseAuthenticationWeb
}
}

public async verifyBeforeUpdateEmail(
options: VerifyBeforeUpdateEmailOptions,
): Promise<void> {
const auth = getAuth();
const currentUser = auth.currentUser;
if (!currentUser) {
throw new Error(FirebaseAuthenticationWeb.ERROR_NO_USER_SIGNED_IN);
}
return verifyBeforeUpdateEmail(
currentUser,
options?.newEmail,
options?.actionCodeSettings,
);
}

private handleAuthStateChange(user: FirebaseUser | null): void {
const userResult = this.createUserResult(user);
const change: AuthStateChange = {
Expand Down

0 comments on commit 7af2032

Please sign in to comment.