Skip to content

Commit e123925

Browse files
committed
feat: address PR feedback:
- replace arrow fn with regular functions - update provider registry - align getSupportingCodeToInject return types
1 parent 68f136c commit e123925

File tree

15 files changed

+121
-94
lines changed

15 files changed

+121
-94
lines changed

injected/src/features/broker-protection/actions/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import * as deprecatedCaptchaHandlers from './captcha-deprecated';
1212
* @param {Object} params
1313
* @param {boolean} params.useNewActionHandlers
1414
*/
15-
export const resolveActionHandlers = ({ useNewActionHandlers }) => {
15+
export function resolveActionHandlers({ useNewActionHandlers }) {
1616
return {
1717
extract,
1818
fillForm,
@@ -28,4 +28,4 @@ export const resolveActionHandlers = ({ useNewActionHandlers }) => {
2828
...deprecatedCaptchaHandlers,
2929
}),
3030
};
31-
};
31+
}

injected/src/features/broker-protection/actions/navigate.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ import { buildUrl } from './build-url';
1010
* @param {Record<string, any>} userData
1111
* @return {import('../types.js').ActionResponse}
1212
*/
13-
export const navigate = (action, userData) => {
14-
const { id: actionID, actionType, injectCaptchaHandler } = action;
15-
try {
16-
const urlResult = buildUrl(action, userData);
17-
if (urlResult instanceof ErrorResponse) {
18-
return urlResult;
19-
}
20-
21-
const codeToInject = injectCaptchaHandler ? getSupportingCodeToInject(injectCaptchaHandler) : null;
22-
const response = {
23-
...urlResult.success.response,
24-
...(codeToInject && { code: codeToInject }),
25-
};
13+
export function navigate(action, userData) {
14+
const { id: actionID, actionType } = action;
15+
const urlResult = buildUrl(action, userData);
16+
if (urlResult instanceof ErrorResponse) {
17+
return urlResult;
18+
}
2619

27-
return new SuccessResponse({ actionID, actionType, response });
28-
} catch (e) {
29-
return new ErrorResponse({ actionID, message: `[navigate] ${e.message}` });
20+
const codeToInjectResponse = getSupportingCodeToInject(action);
21+
if (codeToInjectResponse instanceof ErrorResponse) {
22+
return codeToInjectResponse;
3023
}
31-
};
24+
25+
const response = {
26+
...urlResult.success.response,
27+
...codeToInjectResponse.success.response,
28+
};
29+
30+
return new SuccessResponse({ actionID, actionType, response });
31+
}

injected/src/features/broker-protection/captcha-services/captcha.service.js

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,25 @@ import { captchaFactory } from './providers/registry.js';
77
/**
88
* Returns the supporting code to inject for the given captcha type
99
*
10-
* @param {import('../types.js').PirAction['captchaType']} captchaType
11-
* @return string
12-
* @throws {Error}
10+
* @param {import('../types.js').PirAction} action
11+
* @return {import('../types.js').ActionResponse}
1312
*/
14-
export const getSupportingCodeToInject = (captchaType) => {
13+
export function getSupportingCodeToInject(action) {
14+
const { id: actionID, actionType, injectCaptchaHandler: captchaType } = action;
15+
if (!captchaType) {
16+
return new SuccessResponse({ actionID, actionType, response: {} });
17+
}
18+
1519
const captchaProvider = captchaFactory.getProviderByType(captchaType);
1620
if (!captchaProvider) {
17-
throw new Error(`[injectCaptchaHandler] could not find captchaProvider with type ${captchaType}`);
21+
return new ErrorResponse({
22+
actionID,
23+
message: `[injectCaptchaHandler] could not find captchaProvider with type ${captchaType}`,
24+
});
1825
}
1926

20-
return captchaProvider.getSupportingCodeToInject();
21-
};
27+
return new SuccessResponse({ actionID, actionType, response: { code: captchaProvider.getSupportingCodeToInject() } });
28+
}
2229

2330
/**
2431
* Gets the captcha information to send to the backend
@@ -27,7 +34,7 @@ export const getSupportingCodeToInject = (captchaType) => {
2734
* @param {Document | HTMLElement} root
2835
* @return {import('../types.js').ActionResponse}
2936
*/
30-
export const getCaptchaInfo = (action, root = document) => {
37+
export function getCaptchaInfo(action, root = document) {
3138
const { id: actionID, selector, actionType, captchaType } = action;
3239
try {
3340
if (!selector) {
@@ -54,7 +61,7 @@ export const getCaptchaInfo = (action, root = document) => {
5461
} catch (e) {
5562
return new ErrorResponse({ actionID, message: `[getCaptchaInfo] ${e.message}` });
5663
}
57-
};
64+
}
5865

5966
/**
6067
* Takes the solved captcha token and injects it into the page to solve the captcha
@@ -64,7 +71,7 @@ export const getCaptchaInfo = (action, root = document) => {
6471
* @param {Document} root
6572
* @return {import('../types.js').ActionResponse}
6673
*/
67-
export const solveCaptcha = (action, token, root = document) => {
74+
export function solveCaptcha(action, token, root = document) {
6875
const { id: actionID, actionType, captchaType } = action;
6976
try {
7077
if (!captchaType) {
@@ -76,7 +83,11 @@ export const solveCaptcha = (action, token, root = document) => {
7683
throw new Error(`[solveCaptcha] cannot solve captcha with type ${captchaType}`);
7784
}
7885

79-
captchaSolveProvider.injectToken(root, token);
86+
const isTokenInjected = captchaSolveProvider.injectToken(root, token);
87+
if (!isTokenInjected) {
88+
throw new Error(`[solveCaptcha] could not inject token for captcha with type ${captchaType}`);
89+
}
90+
8091
return new SuccessResponse({
8192
actionID,
8293
actionType,
@@ -85,4 +96,4 @@ export const solveCaptcha = (action, token, root = document) => {
8596
} catch (e) {
8697
return new ErrorResponse({ actionID, message: `[solveCaptcha] ${e.message}` });
8798
}
88-
};
99+
}

injected/src/features/broker-protection/captcha-services/factory.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@ export class CaptchaFactory {
88

99
/**
1010
* Register a captcha provider
11-
* @param {typeof import('./providers/provider.interface').CaptchaProvider} ProviderClass
11+
* @param {import('./providers/provider.interface').CaptchaProvider} provider - The provider to register
1212
*/
13-
registerProvider(ProviderClass) {
14-
const provider = new ProviderClass();
13+
registerProvider(provider) {
1514
this.providers.set(provider.getType(), provider);
1615
}
1716

injected/src/features/broker-protection/captcha-services/get-captcha-provider.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { captchaFactory } from './providers/registry';
88
* @return {import('./providers/provider.interface.js').CaptchaProvider}
99
* @throws {Error}
1010
*/
11-
export const getCaptchaProvider = (captchaDiv, captchaType) => {
11+
export function getCaptchaProvider(captchaDiv, captchaType) {
1212
const captchaProvider = captchaFactory.getProviderByType(captchaType);
1313
if (!captchaProvider) {
1414
throw new Error(`[getCaptchaProvider] could not find captchaProvider with type ${captchaType}`);
@@ -29,7 +29,7 @@ export const getCaptchaProvider = (captchaDiv, captchaType) => {
2929
}
3030

3131
return detectedProvider;
32-
};
32+
}
3333

3434
/**
3535
* Gets the captcha provider for the solveCaptcha action
@@ -38,7 +38,7 @@ export const getCaptchaProvider = (captchaDiv, captchaType) => {
3838
* @return {import('./providers/provider.interface.js').CaptchaProvider}
3939
* @throws {Error}
4040
*/
41-
export const getCaptchaSolveProvider = (root, captchaType) => {
41+
export function getCaptchaSolveProvider(root, captchaType) {
4242
const captchaProvider = captchaFactory.getProviderByType(captchaType);
4343
if (!captchaProvider) {
4444
throw new Error(`[getCaptchaSolveProvider] could not find captchaProvider with type ${captchaType}`);
@@ -59,4 +59,4 @@ export const getCaptchaSolveProvider = (root, captchaType) => {
5959
}
6060

6161
return detectedProvider;
62-
};
62+
}

injected/src/features/broker-protection/captcha-services/providers/cloudflare-turnstile.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { CaptchaProvider } from './provider.interface';
2-
3-
export class CloudFlareTurnstileProvider extends CaptchaProvider {
1+
/**
2+
* @import { CaptchaProvider } from './provider.interface';
3+
* @implements {CaptchaProvider}
4+
*/
5+
export class CloudFlareTurnstileProvider {
46
getType() {
57
return 'cloudflareTurnstile';
68
}

injected/src/features/broker-protection/captcha-services/providers/hcaptcha.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@ import { getUrlHashParameter, getUrlParameter } from '../../utils/url';
22
import { getElementByName, getElementWithSrcStart } from '../../utils/utils';
33
import { stringifyFunction } from '../utils/stringify-function';
44
import { injectTokenIntoElement } from '../utils/token';
5-
import { CaptchaProvider } from './provider.interface';
65

76
/**
8-
* Provider for hCaptcha
7+
* @import { CaptchaProvider } from './provider.interface';
8+
* @implements {CaptchaProvider}
99
*/
10-
export class HCaptchaProvider extends CaptchaProvider {
10+
export class HCaptchaProvider {
1111
#CAPTCHA_URL = 'https://newassets.hcaptcha.com/captcha';
1212
#CAPTCHA_RESPONSE_ELEMENT_NAME = 'h-captcha-response';
1313

@@ -41,6 +41,10 @@ export class HCaptchaProvider extends CaptchaProvider {
4141
return siteKey;
4242
}
4343

44+
getSupportingCodeToInject() {
45+
return null;
46+
}
47+
4448
/**
4549
* @param {string} token - The solved captcha token
4650
*/

injected/src/features/broker-protection/captcha-services/providers/recaptcha-enterprise.js

Lines changed: 0 additions & 15 deletions
This file was deleted.

injected/src/features/broker-protection/captcha-services/providers/recaptcha-v2.js renamed to injected/src/features/broker-protection/captcha-services/providers/recaptcha.js

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,37 @@
1-
import { CaptchaProvider } from './provider.interface';
21
import { getElementByName, getElementWithSrcStart } from '../../utils/utils';
32
import { getSiteKeyFromSearchParam } from '../utils/sitekey';
43
import { stringifyFunction } from '../utils/stringify-function';
54
import { injectTokenIntoElement } from '../utils/token';
65
// TODO move on the same folder level once we deprecate the existing captcha scripts
76
import { captchaCallback } from '../../actions/captcha-callback';
87

9-
export class ReCaptchaV2Provider extends CaptchaProvider {
10-
getType() {
11-
return 'recaptcha2';
12-
}
8+
// define the config below to reuse it in the class
9+
/**
10+
* @typedef {Object} ReCaptchaProviderConfig
11+
* @property {string} type - The captcha type
12+
* @property {string} providerUrl - The captcha provider URL
13+
* @property {string} responseElementName - The name of the captcha response element
14+
*/
1315

16+
/**
17+
* @import { CaptchaProvider } from './provider.interface';
18+
* @implements {CaptchaProvider}
19+
*/
20+
export class ReCaptchaProvider {
1421
/**
15-
* @protected
22+
* @type {ReCaptchaProviderConfig}
1623
*/
17-
getCaptchaProviderUrl() {
18-
return 'https://www.google.com/recaptcha/api2';
19-
}
24+
#config;
2025

2126
/**
22-
* @protected
27+
* @param {ReCaptchaProviderConfig} config
2328
*/
24-
getCaptchaResponseElementName() {
25-
return 'g-recaptcha-response';
29+
constructor(config) {
30+
this.#config = config;
31+
}
32+
33+
getType() {
34+
return this.#config.type;
2635
}
2736

2837
/**
@@ -40,6 +49,10 @@ export class ReCaptchaV2Provider extends CaptchaProvider {
4049
return getSiteKeyFromSearchParam({ captchaElement: this._getCaptchaElement(captchaContainerElement), siteKeyAttrName: 'k' });
4150
}
4251

52+
getSupportingCodeToInject() {
53+
return null;
54+
}
55+
4356
/**
4457
* @param {string} token
4558
*/
@@ -55,22 +68,22 @@ export class ReCaptchaV2Provider extends CaptchaProvider {
5568
* @param {Document} root
5669
*/
5770
canSolve(root) {
58-
return !!getElementByName(root, this.getCaptchaResponseElementName());
71+
return !!getElementByName(root, this.#config.responseElementName);
5972
}
6073

6174
/**
6275
* @param {Document} root
6376
* @param {string} token
6477
*/
6578
injectToken(root, token) {
66-
return injectTokenIntoElement({ root, elementName: this.getCaptchaResponseElementName(), token });
79+
return injectTokenIntoElement({ root, elementName: this.#config.responseElementName, token });
6780
}
6881

6982
/**
7083
* @private
7184
* @param {HTMLElement} captchaContainerElement
7285
*/
7386
_getCaptchaElement(captchaContainerElement) {
74-
return getElementWithSrcStart(captchaContainerElement, this.getCaptchaProviderUrl());
87+
return getElementWithSrcStart(captchaContainerElement, this.#config.providerUrl);
7588
}
7689
}
Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
import { CaptchaFactory } from '../factory';
2-
import { ReCaptchaV2Provider } from './recaptcha-v2';
3-
import { ReCaptchaEnterpriseProvider } from './recaptcha-enterprise';
2+
import { ReCaptchaProvider } from './recaptcha';
43
import { CloudFlareTurnstileProvider } from './cloudflare-turnstile';
54
import { HCaptchaProvider } from './hcaptcha';
65

76
const captchaFactory = new CaptchaFactory();
87

9-
captchaFactory.registerProvider(ReCaptchaV2Provider);
10-
captchaFactory.registerProvider(ReCaptchaEnterpriseProvider);
11-
captchaFactory.registerProvider(CloudFlareTurnstileProvider);
12-
captchaFactory.registerProvider(HCaptchaProvider);
8+
captchaFactory.registerProvider(
9+
new ReCaptchaProvider({
10+
type: 'recaptcha2',
11+
providerUrl: 'https://www.google.com/recaptcha/api2',
12+
responseElementName: 'g-recaptcha-response',
13+
}),
14+
);
15+
16+
captchaFactory.registerProvider(
17+
new ReCaptchaProvider({
18+
type: 'recaptchaEnterprise',
19+
providerUrl: 'https://www.google.com/recaptcha/enterprise',
20+
responseElementName: 'g-recaptcha-response',
21+
}),
22+
);
23+
24+
captchaFactory.registerProvider(new CloudFlareTurnstileProvider());
25+
captchaFactory.registerProvider(new HCaptchaProvider());
1326

1427
export { captchaFactory };

injected/src/features/broker-protection/captcha-services/utils/sitekey.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { getUrlParameter } from '../../utils/url';
99
* @returns {string | null} The site key extracted from the captcha element's URL or null if not found
1010
* @throws {Error}
1111
*/
12-
export const getSiteKeyFromSearchParam = ({ captchaElement, siteKeyAttrName }) => {
12+
export function getSiteKeyFromSearchParam({ captchaElement, siteKeyAttrName }) {
1313
if (!captchaElement) {
1414
throw Error('[getSiteKeyFromSearchParam] could not find captcha');
1515
}
@@ -19,4 +19,4 @@ export const getSiteKeyFromSearchParam = ({ captchaElement, siteKeyAttrName }) =
1919
}
2020

2121
return getUrlParameter(String(captchaElement.src), siteKeyAttrName);
22-
};
22+
}

injected/src/features/broker-protection/captcha-services/utils/stringify-function.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import { safeCall } from '../../utils/safe-call';
77
* @param {Object} params.args - The arguments to pass to the function
88
* @returns {string|null} - The stringified function
99
*/
10-
export const stringifyFunction = ({ functionName, functionBody, args }) => {
10+
export function stringifyFunction({ functionName, functionBody, args }) {
1111
return safeCall(
1212
() => `;(function(args) {
1313
${functionBody.toString()};
1414
${functionName}(args);
1515
})(${JSON.stringify(args)});`,
1616
{ errorMessage: `[stringifyFunction] error stringifying function ${functionName}` },
1717
);
18-
};
18+
}

0 commit comments

Comments
 (0)