Skip to content
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

Added support for hCaptcha and Friendly Captcha #2387

Merged
merged 17 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
28 changes: 28 additions & 0 deletions css/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,34 @@ loadingSize = 30px
transform-origin: 0px 0px;
position: relative;

.auth0-lock-hcaptcha-block
border-radius: 4px;
height: 65px;

&.auth0-lock-hcaptcha-block-error
border: 1px solid red;

.auth0-lock-hcaptcha
transform: scale(0.855);
transform-origin: 0px 0px;
position: relative;

.auth0-lock-friendly-captcha-block
border-radius: 4px;
border: 1px solid #eee;
height: 68px;

&.auth0-lock-friendly-captcha-block-error
border: 1px solid red;

.auth0-lock-friendly-captcha
transform: scale(0.92);
transform-origin: 0px 0px;
margin-left: 9px;
position: relative;
min-height: 68px;


input[type="button"]
cursor pointer

Expand Down
58 changes: 51 additions & 7 deletions src/__tests__/field/captcha.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { mount } from 'enzyme';
import I from 'immutable';

import CaptchaPane from '../../field/captcha/captcha_pane';
import { ReCAPTCHA } from '../../field/captcha/recaptcha';
import { ThirdPartyCaptcha } from '../../field/captcha/third_party_captcha';
import CaptchaInput from '../../ui/input/captcha_input';

const createLockMock = ({ provider = 'auth0', required = true, siteKey = '' } = {}) =>
Expand Down Expand Up @@ -47,12 +47,56 @@ describe('CaptchaPane', () => {
wrapper = mount(<CaptchaPane lock={lockMock} onReload={onReloadMock} i18n={i8nMock} />);
});

it('should render reCaptcha if provider is recaptchav2', () => {
expect(wrapper.find(ReCAPTCHA)).toHaveLength(1);
it('should render ThirdPartyCaptcha if provider is recaptchav2', () => {
expect(wrapper.find(ThirdPartyCaptcha)).toHaveLength(1);
});

it('should pass the sitekey', () => {
expect(wrapper.find(ReCAPTCHA).props().sitekey).toBe('mySiteKey');
expect(wrapper.find(ThirdPartyCaptcha).props().sitekey).toBe('mySiteKey');
});
});

describe('friendly captcha', () => {
let wrapper;
beforeAll(() => {
const lockMock = createLockMock({
provider: 'friendly_captcha',
siteKey: 'mySiteKey'
});
const i8nMock = createI18nMock();
const onReloadMock = jest.fn();

wrapper = mount(<CaptchaPane lock={lockMock} onReload={onReloadMock} i18n={i8nMock} />);
});

it('should render ThirdPartyCaptcha if provider is friendly captcha', () => {
expect(wrapper.find(ThirdPartyCaptcha)).toHaveLength(1);
});

it('should pass the sitekey', () => {
expect(wrapper.find(ThirdPartyCaptcha).props().sitekey).toBe('mySiteKey');
});
});

describe('hcaptcha', () => {
let wrapper;
beforeAll(() => {
const lockMock = createLockMock({
provider: 'hcaptcha',
siteKey: 'mySiteKey'
});
const i8nMock = createI18nMock();
const onReloadMock = jest.fn();

wrapper = mount(<CaptchaPane lock={lockMock} onReload={onReloadMock} i18n={i8nMock} />);
});

it('should render ThirdPartyCaptcha if provider is hCaptcha', () => {
expect(wrapper.find(ThirdPartyCaptcha)).toHaveLength(1);
});

it('should pass the sitekey', () => {
expect(wrapper.find(ThirdPartyCaptcha).props().sitekey).toBe('mySiteKey');
});
});

Expand All @@ -69,12 +113,12 @@ describe('CaptchaPane', () => {
wrapper = mount(<CaptchaPane lock={lockMock} onReload={onReloadMock} i18n={i8nMock} />);
});

it('should render reCaptcha if provider is recaptcha_enterprise', () => {
expect(wrapper.find(ReCAPTCHA)).toHaveLength(1);
it('should render ThirdPartyCaptcha if provider is recaptcha_enterprise', () => {
expect(wrapper.find(ThirdPartyCaptcha)).toHaveLength(1);
});

it('should pass the sitekey', () => {
expect(wrapper.find(ReCAPTCHA).props().sitekey).toBe('mySiteKey');
expect(wrapper.find(ThirdPartyCaptcha).props().sitekey).toBe('mySiteKey');
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`friendly captcha should match the snapshot 1`] = `ShallowWrapper {}`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`hCaptcha should match the snapshot 1`] = `ShallowWrapper {}`;
45 changes: 45 additions & 0 deletions src/__tests__/field/captcha/friendlyCaptcha.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import { shallow } from 'enzyme';
import I from 'immutable';

import { ThirdPartyCaptcha } from '../../../field/captcha/third_party_captcha';

const createLockMock = ({ provider = 'none', sitekey = '' } = {}) =>
I.fromJS({
id: '__lock-id__',
core: {
captcha: { provider, sitekey },
transient: {
ui: {
language: 'en-US'
}
}
}
});

describe('friendly captcha', () => {
it('should match the snapshot', () => {
const mockLock = createLockMock({ provider: 'friendly_captcha', sitekey: 'mySiteKey' });
const wrapper = shallow(
<ThirdPartyCaptcha provider={'friendly_captcha'} lock={mockLock} sitekey={'mySiteKey'} />
);

expect(wrapper).toMatchSnapshot();
});

describe('render', () => {
beforeAll(() => {
document.body.innerHTML = "<div id='renderTest'></div>";
});
afterAll(() => {
document.getElementById('renderTest').remove();
});
it('injects the script', () => {
ThirdPartyCaptcha.loadScript({ hl: 'en-US', provider: 'friendly_captcha' }, document.body);
expect(document.body.innerHTML).toContain('<div id="renderTest">');
expect(document.body.innerHTML).toContain(
'<script src="https://cdn.jsdelivr.net/npm/[email protected]/widget.min.js'
);
});
});
});
45 changes: 45 additions & 0 deletions src/__tests__/field/captcha/hcaptcha.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import { shallow } from 'enzyme';
import I from 'immutable';

import { ThirdPartyCaptcha } from '../../../field/captcha/third_party_captcha';

const createLockMock = ({ provider = 'none', sitekey = '' } = {}) =>
I.fromJS({
id: '__lock-id__',
core: {
captcha: { provider, sitekey },
transient: {
ui: {
language: 'en-US'
}
}
}
});

describe('hCaptcha', () => {
it('should match the snapshot', () => {
const mockLock = createLockMock({ provider: 'hcaptcha', sitekey: 'mySiteKey' });
const wrapper = shallow(
<ThirdPartyCaptcha provider={'hcaptcha'} lock={mockLock} sitekey={'mySiteKey'} />
);

expect(wrapper).toMatchSnapshot();
});

describe('render', () => {
beforeAll(() => {
document.body.innerHTML = "<div id='renderTest'></div>";
});
afterAll(() => {
document.getElementById('renderTest').remove();
});
it('injects the script', () => {
ThirdPartyCaptcha.loadScript({ hl: 'en-US', provider: 'hcaptcha' }, document.body);
expect(document.body.innerHTML).toContain('<div id="renderTest">');
expect(document.body.innerHTML).toContain(
'<script src="https://js.hcaptcha.com/1/api.js?hl=en-US'
);
});
});
});
6 changes: 3 additions & 3 deletions src/__tests__/field/captcha/recaptcha_enterprise.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import I from 'immutable';

import { ReCAPTCHA } from '../../../field/captcha/recaptcha';
import { ThirdPartyCaptcha } from '../../../field/captcha/third_party_captcha';

const createLockMock = ({ provider = 'none', sitekey = '' } = {}) =>
I.fromJS({
Expand All @@ -21,7 +21,7 @@ describe('Recaptcha Enterprise', () => {
it('should match the snapshot', () => {
const mockLock = createLockMock({ provider: 'recaptcha_enterprise', sitekey: 'mySiteKey' });
const wrapper = shallow(
<ReCAPTCHA provider={'recaptcha_enterprise'} lock={mockLock} sitekey={'mySiteKey'} />
<ThirdPartyCaptcha provider={'recaptcha_enterprise'} lock={mockLock} sitekey={'mySiteKey'} />
);

expect(wrapper).toMatchSnapshot();
Expand All @@ -35,7 +35,7 @@ describe('Recaptcha Enterprise', () => {
document.getElementById('renderTest').remove();
});
it('injects the script', () => {
ReCAPTCHA.loadScript({ hl: 'en-US', provider: 'recaptcha_enterprise' }, document.body);
ThirdPartyCaptcha.loadScript({ hl: 'en-US', provider: 'recaptcha_enterprise' }, document.body);
expect(document.body.innerHTML).toContain('<div id="renderTest">');
expect(document.body.innerHTML).toContain(
'<script src="https://www.recaptcha.net/recaptcha/enterprise.js?render=explicit'
Expand Down
6 changes: 3 additions & 3 deletions src/__tests__/field/captcha/recaptchav2.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import { shallow } from 'enzyme';
import I from 'immutable';

import { ReCAPTCHA } from '../../../field/captcha/recaptcha';
import { ThirdPartyCaptcha } from '../../../field/captcha/third_party_captcha';

const createLockMock = ({ provider = 'none', sitekey = '' } = {}) =>
I.fromJS({
Expand All @@ -21,7 +21,7 @@ describe('Recaptcha v2', () => {
it('should match the snapshot', () => {
const mockLock = createLockMock({ provider: 'recaptcha_v2', sitekey: 'mySiteKey' });
const wrapper = shallow(
<ReCAPTCHA provider={'recaptcha_v2'} lock={mockLock} sitekey={'mySiteKey'} />
<ThirdPartyCaptcha provider={'recaptcha_v2'} lock={mockLock} sitekey={'mySiteKey'} />
);

expect(wrapper).toMatchSnapshot();
Expand All @@ -35,7 +35,7 @@ describe('Recaptcha v2', () => {
document.getElementById('renderTest').remove();
});
it('injects the script', () => {
ReCAPTCHA.loadScript({ hl: 'en-US', provider: 'recaptcha_v2' }, document.body);
ThirdPartyCaptcha.loadScript({ hl: 'en-US', provider: 'recaptcha_v2' }, document.body);
expect(document.body.innerHTML).toContain('<div id="renderTest">');
expect(document.body.innerHTML).toContain(
'<script src="https://www.recaptcha.net/recaptcha/api.js?hl=en-US'
Expand Down
4 changes: 3 additions & 1 deletion src/connection/captcha.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ export function showMissingCaptcha(m, id, isPasswordless = false) {

const captchaError = (
captchaConfig.get('provider') === 'recaptcha_v2' ||
captchaConfig.get('provider') === 'recaptcha_enterprise'
captchaConfig.get('provider') === 'recaptcha_enterprise' ||
captchaConfig.get('provider') === 'hcaptcha' ||
captchaConfig.get('provider') === 'friendly_captcha'
frederikprijck marked this conversation as resolved.
Show resolved Hide resolved
) ? 'invalid_recaptcha' : 'invalid_captcha';

const errorMessage = i18n.html(m, ['error', 'login', captchaError]);
Expand Down
2 changes: 1 addition & 1 deletion src/connection/database/login_pane.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default class LoginPane extends React.Component {
strictValidation={false}
/>
);

const captchaPane =
l.captcha(lock) &&
l.captcha(lock).get('required') &&
Expand Down
4 changes: 3 additions & 1 deletion src/connection/passwordless/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ function getErrorMessage(m, id, error) {
const captchaConfig = l.passwordlessCaptcha(m);
key = (
captchaConfig.get('provider') === 'recaptcha_v2' ||
captchaConfig.get('provider') === 'recaptcha_enterprise'
captchaConfig.get('provider') === 'recaptcha_enterprise' ||
captchaConfig.get('provider') === 'hcaptcha' ||
captchaConfig.get('provider') === 'friendly_captcha'
frederikprijck marked this conversation as resolved.
Show resolved Hide resolved
) ? 'invalid_recaptcha' : 'invalid_captcha';
}

Expand Down
4 changes: 3 additions & 1 deletion src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,9 @@ export function loginErrorMessage(m, error, type) {
if (
currentCaptcha && (
currentCaptcha.get('provider') === 'recaptcha_v2' ||
currentCaptcha.get('provider') === 'recaptcha_enterprise'
currentCaptcha.get('provider') === 'recaptcha_enterprise' ||
currentCaptcha.get('provider') === 'hcaptcha' ||
captchaConfig.get('provider') === 'friendly_captcha'
frederikprijck marked this conversation as resolved.
Show resolved Hide resolved
)) {
code = 'invalid_recaptcha';
}
Expand Down
6 changes: 3 additions & 3 deletions src/field/captcha/captcha_pane.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import * as l from '../../core/index';
import { swap, updateEntity } from '../../store/index';
import * as captchaField from '../captcha';
import { getFieldValue, isFieldVisiblyInvalid } from '../index';
import { ReCAPTCHA, isRecaptcha } from './recaptcha';
import { ThirdPartyCaptcha, isThirdPartyCaptcha } from './third_party_captcha';

export default class CaptchaPane extends React.Component {
render() {
Expand All @@ -18,7 +18,7 @@ export default class CaptchaPane extends React.Component {
const isValid = !isFieldVisiblyInvalid(lock, 'captcha');
const provider = captcha.get('provider');

if (isRecaptcha(provider)) {
if (isThirdPartyCaptcha(provider)) {
function handleChange(value) {
swap(updateEntity, 'lock', lockId, captchaField.set, value);
}
Expand All @@ -28,7 +28,7 @@ export default class CaptchaPane extends React.Component {
}

return (
<ReCAPTCHA
<ThirdPartyCaptcha
provider={provider}
sitekey={captcha.get('siteKey')}
onChange={handleChange}
Expand Down
Loading