diff --git a/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java b/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java index c74ba7e2a0..b0ded9473b 100644 --- a/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java +++ b/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java @@ -599,6 +599,52 @@ public void sendEmailVerification( } } + /** + * verifyBeforeUpdateEmail + * + * @param promise + */ + @ReactMethod + public void verifyBeforeUpdateEmail( + String appName, + String email, + ReadableMap actionCodeSettings, + final Promise promise + ) { + FirebaseApp firebaseApp = FirebaseApp.getInstance(appName); + final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp); + + FirebaseUser user = firebaseAuth.getCurrentUser(); + Log.d(TAG, "verifyBeforeUpdateEmail"); + + if (user == null) { + promiseNoUser(promise, false); + Log.e(TAG, "verifyBeforeUpdateEmail:failure:noCurrentUser"); + } else { + OnCompleteListener listener = task -> { + if (task.isSuccessful()) { + Log.d(TAG, "verifyBeforeUpdateEmail:onComplete:success"); + promiseWithUser(firebaseAuth.getCurrentUser(), promise); + } else { + Exception exception = task.getException(); + Log.e(TAG, "verifyBeforeUpdateEmail:onComplete:failure", exception); + promiseRejectAuthException(promise, exception); + } + }; + + if (actionCodeSettings == null) { + user + .verifyBeforeUpdateEmail(email) + .addOnCompleteListener(getExecutor(), listener); + } else { + ActionCodeSettings settings = buildActionCodeSettings(actionCodeSettings); + user + .verifyBeforeUpdateEmail(email, settings) + .addOnCompleteListener(getExecutor(), listener); + } + } + } + /** * updateEmail * diff --git a/e2e/user.e2e.js b/e2e/user.e2e.js index 8e38e162fe..5c6602b48d 100644 --- a/e2e/user.e2e.js +++ b/e2e/user.e2e.js @@ -154,6 +154,160 @@ describe('auth().currentUser', () => { }); describe('sendEmailVerification()', () => { + it('should error if actionCodeSettings.url is not present', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({}); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.url' expected a string value."); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.url is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ url: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.url' expected a string value."); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.dynamicLinkDomain is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase + .auth() + .currentUser.sendEmailVerification({ url: 'string', dynamicLinkDomain: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.dynamicLinkDomain' expected a string value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if handleCodeInApp is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ url: 'string', handleCodeInApp: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.handleCodeInApp' expected a boolean value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.iOS is not an object', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ url: 'string', iOS: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.iOS' expected an object value."); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.iOS.bundleId is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase + .auth() + .currentUser.sendEmailVerification({ url: 'string', iOS: { bundleId: 123 } }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.android is not an object', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ url: 'string', android: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.android' expected an object value."); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.android.packageName is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase + .auth() + .currentUser.sendEmailVerification({ url: 'string', android: { packageName: 123 } }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.packageName' expected a string value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.android.installApp is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ + url: 'string', + android: { packageName: 'packageName', installApp: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.installApp' expected a boolean value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.android.minimumVersion is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.sendEmailVerification({ + url: 'string', + android: { packageName: 'packageName', minimumVersion: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + it('should not error', async () => { const random = Utils.randString(12, '#aA'); const email = `${random}@${random}.com`; @@ -204,6 +358,254 @@ describe('auth().currentUser', () => { }); }); + describe('verifyBeforeUpdateEmail()', () => { + it('should error if newEmail is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(123); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'newEmail' expected a string value"); + } + await firebase.auth().currentUser.delete(); + }); + it('should error if actionCodeSettings.url is not present', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, {}); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.url' expected a string value."); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.url is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { url: 123 }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.url' expected a string value."); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.dynamicLinkDomain is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + dynamicLinkDomain: 123, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.dynamicLinkDomain' expected a string value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if handleCodeInApp is not a boolean', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + handleCodeInApp: 123, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.handleCodeInApp' expected a boolean value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.iOS is not an object', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + iOS: 123, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.iOS' expected an object value."); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.iOS.bundleId is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + iOS: { bundleId: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.android is not an object', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + android: 123, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql("'actionCodeSettings.android' expected an object value."); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.android.packageName is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + android: { packageName: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.packageName' expected a string value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.android.installApp is not a boolean', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + android: { packageName: 'string', installApp: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.installApp' expected a boolean value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + + it('should error if actionCodeSettings.android.minimumVersion is not a string', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + await firebase.auth().createUserWithEmailAndPassword(email, random); + try { + firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, { + url: 'string', + android: { packageName: 'string', minimumVersion: 123 }, + }); + return Promise.reject(new Error('it did not error')); + } catch (error) { + error.message.should.containEql( + "'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + } + await firebase.auth().currentUser.delete(); + }); + it('should not error', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + + try { + await firebase.auth().createUserWithEmailAndPassword(email, random); + await firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail); + } catch (_) { + return Promise.reject("'verifyBeforeUpdateEmail()' did not work"); + } + await firebase.auth().currentUser.delete(); + }); + + it('should work with actionCodeSettings', async () => { + const random = Utils.randString(12, '#aA'); + const random2 = Utils.randString(12, '#aA'); + const email = `${random}@${random}.com`; + const updateEmail = `${random2}@${random2}.com`; + const actionCodeSettings = { + url: 'https://react-native-firebase-testing.firebaseapp.com/foo', + }; + try { + await firebase.auth().createUserWithEmailAndPassword(email, random); + await firebase.auth().currentUser.verifyBeforeUpdateEmail(updateEmail, actionCodeSettings); + await firebase.auth().currentUser.delete(); + } catch (error) { + try { + await firebase.auth().currentUser.delete(); + } catch (_) { + /* do nothing */ + } + + return Promise.reject("'verifyBeforeUpdateEmail()' with 'actionCodeSettings' did not work"); + } + return Promise.resolve(); + }); + }); describe('unlink()', () => { it('should unlink the email address', async () => { const random = Utils.randString(12, '#aA'); diff --git a/ios/RNFBAuth/RNFBAuthModule.m b/ios/RNFBAuth/RNFBAuthModule.m index 246dbcf95c..392e8c93f5 100644 --- a/ios/RNFBAuth/RNFBAuthModule.m +++ b/ios/RNFBAuth/RNFBAuthModule.m @@ -329,6 +329,34 @@ - (void)invalidate { } } +RCT_EXPORT_METHOD(verifyBeforeUpdateEmail: + (FIRApp *) firebaseApp + :(NSString *) email + :(NSDictionary *) actionCodeSettings + :(RCTPromiseResolveBlock) resolve + :(RCTPromiseRejectBlock) reject +) { + FIRUser *user = [FIRAuth authWithApp:firebaseApp].currentUser; + if (user) { + id handler = ^(NSError *_Nullable error) { + if (error) { + [self promiseRejectAuthException:reject error:error]; + } else { + FIRUser *userAfterUpdate = [FIRAuth authWithApp:firebaseApp].currentUser; + [self promiseWithUser:resolve rejecter:reject user:userAfterUpdate]; + } + }; + if (actionCodeSettings) { + FIRActionCodeSettings *settings = [self buildActionCodeSettings:actionCodeSettings]; + [user sendEmailVerificationBeforeUpdatingEmail:email actionCodeSettings:settings completion:handler]; + } else { + [user sendEmailVerificationBeforeUpdatingEmail:email completion:handler]; + } + } else { + [self promiseNoUser:resolve rejecter:reject isError:YES]; + } +} + RCT_EXPORT_METHOD(updateEmail: (FIRApp *) firebaseApp :(NSString *) email diff --git a/lib/User.js b/lib/User.js index 0d7472fbef..179a50c8a1 100644 --- a/lib/User.js +++ b/lib/User.js @@ -15,7 +15,7 @@ * */ -import { isObject, isString } from '@react-native-firebase/app/lib/common'; +import { isObject, isString, isUndefined, isBoolean } from '@react-native-firebase/app/lib/common'; export default class User { constructor(auth, user) { @@ -107,6 +107,68 @@ export default class User { "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.url' expected a string value.", ); } + + if ( + !isUndefined(actionCodeSettings.dynamicLinkDomain) && + !isString(actionCodeSettings.dynamicLinkDomain) + ) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.dynamicLinkDomain' expected a string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.handleCodeInApp) && + !isBoolean(actionCodeSettings.handleCodeInApp) + ) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", + ); + } + + if (!isUndefined(actionCodeSettings.iOS)) { + if (!isObject(actionCodeSettings.iOS)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.iOS' expected an object value.", + ); + } + if (!isString(actionCodeSettings.iOS.bundleId)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + } + } + + if (!isUndefined(actionCodeSettings.android)) { + if (!isObject(actionCodeSettings.android)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android' expected an object value.", + ); + } + if (!isString(actionCodeSettings.android.packageName)) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.packageName' expected a string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.android.installApp) && + !isBoolean(actionCodeSettings.android.installApp) + ) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.installApp' expected a boolean value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.android.minimumVersion) && + !isString(actionCodeSettings.android.minimumVersion) + ) { + throw new Error( + "firebase.auth.User.sendEmailVerification(*) 'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + } + } } return this._auth.native.sendEmailVerification(actionCodeSettings).then(user => { @@ -148,6 +210,88 @@ export default class User { }); } + verifyBeforeUpdateEmail(newEmail, actionCodeSettings) { + if (!isString(newEmail)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(*) 'newEmail' expected a string value.", + ); + } + + if (isObject(actionCodeSettings)) { + if (!isString(actionCodeSettings.url)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.url' expected a string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.dynamicLinkDomain) && + !isString(actionCodeSettings.dynamicLinkDomain) + ) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.dynamicLinkDomain' expected a string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.handleCodeInApp) && + !isBoolean(actionCodeSettings.handleCodeInApp) + ) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.handleCodeInApp' expected a boolean value.", + ); + } + + if (!isUndefined(actionCodeSettings.iOS)) { + if (!isObject(actionCodeSettings.iOS)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.iOS' expected an object value.", + ); + } + if (!isString(actionCodeSettings.iOS.bundleId)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.iOS.bundleId' expected a string value.", + ); + } + } + + if (!isUndefined(actionCodeSettings.android)) { + if (!isObject(actionCodeSettings.android)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android' expected an object value.", + ); + } + if (!isString(actionCodeSettings.android.packageName)) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.packageName' expected a string value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.android.installApp) && + !isBoolean(actionCodeSettings.android.installApp) + ) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.installApp' expected a boolean value.", + ); + } + + if ( + !isUndefined(actionCodeSettings.android.minimumVersion) && + !isString(actionCodeSettings.android.minimumVersion) + ) { + throw new Error( + "firebase.auth.User.verifyBeforeUpdateEmail(_, *) 'actionCodeSettings.android.minimumVersion' expected a string value.", + ); + } + } + } + + return this._auth.native.verifyBeforeUpdateEmail(newEmail, actionCodeSettings).then(user => { + this._auth._setUser(user); + }); + } + /** * KNOWN UNSUPPORTED METHODS */ diff --git a/lib/index.d.ts b/lib/index.d.ts index f2bf532617..4eb53171d6 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1037,6 +1037,30 @@ export namespace FirebaseAuthTypes { * @param actionCodeSettings Any optional additional settings to be set before sending the verification email. */ sendEmailVerification(actionCodeSettings?: ActionCodeSettings): Promise; + /** + * Sends a link to the user's email address, when clicked, the user's Authentication email address will be updated to whatever + * was passed as the first argument. + * + * #### Example + * + * ```js + * await firebase.auth().currentUser.verifyBeforeUpdateEmail( + * 'foo@emailaddress.com', + * { + * handleCodeInApp: true, + * }); + * ``` + * + * > This will Promise reject if the user is anonymous. + * + * @error auth/missing-android-pkg-name An Android package name must be provided if the Android app is required to be installed. + * @error auth/missing-continue-uri A continue URL must be provided in the request. + * @error auth/missing-ios-bundle-id An iOS bundle ID must be provided if an App Store ID is provided. + * @error auth/invalid-continue-uri The continue URL provided in the request is invalid. + * @error auth/unauthorized-continue-uri The domain of the continue URL is not whitelisted. Whitelist the domain in the Firebase console. + * @param actionCodeSettings Any optional additional settings to be set before sending the verification email. + */ + verifyBeforeUpdateEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise; /** * Returns a JSON-serializable representation of this object.