Skip to content

Commit

Permalink
feat(loader): Use @hcaptcha/loader package for loading script
Browse files Browse the repository at this point in the history
  • Loading branch information
faris-imi committed Oct 24, 2023
1 parent d259497 commit ebce9b1
Show file tree
Hide file tree
Showing 9 changed files with 127 additions and 95 deletions.
3 changes: 2 additions & 1 deletion demo/app/examples/AsyncExample.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ export function AsyncExample() {
onClose={handleClose}
onError={handleError}
onChalExpired={handleChallengeExpired}
sentry={false}
/>
<button onClick={executeCaptcha}>Execute asynchronously</button>
<button onClick={getRespKey}>Get Response Key</button>
<button onClick={getResponse}>Get Response</button>
</div>
);
}
}
3 changes: 2 additions & 1 deletion demo/app/examples/ClassExample.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export class ClassExample extends React.Component {
onClose={this.handleClose}
onError={this.handleError}
onChalExpired={this.handleChallengeExpired}
sentry={false}
/>
{isVerified &&
<div>
Expand All @@ -84,4 +85,4 @@ export class ClassExample extends React.Component {
</div>
);
}
}
}
3 changes: 2 additions & 1 deletion demo/app/examples/FrameExample.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export function FrameExample({ document }) {
onChalExpired={handleChallengeExpired}
scriptLocation={document.head}
challenge-container={document.body}
sentry={false}
/>
);
}
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
"webpack-dev-server": "^4.13.1"
},
"dependencies": {
"@babel/runtime": "^7.17.9"
"@babel/runtime": "^7.17.9",
"@hcaptcha/loader": "^1.0.5"
}
}
101 changes: 50 additions & 51 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,6 @@
import * as React from 'react';
import { generateQuery, getFrame, getMountElement } from './utils.js';

const SCRIPT_ID = 'hcaptcha-api-script-id';
const HCAPTCHA_LOAD_FN_NAME = 'hcaptchaOnLoad';

// Prevent loading API script multiple times
const scripts = [];

// Generate hCaptcha API script
const mountCaptchaScript = (params = {}) => {
const element = getMountElement(params.scriptLocation);
delete params.scriptLocation;

const frame = getFrame(element);
const script = scripts.find(({ scope }) => scope === frame.window);

if (frame.document.getElementById(SCRIPT_ID) && script) {
// API was already requested
return script.promise;
}

const promise = new Promise((resolve, reject) => {
// Create global onload callback
frame.window[HCAPTCHA_LOAD_FN_NAME] = resolve;

const domain = params.apihost || "https://js.hcaptcha.com";
delete params.apihost;

const script = frame.document.createElement("script");
script.id = SCRIPT_ID;
script.src = `${domain}/1/api.js?render=explicit&onload=${HCAPTCHA_LOAD_FN_NAME}`;

script.async = params.loadAsync !== undefined? params.loadAsync : true;
delete params.loadAsync;

script.onerror = (event) => reject('script-error');

const query = generateQuery(params);
script.src += query !== ""? `&${query}` : "";

element.appendChild(script);
});

scripts.push({ promise, scope: frame.window });

return promise;
};
import { getFrame, getMountElement } from './utils.js';
import { hCaptchaLoader, initSentry } from '@hcaptcha/loader';


class HCaptcha extends React.Component {
Expand Down Expand Up @@ -78,6 +33,7 @@ class HCaptcha extends React.Component {

this.ref = React.createRef();
this.apiScriptRequested = false;
this.sentryHub = null;

this.state = {
isApiReady: false,
Expand All @@ -94,6 +50,16 @@ class HCaptcha extends React.Component {

const isApiReady = typeof this._hcaptcha !== 'undefined';

this.sentryHub = initSentry(this.props.sentry);
this.sentryHub?.setTag('@hCaptcha/react');

this.sentryHub?.addBreadcrumb({
category: 'react-sdk',
message: 'hCaptcha component mounted',
level: 'info'
});


/*
* Check if hCaptcha has already been loaded,
* If Yes, render the captcha
Expand Down Expand Up @@ -126,6 +92,12 @@ class HCaptcha extends React.Component {
// Reset any stored variables / timers when unmounting
hcaptcha.reset(captchaId);
hcaptcha.remove(captchaId);

this.sentryHub?.addBreadcrumb({
category: 'react-sdk',
message: 'hCaptcha component unmounted',
level: 'info'
});
}

shouldComponentUpdate(nextProps, nextState) {
Expand Down Expand Up @@ -171,23 +143,24 @@ class HCaptcha extends React.Component {
scriptLocation
} = this.props;
const mountParams = {
render: 'explicit',
apihost,
assethost,
endpoint,
hl,
host,
imghost,
recaptchacompat: reCaptchaCompat === false? "off" : null,
recaptchacompat: reCaptchaCompat === false? 'off' : null,
reportapi,
sentry,
custom,
loadAsync,
scriptLocation,
};

mountCaptchaScript(mountParams)
.then(this.handleOnLoad)
.catch(this.handleError);
hCaptchaLoader(mountParams)
.then(this.handleOnLoad, this.handleError);

this.apiScriptRequested = true;
}

Expand Down Expand Up @@ -225,6 +198,12 @@ class HCaptcha extends React.Component {
}
// Reset captcha state, removes stored token and unticks checkbox
hcaptcha.reset(captchaId)

this.sentryHub?.addBreadcrumb({
category: 'react-sdk',
message: 'hCaptcha reset',
level: 'info'
});
}

removeCaptcha(callback) {
Expand All @@ -239,6 +218,13 @@ class HCaptcha extends React.Component {
hcaptcha.remove(captchaId);
callback && callback()
});


this.sentryHub?.addBreadcrumb({
category: 'react-sdk',
message: 'hCaptcha removed',
level: 'info'
});
}

handleOnLoad () {
Expand All @@ -255,6 +241,11 @@ class HCaptcha extends React.Component {
if (onLoad) onLoad();
});
});
this.sentryHub?.addBreadcrumb({
category: 'react-sdk',
message: 'hCaptcha loaded',
level: 'info'
});
}

handleSubmit (event) {
Expand All @@ -281,6 +272,12 @@ class HCaptcha extends React.Component {
hcaptcha.reset(captchaId) // If hCaptcha runs into error, reset captcha - hCaptcha

if (onExpire) onExpire();

this.sentryHub?.addBreadcrumb({
category: 'react-sdk',
message: 'hCaptcha expired',
level: 'info'
});
}

handleError (event) {
Expand All @@ -293,6 +290,8 @@ class HCaptcha extends React.Component {
hcaptcha.reset(captchaId);
}

this.sentryHub?.captureException(event);

if (onError) onError(event);
}

Expand Down
11 changes: 1 addition & 10 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
function generateQuery(params) {
return Object.entries(params)
.filter(([key, value]) => value || value === false)
.map(([key, value]) => {
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`
}).join("&");
};

function getFrame(element) {
const doc = (element && element.ownerDocument) || document;
const win = doc.defaultView || doc.parentWindow || window;
Expand All @@ -18,7 +10,6 @@ function getMountElement(element) {
}

export {
generateQuery,
getFrame,
getMountElement
};
};
Loading

0 comments on commit ebce9b1

Please sign in to comment.