-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathrecaptcha.js
More file actions
119 lines (114 loc) · 3.03 KB
/
recaptcha.js
File metadata and controls
119 lines (114 loc) · 3.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import config from '../config'
import withStyles from './jss'
import { useEffect, useCallback } from 'preact/hooks'
const loadRecaptchaScript = () =>
new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = 'https://www.google.com/recaptcha/api.js?render=explicit'
script.addEventListener('load', () => {
window.grecaptcha.ready(() => resolve(window.grecaptcha))
})
script.addEventListener('error', reject)
document.body.appendChild(script)
})
const recaptchaQueue = []
let recaptchaPromise
let recaptchaId
let recaptchaContainer
const getRecaptchaContainer = () => {
if (recaptchaContainer) {
return recaptchaContainer
}
const container = document.createElement('div')
container.style.display = 'none'
document.body.appendChild(container)
recaptchaContainer = container
return container
}
const handleRecaptchaNext = async () => {
if (recaptchaQueue.length === 0) {
return
}
;(await loadRecaptcha()).execute(recaptchaId)
}
const handleRecaptchaDone = async code => {
;(await loadRecaptcha()).reset(recaptchaId)
const { resolve } = recaptchaQueue.shift()
resolve(code)
handleRecaptchaNext()
}
const handleRecaptchaError = async err => {
;(await loadRecaptcha()).reset(recaptchaId)
const { reject } = recaptchaQueue.shift()
reject(err)
handleRecaptchaNext()
}
const loadRecaptcha = async () => {
recaptchaPromise = recaptchaPromise ?? loadRecaptchaScript()
recaptchaId =
recaptchaId ??
(await recaptchaPromise).render(getRecaptchaContainer(), {
theme: 'dark',
size: 'invisible',
sitekey: config.recaptcha.siteKey,
callback: handleRecaptchaDone,
'error-callback': handleRecaptchaError,
})
return recaptchaPromise
}
const requestRecaptchaCode = () =>
new Promise((resolve, reject) => {
recaptchaQueue.push({ resolve, reject })
handleRecaptchaNext()
})
// exported for legacy class component usage
export { loadRecaptcha, requestRecaptchaCode }
export const RecaptchaLegalNotice = withStyles(
{
root: {
fontSize: '12px',
textAlign: 'center',
},
link: {
display: 'inline',
padding: '0',
},
},
({ classes }) => (
<div className={classes.root}>
This site is protected by reCAPTCHA.
<br />
The Google{' '}
<a
className={classes.link}
href='https://policies.google.com/privacy'
target='_blank'
rel='noopener noreferrer'
>
Privacy Policy
</a>{' '}
and{' '}
<a
className={classes.link}
href='https://policies.google.com/terms'
target='_blank'
rel='noopener noreferrer'
>
Terms of Service
</a>{' '}
apply.
</div>
)
)
export default action => {
const recaptchaEnabled = config.recaptcha?.protectedActions.includes(action)
useEffect(() => {
if (recaptchaEnabled) {
loadRecaptcha()
}
}, [recaptchaEnabled])
const callback = useCallback(requestRecaptchaCode, [])
if (recaptchaEnabled) {
return callback
}
}