Skip to content

Commit

Permalink
Update injectRecaptchaFields to inject recaptcha enterprise fields in…
Browse files Browse the repository at this point in the history
…to phone API requests (#7786)

* Update injectRecaptchaFields to inject recaptcha fields into phone API requests

* Fix lint

* Rename captchaResp and fakeToken params

* Format
  • Loading branch information
NhienLam authored Nov 17, 2023
1 parent bebecda commit 3bfd025
Show file tree
Hide file tree
Showing 11 changed files with 391 additions and 51 deletions.
12 changes: 10 additions & 2 deletions packages/auth/src/api/account_management/mfa.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ import chaiAsPromised from 'chai-as-promised';

import { FirebaseError } from '@firebase/util';

import { Endpoint, HttpHeader } from '../';
import {
Endpoint,
HttpHeader,
RecaptchaClientType,
RecaptchaVersion
} from '../';
import { mockEndpoint } from '../../../test/helpers/api/helper';
import { testAuth, TestAuth } from '../../../test/helpers/mock_auth';
import * as mockFetch from '../../../test/helpers/mock_fetch';
Expand All @@ -40,7 +45,10 @@ describe('api/account_management/startEnrollPhoneMfa', () => {
idToken: 'id-token',
phoneEnrollmentInfo: {
phoneNumber: 'phone-number',
recaptchaToken: 'captcha-token'
recaptchaToken: 'captcha-token',
captchaResponse: 'captcha-response',
clientType: RecaptchaClientType.WEB,
recaptchaVersion: RecaptchaVersion.ENTERPRISE
}
};

Expand Down
9 changes: 8 additions & 1 deletion packages/auth/src/api/account_management/mfa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import {
Endpoint,
HttpMethod,
RecaptchaClientType,
RecaptchaVersion,
_addTidIfNecessary,
_performApiRequest
} from '../index';
Expand Down Expand Up @@ -55,7 +57,12 @@ export interface StartPhoneMfaEnrollmentRequest {
idToken: string;
phoneEnrollmentInfo: {
phoneNumber: string;
recaptchaToken: string;
// reCAPTCHA v2 token
recaptchaToken?: string;
// reCAPTCHA Enterprise token
captchaResponse?: string;
clientType?: RecaptchaClientType;
recaptchaVersion?: RecaptchaVersion;
};
tenantId?: string;
}
Expand Down
12 changes: 10 additions & 2 deletions packages/auth/src/api/authentication/mfa.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@ import chaiAsPromised from 'chai-as-promised';

import { FirebaseError } from '@firebase/util';

import { Endpoint, HttpHeader } from '../';
import {
Endpoint,
HttpHeader,
RecaptchaClientType,
RecaptchaVersion
} from '../';
import { mockEndpoint } from '../../../test/helpers/api/helper';
import { testAuth, TestAuth } from '../../../test/helpers/mock_auth';
import * as mockFetch from '../../../test/helpers/mock_fetch';
Expand All @@ -34,7 +39,10 @@ describe('api/authentication/startSignInPhoneMfa', () => {
mfaPendingCredential: 'my-creds',
mfaEnrollmentId: 'my-enrollment-id',
phoneSignInInfo: {
recaptchaToken: 'catpcha-token'
recaptchaToken: 'catpcha-token',
captchaResponse: 'captcha-response',
clientType: RecaptchaClientType.WEB,
recaptchaVersion: RecaptchaVersion.ENTERPRISE
}
};

Expand Down
9 changes: 8 additions & 1 deletion packages/auth/src/api/authentication/mfa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
_performApiRequest,
Endpoint,
HttpMethod,
RecaptchaClientType,
RecaptchaVersion,
_addTidIfNecessary
} from '../index';
import { Auth } from '../../model/public_types';
Expand Down Expand Up @@ -47,7 +49,12 @@ export interface StartPhoneMfaSignInRequest {
mfaPendingCredential: string;
mfaEnrollmentId: string;
phoneSignInInfo: {
recaptchaToken: string;
// reCAPTCHA v2 token
recaptchaToken?: string;
// reCAPTCHA Enterprise token
captchaResponse?: string;
clientType?: RecaptchaClientType;
recaptchaVersion?: RecaptchaVersion;
};
tenantId?: string;
}
Expand Down
12 changes: 10 additions & 2 deletions packages/auth/src/api/authentication/sms.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ import chaiAsPromised from 'chai-as-promised';
import { ProviderId } from '../../model/enums';
import { FirebaseError } from '@firebase/util';

import { Endpoint, HttpHeader } from '../';
import {
Endpoint,
HttpHeader,
RecaptchaClientType,
RecaptchaVersion
} from '../';
import { mockEndpoint } from '../../../test/helpers/api/helper';
import { testAuth, TestAuth } from '../../../test/helpers/mock_auth';
import * as mockFetch from '../../../test/helpers/mock_fetch';
Expand All @@ -38,7 +43,10 @@ use(chaiAsPromised);
describe('api/authentication/sendPhoneVerificationCode', () => {
const request = {
phoneNumber: '123456789',
recaptchaToken: 'captchad'
recaptchaToken: 'captchad',
captchaResponse: 'captcha-response',
clientType: RecaptchaClientType.WEB,
recaptchaVersion: RecaptchaVersion.ENTERPRISE
};

let auth: TestAuth;
Expand Down
9 changes: 8 additions & 1 deletion packages/auth/src/api/authentication/sms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import {
Endpoint,
HttpMethod,
RecaptchaClientType,
RecaptchaVersion,
_addTidIfNecessary,
_makeTaggedError,
_performApiRequest,
Expand All @@ -30,8 +32,13 @@ import { Auth } from '../../model/public_types';

export interface SendPhoneVerificationCodeRequest {
phoneNumber: string;
recaptchaToken: string;
// reCAPTCHA v2 token
recaptchaToken?: string;
tenantId?: string;
// reCAPTCHA Enterprise token
captchaResponse?: string;
clientType?: RecaptchaClientType;
recaptchaVersion?: RecaptchaVersion;
}

export interface SendPhoneVerificationCodeResponse {
Expand Down
8 changes: 6 additions & 2 deletions packages/auth/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,10 @@ export const enum RecaptchaVersion {
export const enum RecaptchaActionName {
SIGN_IN_WITH_PASSWORD = 'signInWithPassword',
GET_OOB_CODE = 'getOobCode',
SIGN_UP_PASSWORD = 'signUpPassword'
SIGN_UP_PASSWORD = 'signUpPassword',
SEND_VERIFICATION_CODE = 'sendVerificationCode',
MFA_SMS_ENROLLMENT = 'mfaSmsEnrollment',
MFA_SMS_SIGNIN = 'mfaSmsSignin'
}

export const enum EnforcementState {
Expand All @@ -98,7 +101,8 @@ export const enum EnforcementState {

// Providers that have reCAPTCHA Enterprise support.
export const enum RecaptchaProvider {
EMAIL_PASSWORD_PROVIDER = 'EMAIL_PASSWORD_PROVIDER'
EMAIL_PASSWORD_PROVIDER = 'EMAIL_PASSWORD_PROVIDER',
PHONE_PROVIDER = 'PHONE_PROVIDER'
}

export const DEFAULT_API_TIMEOUT_MS = new Delay(30_000, 60_000);
Expand Down
100 changes: 88 additions & 12 deletions packages/auth/src/platform_browser/recaptcha/recaptcha.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {

import { isV2, isEnterprise, RecaptchaConfig } from './recaptcha';
import { GetRecaptchaConfigResponse } from '../../api/authentication/recaptcha';
import { EnforcementState } from '../../api/index';
import { EnforcementState, RecaptchaProvider } from '../../api/index';

use(chaiAsPromised);
use(sinonChai);
Expand All @@ -39,17 +39,60 @@ describe('platform_browser/recaptcha/recaptcha', () => {
let recaptchaV2: MockReCaptcha;
let recaptchaV3: MockGreCAPTCHA;
let recaptchaEnterprise: MockGreCAPTCHATopLevel;
let recaptchaConfig: RecaptchaConfig;

const TEST_SITE_KEY = 'test-site-key';

const GET_RECAPTCHA_CONFIG_RESPONSE: GetRecaptchaConfigResponse = {
recaptchaKey: 'projects/testproj/keys/' + TEST_SITE_KEY,
recaptchaEnforcementState: [
{ provider: 'EMAIL_PASSWORD_PROVIDER', enforcementState: 'ENFORCE' }
{
provider: RecaptchaProvider.EMAIL_PASSWORD_PROVIDER,
enforcementState: EnforcementState.ENFORCE
},
{
provider: RecaptchaProvider.PHONE_PROVIDER,
enforcementState: EnforcementState.AUDIT
}
]
};

const GET_RECAPTCHA_CONFIG_RESPONSE_OFF: GetRecaptchaConfigResponse = {
recaptchaKey: 'projects/testproj/keys/' + TEST_SITE_KEY,
recaptchaEnforcementState: [
{
provider: RecaptchaProvider.EMAIL_PASSWORD_PROVIDER,
enforcementState: EnforcementState.OFF
},
{
provider: RecaptchaProvider.PHONE_PROVIDER,
enforcementState: EnforcementState.OFF
}
]
};

const GET_RECAPTCHA_CONFIG_RESPONSE_ENFORCE_AND_OFF: GetRecaptchaConfigResponse =
{
recaptchaKey: 'projects/testproj/keys/' + TEST_SITE_KEY,
recaptchaEnforcementState: [
{
provider: RecaptchaProvider.EMAIL_PASSWORD_PROVIDER,
enforcementState: EnforcementState.ENFORCE
},
{
provider: RecaptchaProvider.PHONE_PROVIDER,
enforcementState: EnforcementState.OFF
}
]
};

const recaptchaConfig = new RecaptchaConfig(GET_RECAPTCHA_CONFIG_RESPONSE);
const recaptchaConfigOff = new RecaptchaConfig(
GET_RECAPTCHA_CONFIG_RESPONSE_OFF
);
const recaptchaConfigEnforceAndOff = new RecaptchaConfig(
GET_RECAPTCHA_CONFIG_RESPONSE_ENFORCE_AND_OFF
);

context('#verify', () => {
beforeEach(async () => {
auth = await testAuth();
Expand All @@ -74,30 +117,63 @@ describe('platform_browser/recaptcha/recaptcha', () => {
});

context('#RecaptchaConfig', () => {
beforeEach(async () => {
recaptchaConfig = new RecaptchaConfig(GET_RECAPTCHA_CONFIG_RESPONSE);
});

it('should construct the recaptcha config from the backend response', () => {
expect(recaptchaConfig.siteKey).to.eq(TEST_SITE_KEY);
expect(recaptchaConfig.recaptchaEnforcementState[0]).to.eql({
provider: 'EMAIL_PASSWORD_PROVIDER',
enforcementState: 'ENFORCE'
provider: RecaptchaProvider.EMAIL_PASSWORD_PROVIDER,
enforcementState: EnforcementState.ENFORCE
});
expect(recaptchaConfig.recaptchaEnforcementState[1]).to.eql({
provider: RecaptchaProvider.PHONE_PROVIDER,
enforcementState: EnforcementState.AUDIT
});
expect(recaptchaConfigEnforceAndOff.recaptchaEnforcementState[1]).to.eql({
provider: RecaptchaProvider.PHONE_PROVIDER,
enforcementState: EnforcementState.OFF
});
});

it('#getProviderEnforcementState should return the correct enforcement state of the provider', () => {
expect(
recaptchaConfig.getProviderEnforcementState('EMAIL_PASSWORD_PROVIDER')
recaptchaConfig.getProviderEnforcementState(
RecaptchaProvider.EMAIL_PASSWORD_PROVIDER
)
).to.eq(EnforcementState.ENFORCE);
expect(
recaptchaConfig.getProviderEnforcementState(
RecaptchaProvider.PHONE_PROVIDER
)
).to.eq(EnforcementState.AUDIT);
expect(
recaptchaConfigEnforceAndOff.getProviderEnforcementState(
RecaptchaProvider.PHONE_PROVIDER
)
).to.eq(EnforcementState.OFF);
expect(recaptchaConfig.getProviderEnforcementState('invalid-provider')).to
.be.null;
});

it('#isProviderEnabled should return the enablement state of the provider', () => {
expect(recaptchaConfig.isProviderEnabled('EMAIL_PASSWORD_PROVIDER')).to.be
.true;
expect(
recaptchaConfig.isProviderEnabled(
RecaptchaProvider.EMAIL_PASSWORD_PROVIDER
)
).to.be.true;
expect(
recaptchaConfig.isProviderEnabled(RecaptchaProvider.PHONE_PROVIDER)
).to.be.true;
expect(
recaptchaConfigEnforceAndOff.isProviderEnabled(
RecaptchaProvider.PHONE_PROVIDER
)
).to.be.false;
expect(recaptchaConfig.isProviderEnabled('invalid-provider')).to.be.false;
});

it('#isAnyProviderEnabled should return true if at least one provider is enabled', () => {
expect(recaptchaConfig.isAnyProviderEnabled()).to.be.true;
expect(recaptchaConfigEnforceAndOff.isAnyProviderEnabled()).to.be.true;
expect(recaptchaConfigOff.isAnyProviderEnabled()).to.be.false;
});
});
});
19 changes: 18 additions & 1 deletion packages/auth/src/platform_browser/recaptcha/recaptcha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ import {
GetRecaptchaConfigResponse,
RecaptchaEnforcementProviderState
} from '../../api/authentication/recaptcha';
import { EnforcementState, _parseEnforcementState } from '../../api/index';
import {
EnforcementState,
RecaptchaProvider,
_parseEnforcementState
} from '../../api/index';

// reCAPTCHA v2 interface
export interface Recaptcha {
Expand Down Expand Up @@ -135,4 +139,17 @@ export class RecaptchaConfig {
this.getProviderEnforcementState(providerStr) === EnforcementState.AUDIT
);
}

/**
* Returns true if reCAPTCHA Enterprise protection is enabled in at least one provider, otherwise
* returns false.
*
* @returns Whether or not reCAPTCHA Enterprise protection is enabled for at least one provider.
*/
isAnyProviderEnabled(): boolean {
return (
this.isProviderEnabled(RecaptchaProvider.EMAIL_PASSWORD_PROVIDER) ||
this.isProviderEnabled(RecaptchaProvider.PHONE_PROVIDER)
);
}
}
Loading

0 comments on commit 3bfd025

Please sign in to comment.