Skip to content

Commit d8fcd95

Browse files
committed
Update injectRecaptchaFields to inject recaptcha enterprise fields into phone API requests (#7786)
* Update injectRecaptchaFields to inject recaptcha fields into phone API requests * Fix lint * Rename captchaResp and fakeToken params * Format
1 parent c8a2568 commit d8fcd95

File tree

11 files changed

+391
-51
lines changed

11 files changed

+391
-51
lines changed

packages/auth/src/api/account_management/mfa.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ import chaiAsPromised from 'chai-as-promised';
2020

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

23-
import { Endpoint, HttpHeader } from '../';
23+
import {
24+
Endpoint,
25+
HttpHeader,
26+
RecaptchaClientType,
27+
RecaptchaVersion
28+
} from '../';
2429
import { mockEndpoint } from '../../../test/helpers/api/helper';
2530
import { testAuth, TestAuth } from '../../../test/helpers/mock_auth';
2631
import * as mockFetch from '../../../test/helpers/mock_fetch';
@@ -40,7 +45,10 @@ describe('api/account_management/startEnrollPhoneMfa', () => {
4045
idToken: 'id-token',
4146
phoneEnrollmentInfo: {
4247
phoneNumber: 'phone-number',
43-
recaptchaToken: 'captcha-token'
48+
recaptchaToken: 'captcha-token',
49+
captchaResponse: 'captcha-response',
50+
clientType: RecaptchaClientType.WEB,
51+
recaptchaVersion: RecaptchaVersion.ENTERPRISE
4452
}
4553
};
4654

packages/auth/src/api/account_management/mfa.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import {
1919
Endpoint,
2020
HttpMethod,
21+
RecaptchaClientType,
22+
RecaptchaVersion,
2123
_addTidIfNecessary,
2224
_performApiRequest
2325
} from '../index';
@@ -55,7 +57,12 @@ export interface StartPhoneMfaEnrollmentRequest {
5557
idToken: string;
5658
phoneEnrollmentInfo: {
5759
phoneNumber: string;
58-
recaptchaToken: string;
60+
// reCAPTCHA v2 token
61+
recaptchaToken?: string;
62+
// reCAPTCHA Enterprise token
63+
captchaResponse?: string;
64+
clientType?: RecaptchaClientType;
65+
recaptchaVersion?: RecaptchaVersion;
5966
};
6067
tenantId?: string;
6168
}

packages/auth/src/api/authentication/mfa.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ import chaiAsPromised from 'chai-as-promised';
2020

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

23-
import { Endpoint, HttpHeader } from '../';
23+
import {
24+
Endpoint,
25+
HttpHeader,
26+
RecaptchaClientType,
27+
RecaptchaVersion
28+
} from '../';
2429
import { mockEndpoint } from '../../../test/helpers/api/helper';
2530
import { testAuth, TestAuth } from '../../../test/helpers/mock_auth';
2631
import * as mockFetch from '../../../test/helpers/mock_fetch';
@@ -34,7 +39,10 @@ describe('api/authentication/startSignInPhoneMfa', () => {
3439
mfaPendingCredential: 'my-creds',
3540
mfaEnrollmentId: 'my-enrollment-id',
3641
phoneSignInInfo: {
37-
recaptchaToken: 'catpcha-token'
42+
recaptchaToken: 'catpcha-token',
43+
captchaResponse: 'captcha-response',
44+
clientType: RecaptchaClientType.WEB,
45+
recaptchaVersion: RecaptchaVersion.ENTERPRISE
3846
}
3947
};
4048

packages/auth/src/api/authentication/mfa.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
_performApiRequest,
2020
Endpoint,
2121
HttpMethod,
22+
RecaptchaClientType,
23+
RecaptchaVersion,
2224
_addTidIfNecessary
2325
} from '../index';
2426
import { Auth } from '../../model/public_types';
@@ -47,7 +49,12 @@ export interface StartPhoneMfaSignInRequest {
4749
mfaPendingCredential: string;
4850
mfaEnrollmentId: string;
4951
phoneSignInInfo: {
50-
recaptchaToken: string;
52+
// reCAPTCHA v2 token
53+
recaptchaToken?: string;
54+
// reCAPTCHA Enterprise token
55+
captchaResponse?: string;
56+
clientType?: RecaptchaClientType;
57+
recaptchaVersion?: RecaptchaVersion;
5158
};
5259
tenantId?: string;
5360
}

packages/auth/src/api/authentication/sms.test.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ import chaiAsPromised from 'chai-as-promised';
2121
import { ProviderId } from '../../model/enums';
2222
import { FirebaseError } from '@firebase/util';
2323

24-
import { Endpoint, HttpHeader } from '../';
24+
import {
25+
Endpoint,
26+
HttpHeader,
27+
RecaptchaClientType,
28+
RecaptchaVersion
29+
} from '../';
2530
import { mockEndpoint } from '../../../test/helpers/api/helper';
2631
import { testAuth, TestAuth } from '../../../test/helpers/mock_auth';
2732
import * as mockFetch from '../../../test/helpers/mock_fetch';
@@ -38,7 +43,10 @@ use(chaiAsPromised);
3843
describe('api/authentication/sendPhoneVerificationCode', () => {
3944
const request = {
4045
phoneNumber: '123456789',
41-
recaptchaToken: 'captchad'
46+
recaptchaToken: 'captchad',
47+
captchaResponse: 'captcha-response',
48+
clientType: RecaptchaClientType.WEB,
49+
recaptchaVersion: RecaptchaVersion.ENTERPRISE
4250
};
4351

4452
let auth: TestAuth;

packages/auth/src/api/authentication/sms.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import {
1919
Endpoint,
2020
HttpMethod,
21+
RecaptchaClientType,
22+
RecaptchaVersion,
2123
_addTidIfNecessary,
2224
_makeTaggedError,
2325
_performApiRequest,
@@ -30,8 +32,13 @@ import { Auth } from '../../model/public_types';
3032

3133
export interface SendPhoneVerificationCodeRequest {
3234
phoneNumber: string;
33-
recaptchaToken: string;
35+
// reCAPTCHA v2 token
36+
recaptchaToken?: string;
3437
tenantId?: string;
38+
// reCAPTCHA Enterprise token
39+
captchaResponse?: string;
40+
clientType?: RecaptchaClientType;
41+
recaptchaVersion?: RecaptchaVersion;
3542
}
3643

3744
export interface SendPhoneVerificationCodeResponse {

packages/auth/src/api/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,10 @@ export const enum RecaptchaVersion {
8686
export const enum RecaptchaActionName {
8787
SIGN_IN_WITH_PASSWORD = 'signInWithPassword',
8888
GET_OOB_CODE = 'getOobCode',
89-
SIGN_UP_PASSWORD = 'signUpPassword'
89+
SIGN_UP_PASSWORD = 'signUpPassword',
90+
SEND_VERIFICATION_CODE = 'sendVerificationCode',
91+
MFA_SMS_ENROLLMENT = 'mfaSmsEnrollment',
92+
MFA_SMS_SIGNIN = 'mfaSmsSignin'
9093
}
9194

9295
export const enum EnforcementState {
@@ -98,7 +101,8 @@ export const enum EnforcementState {
98101

99102
// Providers that have reCAPTCHA Enterprise support.
100103
export const enum RecaptchaProvider {
101-
EMAIL_PASSWORD_PROVIDER = 'EMAIL_PASSWORD_PROVIDER'
104+
EMAIL_PASSWORD_PROVIDER = 'EMAIL_PASSWORD_PROVIDER',
105+
PHONE_PROVIDER = 'PHONE_PROVIDER'
102106
}
103107

104108
export const DEFAULT_API_TIMEOUT_MS = new Delay(30_000, 60_000);

packages/auth/src/platform_browser/recaptcha/recaptcha.test.ts

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929

3030
import { isV2, isEnterprise, RecaptchaConfig } from './recaptcha';
3131
import { GetRecaptchaConfigResponse } from '../../api/authentication/recaptcha';
32-
import { EnforcementState } from '../../api/index';
32+
import { EnforcementState, RecaptchaProvider } from '../../api/index';
3333

3434
use(chaiAsPromised);
3535
use(sinonChai);
@@ -39,17 +39,60 @@ describe('platform_browser/recaptcha/recaptcha', () => {
3939
let recaptchaV2: MockReCaptcha;
4040
let recaptchaV3: MockGreCAPTCHA;
4141
let recaptchaEnterprise: MockGreCAPTCHATopLevel;
42-
let recaptchaConfig: RecaptchaConfig;
4342

4443
const TEST_SITE_KEY = 'test-site-key';
4544

4645
const GET_RECAPTCHA_CONFIG_RESPONSE: GetRecaptchaConfigResponse = {
4746
recaptchaKey: 'projects/testproj/keys/' + TEST_SITE_KEY,
4847
recaptchaEnforcementState: [
49-
{ provider: 'EMAIL_PASSWORD_PROVIDER', enforcementState: 'ENFORCE' }
48+
{
49+
provider: RecaptchaProvider.EMAIL_PASSWORD_PROVIDER,
50+
enforcementState: EnforcementState.ENFORCE
51+
},
52+
{
53+
provider: RecaptchaProvider.PHONE_PROVIDER,
54+
enforcementState: EnforcementState.AUDIT
55+
}
5056
]
5157
};
5258

59+
const GET_RECAPTCHA_CONFIG_RESPONSE_OFF: GetRecaptchaConfigResponse = {
60+
recaptchaKey: 'projects/testproj/keys/' + TEST_SITE_KEY,
61+
recaptchaEnforcementState: [
62+
{
63+
provider: RecaptchaProvider.EMAIL_PASSWORD_PROVIDER,
64+
enforcementState: EnforcementState.OFF
65+
},
66+
{
67+
provider: RecaptchaProvider.PHONE_PROVIDER,
68+
enforcementState: EnforcementState.OFF
69+
}
70+
]
71+
};
72+
73+
const GET_RECAPTCHA_CONFIG_RESPONSE_ENFORCE_AND_OFF: GetRecaptchaConfigResponse =
74+
{
75+
recaptchaKey: 'projects/testproj/keys/' + TEST_SITE_KEY,
76+
recaptchaEnforcementState: [
77+
{
78+
provider: RecaptchaProvider.EMAIL_PASSWORD_PROVIDER,
79+
enforcementState: EnforcementState.ENFORCE
80+
},
81+
{
82+
provider: RecaptchaProvider.PHONE_PROVIDER,
83+
enforcementState: EnforcementState.OFF
84+
}
85+
]
86+
};
87+
88+
const recaptchaConfig = new RecaptchaConfig(GET_RECAPTCHA_CONFIG_RESPONSE);
89+
const recaptchaConfigOff = new RecaptchaConfig(
90+
GET_RECAPTCHA_CONFIG_RESPONSE_OFF
91+
);
92+
const recaptchaConfigEnforceAndOff = new RecaptchaConfig(
93+
GET_RECAPTCHA_CONFIG_RESPONSE_ENFORCE_AND_OFF
94+
);
95+
5396
context('#verify', () => {
5497
beforeEach(async () => {
5598
auth = await testAuth();
@@ -74,30 +117,63 @@ describe('platform_browser/recaptcha/recaptcha', () => {
74117
});
75118

76119
context('#RecaptchaConfig', () => {
77-
beforeEach(async () => {
78-
recaptchaConfig = new RecaptchaConfig(GET_RECAPTCHA_CONFIG_RESPONSE);
79-
});
80-
81120
it('should construct the recaptcha config from the backend response', () => {
82121
expect(recaptchaConfig.siteKey).to.eq(TEST_SITE_KEY);
83122
expect(recaptchaConfig.recaptchaEnforcementState[0]).to.eql({
84-
provider: 'EMAIL_PASSWORD_PROVIDER',
85-
enforcementState: 'ENFORCE'
123+
provider: RecaptchaProvider.EMAIL_PASSWORD_PROVIDER,
124+
enforcementState: EnforcementState.ENFORCE
125+
});
126+
expect(recaptchaConfig.recaptchaEnforcementState[1]).to.eql({
127+
provider: RecaptchaProvider.PHONE_PROVIDER,
128+
enforcementState: EnforcementState.AUDIT
129+
});
130+
expect(recaptchaConfigEnforceAndOff.recaptchaEnforcementState[1]).to.eql({
131+
provider: RecaptchaProvider.PHONE_PROVIDER,
132+
enforcementState: EnforcementState.OFF
86133
});
87134
});
88135

89136
it('#getProviderEnforcementState should return the correct enforcement state of the provider', () => {
90137
expect(
91-
recaptchaConfig.getProviderEnforcementState('EMAIL_PASSWORD_PROVIDER')
138+
recaptchaConfig.getProviderEnforcementState(
139+
RecaptchaProvider.EMAIL_PASSWORD_PROVIDER
140+
)
92141
).to.eq(EnforcementState.ENFORCE);
142+
expect(
143+
recaptchaConfig.getProviderEnforcementState(
144+
RecaptchaProvider.PHONE_PROVIDER
145+
)
146+
).to.eq(EnforcementState.AUDIT);
147+
expect(
148+
recaptchaConfigEnforceAndOff.getProviderEnforcementState(
149+
RecaptchaProvider.PHONE_PROVIDER
150+
)
151+
).to.eq(EnforcementState.OFF);
93152
expect(recaptchaConfig.getProviderEnforcementState('invalid-provider')).to
94153
.be.null;
95154
});
96155

97156
it('#isProviderEnabled should return the enablement state of the provider', () => {
98-
expect(recaptchaConfig.isProviderEnabled('EMAIL_PASSWORD_PROVIDER')).to.be
99-
.true;
157+
expect(
158+
recaptchaConfig.isProviderEnabled(
159+
RecaptchaProvider.EMAIL_PASSWORD_PROVIDER
160+
)
161+
).to.be.true;
162+
expect(
163+
recaptchaConfig.isProviderEnabled(RecaptchaProvider.PHONE_PROVIDER)
164+
).to.be.true;
165+
expect(
166+
recaptchaConfigEnforceAndOff.isProviderEnabled(
167+
RecaptchaProvider.PHONE_PROVIDER
168+
)
169+
).to.be.false;
100170
expect(recaptchaConfig.isProviderEnabled('invalid-provider')).to.be.false;
101171
});
172+
173+
it('#isAnyProviderEnabled should return true if at least one provider is enabled', () => {
174+
expect(recaptchaConfig.isAnyProviderEnabled()).to.be.true;
175+
expect(recaptchaConfigEnforceAndOff.isAnyProviderEnabled()).to.be.true;
176+
expect(recaptchaConfigOff.isAnyProviderEnabled()).to.be.false;
177+
});
102178
});
103179
});

packages/auth/src/platform_browser/recaptcha/recaptcha.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ import {
2020
GetRecaptchaConfigResponse,
2121
RecaptchaEnforcementProviderState
2222
} from '../../api/authentication/recaptcha';
23-
import { EnforcementState, _parseEnforcementState } from '../../api/index';
23+
import {
24+
EnforcementState,
25+
RecaptchaProvider,
26+
_parseEnforcementState
27+
} from '../../api/index';
2428

2529
// reCAPTCHA v2 interface
2630
export interface Recaptcha {
@@ -135,4 +139,17 @@ export class RecaptchaConfig {
135139
this.getProviderEnforcementState(providerStr) === EnforcementState.AUDIT
136140
);
137141
}
142+
143+
/**
144+
* Returns true if reCAPTCHA Enterprise protection is enabled in at least one provider, otherwise
145+
* returns false.
146+
*
147+
* @returns Whether or not reCAPTCHA Enterprise protection is enabled for at least one provider.
148+
*/
149+
isAnyProviderEnabled(): boolean {
150+
return (
151+
this.isProviderEnabled(RecaptchaProvider.EMAIL_PASSWORD_PROVIDER) ||
152+
this.isProviderEnabled(RecaptchaProvider.PHONE_PROVIDER)
153+
);
154+
}
138155
}

0 commit comments

Comments
 (0)