@hcaptcha/react-hcaptcha 1.17.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -4
- package/lib/dist/cjs/hooks/index.js +4 -0
- package/lib/dist/cjs/index.js +4 -0
- package/lib/dist/esm/hooks/index.js +4 -0
- package/lib/dist/esm/index.js +4 -0
- package/package.json +41 -61
- package/types/hooks/index.d.ts +2 -3
- package/types/index.d.ts +18 -19
- package/dist/esm/hooks/Context.js +0 -2
- package/dist/esm/hooks/Provider.js +0 -120
- package/dist/esm/hooks/index.js +0 -2
- package/dist/esm/hooks/useHCaptcha.tsx +0 -4
- package/dist/esm/index.js +0 -421
- package/dist/esm/package.json +0 -1
- package/dist/esm/utils.js +0 -12
- package/dist/hooks/Context.js +0 -8
- package/dist/hooks/Provider.js +0 -137
- package/dist/hooks/index.js +0 -19
- package/dist/hooks/useHCaptcha.tsx +0 -4
- package/dist/index.js +0 -484
- package/dist/utils.js +0 -18
- package/src/hooks/Context.jsx +0 -3
- package/src/hooks/Provider.jsx +0 -98
- package/src/hooks/index.jsx +0 -2
- package/src/hooks/useHCaptcha.tsx +0 -4
- package/src/index.js +0 -471
- package/src/utils.js +0 -15
package/src/index.js
DELETED
|
@@ -1,471 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { hCaptchaLoader } from '@hcaptcha/loader';
|
|
3
|
-
|
|
4
|
-
import { getFrame, getMountElement } from './utils.js';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class HCaptcha extends React.Component {
|
|
8
|
-
constructor (props) {
|
|
9
|
-
super(props);
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Internal reference to track hCaptcha API
|
|
13
|
-
*
|
|
14
|
-
* Required as window is relative to initialization in application
|
|
15
|
-
* not where the script and iFrames have been loaded.
|
|
16
|
-
*/
|
|
17
|
-
this._hcaptcha = undefined;
|
|
18
|
-
|
|
19
|
-
// API Methods
|
|
20
|
-
this.renderCaptcha = this.renderCaptcha.bind(this);
|
|
21
|
-
this.resetCaptcha = this.resetCaptcha.bind(this);
|
|
22
|
-
this.removeCaptcha = this.removeCaptcha.bind(this);
|
|
23
|
-
this.isReady = this.isReady.bind(this);
|
|
24
|
-
this._onReady = null;
|
|
25
|
-
|
|
26
|
-
// Event Handlers
|
|
27
|
-
this.loadCaptcha = this.loadCaptcha.bind(this);
|
|
28
|
-
this.handleOnLoad = this.handleOnLoad.bind(this);
|
|
29
|
-
this.handleSubmit = this.handleSubmit.bind(this);
|
|
30
|
-
this.handleExpire = this.handleExpire.bind(this);
|
|
31
|
-
this.handleError = this.handleError.bind(this);
|
|
32
|
-
this.handleOpen = this.handleOpen.bind(this);
|
|
33
|
-
this.handleClose = this.handleClose.bind(this);
|
|
34
|
-
this.handleChallengeExpired = this.handleChallengeExpired.bind(this);
|
|
35
|
-
|
|
36
|
-
this.ref = React.createRef();
|
|
37
|
-
this.apiScriptRequested = false;
|
|
38
|
-
this.sentryHub = null;
|
|
39
|
-
this.captchaId = '';
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Tracks the currently pending async execute() promise.
|
|
43
|
-
* Stores { resolve, reject } so we can cancel on unmount/errors/etc.
|
|
44
|
-
*/
|
|
45
|
-
this._pendingExecute = null;
|
|
46
|
-
|
|
47
|
-
this.state = {
|
|
48
|
-
isApiReady: false,
|
|
49
|
-
isRemoved: false,
|
|
50
|
-
elementId: props.id,
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
componentDidMount () { // Once captcha is mounted intialize hCaptcha - hCaptcha
|
|
55
|
-
const element = getMountElement(this.props.scriptLocation);
|
|
56
|
-
const frame = getFrame(element);
|
|
57
|
-
this._hcaptcha = frame.window.hcaptcha || undefined;
|
|
58
|
-
|
|
59
|
-
const isApiReady = typeof this._hcaptcha !== 'undefined';
|
|
60
|
-
|
|
61
|
-
/*
|
|
62
|
-
* Check if hCaptcha has already been loaded,
|
|
63
|
-
* If Yes, render the captcha
|
|
64
|
-
* If No, create script tag and wait to render the captcha
|
|
65
|
-
*/
|
|
66
|
-
if (isApiReady) {
|
|
67
|
-
this.setState(
|
|
68
|
-
{
|
|
69
|
-
isApiReady: true
|
|
70
|
-
},
|
|
71
|
-
() => {
|
|
72
|
-
this.renderCaptcha();
|
|
73
|
-
}
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
this.loadCaptcha();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
componentWillUnmount() {
|
|
83
|
-
const hcaptcha = this._hcaptcha;
|
|
84
|
-
const captchaId = this.captchaId;
|
|
85
|
-
|
|
86
|
-
this._cancelPendingExecute('react-component-unmounted');
|
|
87
|
-
|
|
88
|
-
if (!this.isReady()) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Reset any stored variables / timers when unmounting
|
|
93
|
-
hcaptcha.reset(captchaId);
|
|
94
|
-
hcaptcha.remove(captchaId);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
shouldComponentUpdate(nextProps, nextState) {
|
|
98
|
-
// Prevent component re-rendering when these internal state variables are updated
|
|
99
|
-
if (this.state.isApiReady !== nextState.isApiReady || this.state.isRemoved !== nextState.isRemoved) {
|
|
100
|
-
return false;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return true;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
componentDidUpdate(prevProps) {
|
|
107
|
-
// Prop Keys that could change
|
|
108
|
-
const keys = ['sitekey', 'size', 'theme', 'tabindex', 'languageOverride', 'endpoint'];
|
|
109
|
-
// See if any props changed during component update
|
|
110
|
-
const match = keys.every( key => prevProps[key] === this.props[key]);
|
|
111
|
-
|
|
112
|
-
// If they have changed, remove current captcha and render a new one
|
|
113
|
-
if (!match) {
|
|
114
|
-
this.removeCaptcha(() => {
|
|
115
|
-
this.renderCaptcha();
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
loadCaptcha() {
|
|
121
|
-
if (this.apiScriptRequested) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const {
|
|
126
|
-
apihost,
|
|
127
|
-
assethost,
|
|
128
|
-
endpoint,
|
|
129
|
-
host,
|
|
130
|
-
imghost,
|
|
131
|
-
languageOverride: hl,
|
|
132
|
-
reCaptchaCompat,
|
|
133
|
-
reportapi,
|
|
134
|
-
sentry,
|
|
135
|
-
custom,
|
|
136
|
-
loadAsync,
|
|
137
|
-
scriptLocation,
|
|
138
|
-
scriptSource,
|
|
139
|
-
secureApi,
|
|
140
|
-
cleanup = true,
|
|
141
|
-
userJourneys,
|
|
142
|
-
} = this.props;
|
|
143
|
-
|
|
144
|
-
const mountParams = {
|
|
145
|
-
render: 'explicit',
|
|
146
|
-
apihost,
|
|
147
|
-
assethost,
|
|
148
|
-
endpoint,
|
|
149
|
-
hl,
|
|
150
|
-
host,
|
|
151
|
-
imghost,
|
|
152
|
-
recaptchacompat: reCaptchaCompat === false? 'off' : null,
|
|
153
|
-
reportapi,
|
|
154
|
-
sentry,
|
|
155
|
-
custom,
|
|
156
|
-
loadAsync,
|
|
157
|
-
scriptLocation,
|
|
158
|
-
scriptSource,
|
|
159
|
-
secureApi,
|
|
160
|
-
cleanup,
|
|
161
|
-
uj: userJourneys !== undefined ? userJourneys : false,
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
hCaptchaLoader(mountParams)
|
|
165
|
-
.then(this.handleOnLoad, this.handleError)
|
|
166
|
-
.catch(this.handleError);
|
|
167
|
-
|
|
168
|
-
this.apiScriptRequested = true;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
renderCaptcha(onRender) {
|
|
172
|
-
const { onReady } = this.props;
|
|
173
|
-
const { isApiReady } = this.state;
|
|
174
|
-
const captchaId = this.captchaId;
|
|
175
|
-
|
|
176
|
-
// Prevent calling hCaptcha render on two conditions:
|
|
177
|
-
// • API is not ready
|
|
178
|
-
// • Component has already been mounted
|
|
179
|
-
if (!isApiReady || captchaId) return;
|
|
180
|
-
|
|
181
|
-
const renderParams = Object.assign({
|
|
182
|
-
"open-callback" : this.handleOpen,
|
|
183
|
-
"close-callback" : this.handleClose,
|
|
184
|
-
"error-callback" : this.handleError,
|
|
185
|
-
"chalexpired-callback": this.handleChallengeExpired,
|
|
186
|
-
"expired-callback" : this.handleExpire,
|
|
187
|
-
"callback" : this.handleSubmit,
|
|
188
|
-
}, this.props, {
|
|
189
|
-
hl: this.props.hl || this.props.languageOverride,
|
|
190
|
-
languageOverride: undefined
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
const hcaptcha = this._hcaptcha;
|
|
194
|
-
//Render hCaptcha widget and provide necessary callbacks - hCaptcha
|
|
195
|
-
const id = hcaptcha.render(this.ref.current, renderParams);
|
|
196
|
-
this.captchaId = id;
|
|
197
|
-
|
|
198
|
-
this.setState({ isRemoved: false }, () => {
|
|
199
|
-
onRender && onRender();
|
|
200
|
-
onReady && onReady();
|
|
201
|
-
this._onReady && this._onReady(id);
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
resetCaptcha() {
|
|
206
|
-
const hcaptcha = this._hcaptcha;
|
|
207
|
-
const captchaId = this.captchaId;
|
|
208
|
-
|
|
209
|
-
if (!this.isReady()) {
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Reset captcha state, removes stored token and unticks checkbox
|
|
214
|
-
hcaptcha.reset(captchaId)
|
|
215
|
-
|
|
216
|
-
this._cancelPendingExecute('hcaptcha-reset');
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
removeCaptcha(callback) {
|
|
220
|
-
const hcaptcha = this._hcaptcha;
|
|
221
|
-
const captchaId = this.captchaId;
|
|
222
|
-
|
|
223
|
-
this._cancelPendingExecute('hcaptcha-removed');
|
|
224
|
-
|
|
225
|
-
if (!this.isReady()) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
this.setState({ isRemoved: true }, () => {
|
|
230
|
-
this.captchaId = '';
|
|
231
|
-
|
|
232
|
-
hcaptcha.remove(captchaId);
|
|
233
|
-
|
|
234
|
-
callback && callback()
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
handleOnLoad () {
|
|
239
|
-
this.setState({ isApiReady: true }, () => {
|
|
240
|
-
const element = getMountElement(this.props.scriptLocation);
|
|
241
|
-
const frame = getFrame(element);
|
|
242
|
-
|
|
243
|
-
this._hcaptcha = frame.window.hcaptcha;
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
// render captcha and wait for captcha id
|
|
247
|
-
this.renderCaptcha(() => {
|
|
248
|
-
// trigger onLoad if it exists
|
|
249
|
-
|
|
250
|
-
const { onLoad } = this.props;
|
|
251
|
-
if (onLoad) onLoad();
|
|
252
|
-
});
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
handleSubmit (event) {
|
|
257
|
-
const { onVerify } = this.props;
|
|
258
|
-
const { isRemoved } = this.state;
|
|
259
|
-
const hcaptcha = this._hcaptcha;
|
|
260
|
-
const captchaId = this.captchaId;
|
|
261
|
-
|
|
262
|
-
if (typeof hcaptcha === 'undefined' || isRemoved) return
|
|
263
|
-
|
|
264
|
-
const token = hcaptcha.getResponse(captchaId) //Get response token from hCaptcha widget
|
|
265
|
-
const ekey = hcaptcha.getRespKey(captchaId) //Get current challenge session id from hCaptcha widget
|
|
266
|
-
if (onVerify) onVerify(token, ekey) //Dispatch event to verify user response
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
handleExpire () {
|
|
270
|
-
const { onExpire } = this.props;
|
|
271
|
-
const hcaptcha = this._hcaptcha;
|
|
272
|
-
const captchaId = this.captchaId;
|
|
273
|
-
|
|
274
|
-
if (!this.isReady()) {
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
hcaptcha.reset(captchaId) // If hCaptcha runs into error, reset captcha - hCaptcha
|
|
279
|
-
|
|
280
|
-
if (onExpire) onExpire();
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
handleError (event) {
|
|
284
|
-
const { onError } = this.props;
|
|
285
|
-
const hcaptcha = this._hcaptcha;
|
|
286
|
-
const captchaId = this.captchaId;
|
|
287
|
-
|
|
288
|
-
if (this.isReady()) {
|
|
289
|
-
// If hCaptcha runs into error, reset captcha - hCaptcha
|
|
290
|
-
hcaptcha.reset(captchaId);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
if (onError) onError(event);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
isReady () {
|
|
297
|
-
const { isApiReady, isRemoved } = this.state;
|
|
298
|
-
|
|
299
|
-
return isApiReady && !isRemoved;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Cancel any pending async execute() promise
|
|
304
|
-
* Called when the component unmounts, errors occur, resets, etc.
|
|
305
|
-
*/
|
|
306
|
-
_cancelPendingExecute(reason) {
|
|
307
|
-
if (!this._pendingExecute) {
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
const pending = this._pendingExecute;
|
|
312
|
-
this._pendingExecute = null;
|
|
313
|
-
|
|
314
|
-
const error = new Error(reason);
|
|
315
|
-
pending.reject(error);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
handleOpen () {
|
|
319
|
-
if (!this.isReady() || !this.props.onOpen) {
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
this.props.onOpen();
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
handleClose () {
|
|
327
|
-
if (!this.isReady() || !this.props.onClose) {
|
|
328
|
-
return;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
this.props.onClose();
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
handleChallengeExpired () {
|
|
335
|
-
if (!this.isReady() || !this.props.onChalExpired) {
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
this.props.onChalExpired();
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
execute(opts = null) {
|
|
343
|
-
|
|
344
|
-
opts = typeof opts === 'object' ? opts : null;
|
|
345
|
-
|
|
346
|
-
try {
|
|
347
|
-
const hcaptcha = this._hcaptcha;
|
|
348
|
-
const captchaId = this.captchaId;
|
|
349
|
-
|
|
350
|
-
// Is an async execute and there's already 1 pending, cancel the old one.
|
|
351
|
-
if (opts && opts.async && this._pendingExecute) {
|
|
352
|
-
this._cancelPendingExecute('hcaptcha-execute-replaced');
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
if (!this.isReady()) {
|
|
356
|
-
if (opts && opts.async) {
|
|
357
|
-
return new Promise((resolve, reject) => {
|
|
358
|
-
this._pendingExecute = { resolve, reject };
|
|
359
|
-
|
|
360
|
-
this._onReady = (id) => {
|
|
361
|
-
if (!this._pendingExecute) {
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
try {
|
|
366
|
-
const result = hcaptcha.execute(id, opts);
|
|
367
|
-
|
|
368
|
-
if (result && typeof result.then === 'function') {
|
|
369
|
-
result
|
|
370
|
-
.then((val) => {
|
|
371
|
-
this._pendingExecute = null;
|
|
372
|
-
resolve(val);
|
|
373
|
-
})
|
|
374
|
-
.catch((err) => {
|
|
375
|
-
this._pendingExecute = null;
|
|
376
|
-
reject(err);
|
|
377
|
-
});
|
|
378
|
-
} else {
|
|
379
|
-
this._pendingExecute = null;
|
|
380
|
-
reject(new Error('hcaptcha-execute-no-promise'));
|
|
381
|
-
}
|
|
382
|
-
} catch (e) {
|
|
383
|
-
this._pendingExecute = null;
|
|
384
|
-
reject(e);
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
});
|
|
388
|
-
} else {
|
|
389
|
-
// Non-async: don't return a promise.
|
|
390
|
-
this._onReady = (id) => {
|
|
391
|
-
hcaptcha.execute(id, opts);
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
return null;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// hCaptcha is ready, execute directly.
|
|
399
|
-
const result = hcaptcha.execute(captchaId, opts);
|
|
400
|
-
|
|
401
|
-
// If it's async execute, track it.
|
|
402
|
-
if (opts && opts.async && result && typeof result.then === 'function') {
|
|
403
|
-
return new Promise((resolve, reject) => {
|
|
404
|
-
this._pendingExecute = { resolve, reject };
|
|
405
|
-
|
|
406
|
-
result
|
|
407
|
-
.then((val) => {
|
|
408
|
-
this._pendingExecute = null;
|
|
409
|
-
resolve(val);
|
|
410
|
-
})
|
|
411
|
-
.catch((err) => {
|
|
412
|
-
this._pendingExecute = null;
|
|
413
|
-
reject(err);
|
|
414
|
-
});
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
return result;
|
|
419
|
-
} catch (error) {
|
|
420
|
-
if (opts && opts.async) {
|
|
421
|
-
return Promise.reject(error);
|
|
422
|
-
}
|
|
423
|
-
return null;
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
close() {
|
|
428
|
-
const hcaptcha = this._hcaptcha;
|
|
429
|
-
const captchaId = this.captchaId;
|
|
430
|
-
|
|
431
|
-
this._cancelPendingExecute('hcaptcha-closed');
|
|
432
|
-
|
|
433
|
-
if (!this.isReady()) {
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
return hcaptcha.close(captchaId);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
setData (data) {
|
|
441
|
-
const hcaptcha = this._hcaptcha;
|
|
442
|
-
const captchaId = this.captchaId;
|
|
443
|
-
|
|
444
|
-
if (!this.isReady()) {
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if (data && typeof data !== "object") {
|
|
449
|
-
data = null;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
hcaptcha.setData(captchaId, data);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
getResponse() {
|
|
456
|
-
const hcaptcha = this._hcaptcha;
|
|
457
|
-
return hcaptcha.getResponse(this.captchaId);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
getRespKey() {
|
|
461
|
-
const hcaptcha = this._hcaptcha;
|
|
462
|
-
return hcaptcha.getRespKey(this.captchaId)
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
render () {
|
|
466
|
-
const { elementId } = this.state;
|
|
467
|
-
return <div ref={this.ref} id={elementId}></div>;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
export default HCaptcha;
|
package/src/utils.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
function getFrame(element) {
|
|
2
|
-
const doc = (element && element.ownerDocument) || document;
|
|
3
|
-
const win = doc.defaultView || doc.parentWindow || window;
|
|
4
|
-
|
|
5
|
-
return { document: doc, window: win };
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
function getMountElement(element) {
|
|
9
|
-
return element || document.head;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export {
|
|
13
|
-
getFrame,
|
|
14
|
-
getMountElement
|
|
15
|
-
};
|