Skip to content

Commit e48c1fa

Browse files
committed
Use Signup challenge enforcement endpoint
1 parent 59b50aa commit e48c1fa

File tree

10 files changed

+118
-48
lines changed

10 files changed

+118
-48
lines changed

src/__tests__/engine/classic/__snapshots__/sign_up_pane.test.jsx.snap

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ exports[`SignUpPane shows the Captcha pane 1`] = `
214214
/>
215215
<CaptchaPane
216216
error={false}
217+
flow="signup"
217218
i18n={
218219
{
219220
"html": [Function],
@@ -241,6 +242,7 @@ exports[`SignUpPane shows the Captcha pane for SSO (ADFS) connections 1`] = `
241242
/>
242243
<CaptchaPane
243244
error={false}
245+
flow="signup"
244246
i18n={
245247
{
246248
"html": [Function],

src/__tests__/engine/classic/sign_up_pane.test.jsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import React from 'react';
22
import { expectComponent, mockComponent } from 'testUtils';
33
import { expectShallowComponent } from '../../testUtils';
4+
import { Flow } from '../../../connection/captcha';
45

56
jest.mock('field/email/email_pane', () => mockComponent('email_pane'));
67
jest.mock('field/password/password_pane', () => mockComponent('password_pane'));
78
jest.mock('field/username/username_pane', () => mockComponent('username_pane'));
89
jest.mock('field/custom_input', () => mockComponent('custom_input'));
910

1011
jest.mock('core/index', () => ({
11-
captcha: jest.fn()
12+
signupCaptcha: jest.fn()
1213
}));
1314

1415
jest.mock('engine/classic', () => ({
@@ -38,6 +39,7 @@ describe('SignUpPane', () => {
3839
str: (...keys) => keys.join(','),
3940
html: (...keys) => keys.join(',')
4041
},
42+
flow: Flow.SIGNUP,
4143
model: 'model',
4244
emailInputPlaceholder: 'emailInputPlaceholder',
4345
onlyEmail: true,
@@ -58,7 +60,7 @@ describe('SignUpPane', () => {
5860
});
5961

6062
it('shows the Captcha pane', () => {
61-
require('core/index').captcha.mockReturnValue({
63+
require('core/index').signupCaptcha.mockReturnValue({
6264
get() {
6365
return true;
6466
}
@@ -72,7 +74,7 @@ describe('SignUpPane', () => {
7274
});
7375

7476
it('hides the Captcha pane for SSO connections', () => {
75-
require('core/index').captcha.mockReturnValue({
77+
require('core/index').signupCaptcha.mockReturnValue({
7678
get() {
7779
return true;
7880
}
@@ -86,7 +88,7 @@ describe('SignUpPane', () => {
8688
});
8789

8890
it('shows the Captcha pane for SSO (ADFS) connections', () => {
89-
require('core/index').captcha.mockReturnValue({
91+
require('core/index').signupCaptcha.mockReturnValue({
9092
get() {
9193
return true;
9294
}

src/connection/captcha.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import webApi from '../core/web_api';
66

77
export const Flow = Object.freeze({
88
DEFAULT: 'default',
9+
SIGNUP: 'signup',
910
PASSWORDLESS: 'passwordless',
1011
PASSWORD_RESET: 'password_reset',
1112
});
1213

1314
/**
1415
* Return the captcha config object based on the type of flow.
15-
*
16+
*
1617
* @param {Object} m model
1718
* @param {Flow} flow Which flow the captcha is being rendered in
1819
*/
@@ -21,6 +22,8 @@ export function getCaptchaConfig(m, flow) {
2122
return l.passwordResetCaptcha(m);
2223
} else if (flow === Flow.PASSWORDLESS) {
2324
return l.passwordlessCaptcha(m);
25+
} else if (flow === Flow.SIGNUP) {
26+
return l.signupCaptcha(m);
2427
} else {
2528
return l.captcha(m);
2629
}
@@ -42,7 +45,7 @@ export function showMissingCaptcha(m, id, flow = Flow.DEFAULT) {
4245
captchaConfig.get('provider') === 'hcaptcha' ||
4346
captchaConfig.get('provider') === 'auth0_v2' ||
4447
captchaConfig.get('provider') === 'friendly_captcha' ||
45-
captchaConfig.get('provider') === 'arkose'
48+
captchaConfig.get('provider') === 'arkose'
4649
) ? 'invalid_recaptcha' : 'invalid_captcha';
4750

4851
const errorMessage = i18n.html(m, ['error', 'login', captchaError]);
@@ -110,6 +113,15 @@ export function swapCaptcha(id, flow, wasInvalid, next) {
110113
next();
111114
}
112115
});
116+
} else if (flow === Flow.SIGNUP) {
117+
return webApi.getSignupChallenge(id, (err, newCaptcha) => {
118+
if (!err && newCaptcha) {
119+
swap(updateEntity, 'lock', id, l.setSignupChallenge, newCaptcha, wasInvalid);
120+
}
121+
if (next) {
122+
next();
123+
}
124+
});
113125
} else {
114126
return webApi.getChallenge(id, (err, newCaptcha) => {
115127
if (!err && newCaptcha) {

src/connection/database/actions.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,9 @@ export function signUp(id) {
8888
autoLogin: shouldAutoLogin(m)
8989
};
9090

91-
const isCaptchaValid = setCaptchaParams(m, params, Flow.DEFAULT, fields);
91+
const isCaptchaValid = setCaptchaParams(m, params, Flow.SIGNUP, fields);
9292
if (!isCaptchaValid) {
93-
return showMissingCaptcha(m, id);
93+
return showMissingCaptcha(m, id, Flow.SIGNUP);
9494
}
9595

9696
if (databaseConnectionRequiresUsername(m)) {
@@ -131,7 +131,7 @@ export function signUp(id) {
131131

132132
const wasInvalidCaptcha = error && error.code === 'invalid_captcha';
133133

134-
swapCaptcha(id, Flow.DEFAULT, wasInvalidCaptcha, () => {
134+
swapCaptcha(id, Flow.SIGNUP, wasInvalidCaptcha, () => {
135135
setTimeout(() => signUpError(id, error), 250);
136136
});
137137
};
@@ -290,7 +290,7 @@ export function resetPasswordSuccess(id) {
290290
function resetPasswordError(id, error) {
291291
const m = read(getEntity, 'lock', id);
292292
let key = error.code;
293-
293+
294294
if (error.code === 'invalid_captcha') {
295295
const captchaConfig = l.passwordResetCaptcha(m);
296296
key = (
@@ -302,7 +302,7 @@ function resetPasswordError(id, error) {
302302
const errorMessage =
303303
i18n.html(m, ['error', 'forgotPassword', key]) ||
304304
i18n.html(m, ['error', 'forgotPassword', 'lock.fallback']);
305-
305+
306306
swapCaptcha(id, Flow.PASSWORD_RESET, error.code === 'invalid_captcha', () => {
307307
swap(updateEntity, 'lock', id, l.setSubmitting, false, errorMessage);
308308
});
@@ -322,11 +322,11 @@ export function showLoginActivity(id, fields = ['password']) {
322322

323323
export function showSignUpActivity(id, fields = ['password']) {
324324
const m = read(getEntity, 'lock', id);
325-
const captchaConfig = l.captcha(m);
325+
const captchaConfig = l.signupCaptcha(m);
326326
if (captchaConfig && captchaConfig.get('provider') === 'arkose') {
327327
swap(updateEntity, 'lock', id, setScreen, 'signUp', fields);
328328
} else {
329-
swapCaptcha(id, 'login', false, () => {
329+
swapCaptcha(id, Flow.SIGNUP, false, () => {
330330
swap(updateEntity, 'lock', id, setScreen, 'signUp', fields);
331331
});
332332
}
@@ -338,7 +338,7 @@ export function showResetPasswordActivity(id, fields = ['password']) {
338338
if (captchaConfig && captchaConfig.get('provider') === 'arkose') {
339339
swap(updateEntity, 'lock', id, setScreen, 'forgotPassword', fields);
340340
} else {
341-
swapCaptcha(id, 'login', false, () => {
341+
swapCaptcha(id, Flow.PASSWORD_RESET, false, () => {
342342
swap(updateEntity, 'lock', id, setScreen, 'forgotPassword', fields);
343343
});
344344
}

src/core/index.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,11 @@ export function setCaptcha(m, value, wasInvalid) {
421421
return set(m, 'captcha', Immutable.fromJS(value));
422422
}
423423

424+
export function setSignupChallenge(m, value, wasInvalid) {
425+
m = captchaField.reset(m, wasInvalid);
426+
return set(m, 'signupCaptcha', Immutable.fromJS(value));
427+
}
428+
424429
export function setPasswordlessCaptcha(m, value, wasInvalid) {
425430
m = captchaField.reset(m, wasInvalid);
426431
return set(m, 'passwordlessCaptcha', Immutable.fromJS(value));
@@ -435,6 +440,10 @@ export function captcha(m) {
435440
return get(m, 'captcha');
436441
}
437442

443+
export function signupCaptcha(m) {
444+
return get(m, 'signupCaptcha');
445+
}
446+
438447
export function passwordlessCaptcha(m) {
439448
return get(m, 'passwordlessCaptcha');
440449
}

src/core/web_api.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ class Auth0WebAPI {
6060
return this.clients[lockID].getChallenge(callback);
6161
}
6262

63+
getSignupChallenge(lockID, callback) {
64+
return this.clients[lockID].getSignupChallenge(callback);
65+
}
66+
6367
getPasswordlessChallenge(lockID, callback) {
6468
return this.clients[lockID].getPasswordlessChallenge(callback);
6569
}

src/core/web_api/p2_api.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@ class Auth0APIClient {
195195
return this.client.client.getChallenge(...params);
196196
}
197197

198+
getSignupChallenge(...params) {
199+
return this.client.client.dbConnection.getSignupChallenge(...params);
200+
}
201+
198202
getPasswordlessChallenge(...params) {
199203
return this.client.client.passwordless.getChallenge(...params);
200204
}

src/engine/classic/sign_up_pane.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@ export default class SignUpPane extends React.Component {
6464
));
6565

6666
const captchaPane =
67-
l.captcha(model) &&
68-
l.captcha(model).get('required') &&
67+
l.signupCaptcha(model) &&
68+
l.signupCaptcha(model).get('required') &&
6969
(isHRDDomain(model, databaseUsernameValue(model)) || !sso) ? (
70-
<CaptchaPane i18n={i18n} lock={model} onReload={() => swapCaptcha(l.id(model), Flow.DEFAULT, false)} />
70+
<CaptchaPane i18n={i18n} lock={model} flow={Flow.SIGNUP} onReload={() => swapCaptcha(l.id(model), Flow.SIGNUP, false)} />
7171
) : null;
7272

7373
const passwordPane = !onlyEmail && (

test/captcha_signup.test.js

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import en from '../src/i18n/en';
44

55
const lockOpts = {
66
allowedConnections: ['db'],
7-
rememberLastLogin: false,
8-
initialScreen: 'signUp'
7+
rememberLastLogin: false
98
};
109

1110
const svgCaptchaRequiredResponse1 = {
@@ -33,39 +32,40 @@ describe('captcha on signup', function () {
3332
describe('svg-captcha', () => {
3433
describe('when the api returns a new challenge', function () {
3534
beforeEach(function (done) {
36-
this.stub = h.stubGetChallenge([svgCaptchaRequiredResponse1, svgCaptchaRequiredResponse2]);
37-
this.lock = h.displayLock('', lockOpts, done);
35+
this.stub = h.stubGetChallenge({ required: false });
36+
this.stub = h.stubGetSignupChallenge([svgCaptchaRequiredResponse1, svgCaptchaRequiredResponse2]);
37+
this.lock = h.displayLock('', lockOpts, () => {
38+
h.clickSignUpTab();
39+
h.waitUntilExists(this.lock, '.auth0-lock-with-terms', () => {
40+
done();
41+
});
42+
});
3843
});
3944

4045
afterEach(function () {
4146
this.lock.hide();
4247
});
4348

44-
it('sign-up tab should be active', function (done) {
45-
h.waitUntilExists(this.lock, '.auth0-lock-tabs-current', () => {
46-
expect(h.isSignUpTabCurrent(this.lock)).to.be.ok();
47-
done();
48-
});
49+
it('sign-up tab should be active', function () {
50+
expect(h.isSignUpTabCurrent(this.lock)).to.be.ok();
4951
});
5052

5153
it('should show the captcha input', function (done) {
54+
expect(h.isSignUpTabCurrent(this.lock)).to.be.ok();
5255
setTimeout(() => {
5356
expect(h.qInput(this.lock, 'captcha', false)).to.be.ok();
5457
done();
5558
}, 500);
5659
});
5760

5861
it('should require another challenge when clicking the refresh button', function (done) {
59-
h.waitUntilExists(this.lock, '.auth0-lock-captcha-refresh', () => {
60-
h.clickRefreshCaptchaButton(this.lock);
61-
62-
setTimeout(() => {
63-
expect(h.q(this.lock, '.auth0-lock-captcha-image').style.backgroundImage).to.equal(
64-
`url("${svgCaptchaRequiredResponse2.image}")`
65-
);
66-
done();
67-
}, 200);
68-
});
62+
h.clickRefreshCaptchaButton(this.lock);
63+
setTimeout(() => {
64+
expect(h.q(this.lock, '.auth0-lock-captcha-image').style.backgroundImage).to.equal(
65+
`url("${svgCaptchaRequiredResponse2.image}")`
66+
);
67+
done();
68+
}, 200);
6969
});
7070

7171
it('should submit the captcha provided by the user', function (done) {
@@ -86,12 +86,16 @@ describe('captcha on signup', function () {
8686
});
8787
});
8888

89-
describe('when the challenge api returns required: false', function () {
89+
describe('when the challenge api returns required: false for signup', function () {
9090
beforeEach(function (done) {
91-
h.stubGetChallenge({
92-
required: false
91+
h.stubGetChallenge([svgCaptchaRequiredResponse1, svgCaptchaRequiredResponse2]);
92+
h.stubGetSignupChallenge({ required: false });
93+
this.lock = h.displayLock('', lockOpts, () => {
94+
h.clickSignUpTab();
95+
h.waitUntilExists(this.lock, '.auth0-lock-with-terms', () => {
96+
done();
97+
});
9398
});
94-
this.lock = h.displayLock('', lockOpts, done);
9599
});
96100

97101
afterEach(function () {
@@ -110,7 +114,7 @@ describe('captcha on signup', function () {
110114
});
111115

112116
h.waitForEmailAndPasswordInput(this.lock, () => {
113-
h.stubGetChallenge(svgCaptchaRequiredResponse1);
117+
h.stubGetSignupChallenge(svgCaptchaRequiredResponse1);
114118
h.fillEmailInput(this.lock, '[email protected]');
115119
h.fillComplexPassword(this.lock);
116120
h.submitForm(this.lock);
@@ -127,8 +131,14 @@ describe('captcha on signup', function () {
127131
describe('recaptcha', () => {
128132
describe('when the api returns a new challenge', function () {
129133
beforeEach(function (done) {
130-
this.stub = h.stubGetChallenge([recaptchav2Response]);
131-
this.lock = h.displayLock('', lockOpts, done);
134+
this.stub = h.stubGetChallenge({ required: false });
135+
this.stub = h.stubGetSignupChallenge([recaptchav2Response]);
136+
this.lock = h.displayLock('', lockOpts, () => {
137+
h.clickSignUpTab();
138+
h.waitUntilExists(this.lock, '.auth0-lock-with-terms', () => {
139+
done();
140+
});
141+
});
132142
});
133143

134144
afterEach(function () {
@@ -156,12 +166,17 @@ describe('captcha on signup', function () {
156166
});
157167

158168
describe('when the challenge api returns required: false', function () {
159-
let notRequiredStub;
169+
let notRequiredStub
170+
let loginGetChallengeStub;
160171
beforeEach(function (done) {
161-
notRequiredStub = h.stubGetChallenge({
162-
required: false
172+
loginGetChallengeStub = h.stubGetChallenge([recaptchav2Response]);
173+
notRequiredStub = h.stubGetSignupChallenge({ required: false });
174+
this.lock = h.displayLock('', lockOpts, () => {
175+
h.clickSignUpTab();
176+
h.waitUntilExists(this.lock, '.auth0-lock-with-terms', () => {
177+
done();
178+
});
163179
});
164-
this.lock = h.displayLock('', lockOpts, done);
165180
});
166181

167182
afterEach(function () {
@@ -181,7 +196,7 @@ describe('captcha on signup', function () {
181196
setTimeout(done, 260);
182197
});
183198

184-
challengeStub = h.stubGetChallenge(recaptchav2Response);
199+
challengeStub = h.stubGetSignupChallenge([recaptchav2Response]);
185200
h.fillEmailInput(this.lock, '[email protected]');
186201
h.fillComplexPassword(this.lock);
187202
h.submitForm(this.lock);
@@ -190,6 +205,7 @@ describe('captcha on signup', function () {
190205
it('should call the challenge api again and show the input', function () {
191206
expect(notRequiredStub.calledOnce).to.be.true;
192207
expect(challengeStub.calledOnce).to.be.true;
208+
expect(loginGetChallengeStub.calledOnce).to.be.false;
193209
expect(h.q(this.lock, '.auth0-lock-recaptchav2')).to.be.ok();
194210
});
195211
});

0 commit comments

Comments
 (0)