Skip to content

Update injectRecaptchaFields to inject recaptcha enterprise fields into phone API requests #7786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
7 changes: 6 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,10 @@ export interface StartPhoneMfaEnrollmentRequest {
idToken: string;
phoneEnrollmentInfo: {
phoneNumber: string;
recaptchaToken: string;
recaptchaToken?: string;
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
7 changes: 6 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,10 @@ export interface StartPhoneMfaSignInRequest {
mfaPendingCredential: string;
mfaEnrollmentId: string;
phoneSignInInfo: {
recaptchaToken: string;
recaptchaToken?: string;
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
7 changes: 6 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,11 @@ import { Auth } from '../../model/public_types';

export interface SendPhoneVerificationCodeRequest {
phoneNumber: string;
recaptchaToken: string;
recaptchaToken?: string;
tenantId?: string;
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
60 changes: 53 additions & 7 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 @@ -46,7 +46,14 @@ describe('platform_browser/recaptcha/recaptcha', () => {
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
}
]
};

Expand Down Expand Up @@ -81,23 +88,62 @@ describe('platform_browser/recaptcha/recaptcha', () => {
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
});
});

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(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(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;

const getRecaptchaConfigResponse: 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 configNoProviderEnabled = new RecaptchaConfig(
getRecaptchaConfigResponse
);
expect(configNoProviderEnabled.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