Skip to content

Commit

Permalink
Merge edc0f50 into 02e2518
Browse files Browse the repository at this point in the history
  • Loading branch information
renkelvin committed Oct 11, 2023
2 parents 02e2518 + edc0f50 commit 3d27821
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 140 deletions.
5 changes: 5 additions & 0 deletions .changeset/lucky-dragons-juggle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@firebase/auth': patch
---

Create handleRecaptchaFlow helper method
34 changes: 7 additions & 27 deletions packages/auth/src/core/credentials/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { IdTokenResponse } from '../../model/id_token';
import { AuthErrorCode } from '../errors';
import { _fail } from '../util/assert';
import { AuthCredential } from './auth_credential';
import { injectRecaptchaFields } from '../../platform_browser/recaptcha/recaptcha_enterprise_verifier';
import { handleRecaptchaFlow } from '../../platform_browser/recaptcha/recaptcha_enterprise_verifier';
import { RecaptchaActionName, RecaptchaClientType } from '../../api';
/**
* Interface that represents the credentials returned by {@link EmailAuthProvider} for
Expand Down Expand Up @@ -123,32 +123,12 @@ export class EmailAuthCredential extends AuthCredential {
password: this._password,
clientType: RecaptchaClientType.WEB
};
if (auth._getRecaptchaConfig()?.emailPasswordEnabled) {
const requestWithRecaptcha = await injectRecaptchaFields(
auth,
request,
RecaptchaActionName.SIGN_IN_WITH_PASSWORD
);
return signInWithPassword(auth, requestWithRecaptcha);
} else {
return signInWithPassword(auth, request).catch(async error => {
if (
error.code === `auth/${AuthErrorCode.MISSING_RECAPTCHA_TOKEN}`
) {
console.log(
'Sign-in with email address and password is protected by reCAPTCHA for this project. Automatically triggering the reCAPTCHA flow and restarting the sign-in flow.'
);
const requestWithRecaptcha = await injectRecaptchaFields(
auth,
request,
RecaptchaActionName.SIGN_IN_WITH_PASSWORD
);
return signInWithPassword(auth, requestWithRecaptcha);
} else {
return Promise.reject(error);
}
});
}
return handleRecaptchaFlow(
auth,
request,
RecaptchaActionName.SIGN_IN_WITH_PASSWORD,
signInWithPassword
);
case SignInMethod.EMAIL_LINK:
return signInWithEmailLink(auth, {
email: this._email,
Expand Down
96 changes: 15 additions & 81 deletions packages/auth/src/core/strategies/email_and_password.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { _castAuth } from '../auth/auth_impl';
import { AuthErrorCode } from '../errors';
import { getModularInstance } from '@firebase/util';
import { OperationType } from '../../model/enums';
import { injectRecaptchaFields } from '../../platform_browser/recaptcha/recaptcha_enterprise_verifier';
import { handleRecaptchaFlow } from '../../platform_browser/recaptcha/recaptcha_enterprise_verifier';
import { IdTokenResponse } from '../../model/id_token';
import { RecaptchaActionName, RecaptchaClientType } from '../../api';

Expand Down Expand Up @@ -103,61 +103,15 @@ export async function sendPasswordResetEmail(
email,
clientType: RecaptchaClientType.WEB
};
if (authInternal._getRecaptchaConfig()?.emailPasswordEnabled) {
const requestWithRecaptcha = await injectRecaptchaFields(
authInternal,
request,
RecaptchaActionName.GET_OOB_CODE,
true
);
if (actionCodeSettings) {
_setActionCodeSettingsOnRequest(
authInternal,
requestWithRecaptcha,
actionCodeSettings
);
}
await authentication.sendPasswordResetEmail(
authInternal,
requestWithRecaptcha
);
} else {
if (actionCodeSettings) {
_setActionCodeSettingsOnRequest(
authInternal,
request,
actionCodeSettings
);
}
await authentication
.sendPasswordResetEmail(authInternal, request)
.catch(async error => {
if (error.code === `auth/${AuthErrorCode.MISSING_RECAPTCHA_TOKEN}`) {
console.log(
'Password resets are protected by reCAPTCHA for this project. Automatically triggering the reCAPTCHA flow and restarting the password reset flow.'
);
const requestWithRecaptcha = await injectRecaptchaFields(
authInternal,
request,
RecaptchaActionName.GET_OOB_CODE,
true
);
if (actionCodeSettings) {
_setActionCodeSettingsOnRequest(
authInternal,
requestWithRecaptcha,
actionCodeSettings
);
}
await authentication.sendPasswordResetEmail(
authInternal,
requestWithRecaptcha
);
} else {
return Promise.reject(error);
}
});
if (actionCodeSettings) {
_setActionCodeSettingsOnRequest(authInternal, request, actionCodeSettings);
}
await handleRecaptchaFlow(
authInternal,
request,
RecaptchaActionName.GET_OOB_CODE,
authentication.sendPasswordResetEmail
);
}

/**
Expand Down Expand Up @@ -318,32 +272,12 @@ export async function createUserWithEmailAndPassword(
password,
clientType: RecaptchaClientType.WEB
};
let signUpResponse: Promise<IdTokenResponse>;
if (authInternal._getRecaptchaConfig()?.emailPasswordEnabled) {
const requestWithRecaptcha = await injectRecaptchaFields(
authInternal,
request,
RecaptchaActionName.SIGN_UP_PASSWORD
);
signUpResponse = signUp(authInternal, requestWithRecaptcha);
} else {
signUpResponse = signUp(authInternal, request).catch(async error => {
if (error.code === `auth/${AuthErrorCode.MISSING_RECAPTCHA_TOKEN}`) {
console.log(
'Sign-up is protected by reCAPTCHA for this project. Automatically triggering the reCAPTCHA flow and restarting the sign-up flow.'
);
const requestWithRecaptcha = await injectRecaptchaFields(
authInternal,
request,
RecaptchaActionName.SIGN_UP_PASSWORD
);
return signUp(authInternal, requestWithRecaptcha);
}

throw error;
});
}

const signUpResponse: Promise<IdTokenResponse> = handleRecaptchaFlow(
authInternal,
request,
RecaptchaActionName.SIGN_UP_PASSWORD,
signUp
);
const response = await signUpResponse.catch(error => {
if (
error.code === `auth/${AuthErrorCode.PASSWORD_DOES_NOT_MEET_REQUIREMENTS}`
Expand Down
40 changes: 8 additions & 32 deletions packages/auth/src/core/strategies/email_link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { AuthErrorCode } from '../errors';
import { _assert } from '../util/assert';
import { getModularInstance } from '@firebase/util';
import { _castAuth } from '../auth/auth_impl';
import { injectRecaptchaFields } from '../../platform_browser/recaptcha/recaptcha_enterprise_verifier';
import { handleRecaptchaFlow } from '../../platform_browser/recaptcha/recaptcha_enterprise_verifier';
import { RecaptchaActionName, RecaptchaClientType } from '../../api';

/**
Expand Down Expand Up @@ -101,37 +101,13 @@ export async function sendSignInLinkToEmail(
);
}
}
if (authInternal._getRecaptchaConfig()?.emailPasswordEnabled) {
const requestWithRecaptcha = await injectRecaptchaFields(
authInternal,
request,
RecaptchaActionName.GET_OOB_CODE,
true
);
setActionCodeSettings(requestWithRecaptcha, actionCodeSettings);
await api.sendSignInLinkToEmail(authInternal, requestWithRecaptcha);
} else {
setActionCodeSettings(request, actionCodeSettings);
await api
.sendSignInLinkToEmail(authInternal, request)
.catch(async error => {
if (error.code === `auth/${AuthErrorCode.MISSING_RECAPTCHA_TOKEN}`) {
console.log(
'Email link sign-in is protected by reCAPTCHA for this project. Automatically triggering the reCAPTCHA flow and restarting the sign-in flow.'
);
const requestWithRecaptcha = await injectRecaptchaFields(
authInternal,
request,
RecaptchaActionName.GET_OOB_CODE,
true
);
setActionCodeSettings(requestWithRecaptcha, actionCodeSettings);
await api.sendSignInLinkToEmail(authInternal, requestWithRecaptcha);
} else {
return Promise.reject(error);
}
});
}
setActionCodeSettings(request, actionCodeSettings);
await handleRecaptchaFlow(
authInternal,
request,
RecaptchaActionName.GET_OOB_CODE,
api.sendSignInLinkToEmail
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { Auth } from '../../model/public_types';
import { AuthInternal } from '../../model/auth';
import { _castAuth } from '../../core/auth/auth_impl';
import * as jsHelpers from '../load_js';
import { AuthErrorCode } from '../../core/errors';

const RECAPTCHA_ENTERPRISE_URL =
'https://www.google.com/recaptcha/enterprise.js?render=';
Expand Down Expand Up @@ -175,6 +176,45 @@ export async function injectRecaptchaFields<T>(
return newRequest;
}

type ActionMethod<TRequest, TResponse> = (
auth: Auth,
request: TRequest
) => Promise<TResponse>;

export async function handleRecaptchaFlow<TRequest, TResponse>(
authInstance: AuthInternal,
request: TRequest,
actionName: RecaptchaActionName,
actionMethod: ActionMethod<TRequest, TResponse>
): Promise<TResponse> {
if (authInstance._getRecaptchaConfig()?.emailPasswordEnabled) {
const requestWithRecaptcha = await injectRecaptchaFields(
authInstance,
request,
actionName,
actionName === RecaptchaActionName.GET_OOB_CODE
);
return actionMethod(authInstance, requestWithRecaptcha);
} else {
return actionMethod(authInstance, request).catch(async error => {
if (error.code === `auth/${AuthErrorCode.MISSING_RECAPTCHA_TOKEN}`) {
console.log(
`${actionName} is protected by reCAPTCHA Enterprise for this project. Automatically triggering the reCAPTCHA flow and restarting the flow.`
);
const requestWithRecaptcha = await injectRecaptchaFields(
authInstance,
request,
actionName,
actionName === RecaptchaActionName.GET_OOB_CODE
);
return actionMethod(authInstance, requestWithRecaptcha);
} else {
return Promise.reject(error);
}
});
}
}

export async function _initializeRecaptchaConfig(auth: Auth): Promise<void> {
const authInternal = _castAuth(auth);

Expand Down

0 comments on commit 3d27821

Please sign in to comment.