mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-29 04:03:34 -05:00
Merge pull request #13372 from overleaf/mj-captcha-add-email
[web] Add recaptcha to add-email GitOrigin-RevId: 0540e0dbc3103dcaac87dd7fabeedbc5892c371c
This commit is contained in:
parent
64ca8ce094
commit
af76768eb7
14 changed files with 143 additions and 14 deletions
66
package-lock.json
generated
66
package-lock.json
generated
|
@ -12079,6 +12079,15 @@
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/react-google-recaptcha": {
|
||||||
|
"version": "2.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.5.tgz",
|
||||||
|
"integrity": "sha512-iWTjmVttlNgp0teyh7eBXqNOQzVq2RWNiFROWjraOptRnb1OcHJehQnji0sjqIRAk9K0z8stjyhU+OLpPb0N6w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/react-linkify": {
|
"node_modules/@types/react-linkify": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-linkify/-/react-linkify-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-linkify/-/react-linkify-1.0.0.tgz",
|
||||||
|
@ -32630,6 +32639,18 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-async-script": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"hoist-non-react-statics": "^3.3.0",
|
||||||
|
"prop-types": "^15.5.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-bootstrap": {
|
"node_modules/react-bootstrap": {
|
||||||
"version": "0.33.1",
|
"version": "0.33.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.33.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.33.1.tgz",
|
||||||
|
@ -32802,6 +32823,18 @@
|
||||||
"react": ">=16.13.1"
|
"react": ">=16.13.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-google-recaptcha": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"prop-types": "^15.5.0",
|
||||||
|
"react-async-script": "^1.2.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=16.4.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-i18next": {
|
"node_modules/react-i18next": {
|
||||||
"version": "11.18.6",
|
"version": "11.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz",
|
||||||
|
@ -41330,6 +41363,7 @@
|
||||||
"react-dnd-html5-backend": "^11.1.3",
|
"react-dnd-html5-backend": "^11.1.3",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-error-boundary": "^2.3.1",
|
"react-error-boundary": "^2.3.1",
|
||||||
|
"react-google-recaptcha": "^3.1.0",
|
||||||
"react-i18next": "^11.18.6",
|
"react-i18next": "^11.18.6",
|
||||||
"react-linkify": "^1.0.0-alpha",
|
"react-linkify": "^1.0.0-alpha",
|
||||||
"react-refresh": "^0.14.0",
|
"react-refresh": "^0.14.0",
|
||||||
|
@ -41373,6 +41407,7 @@
|
||||||
"@types/react-bootstrap": "^0.32.29",
|
"@types/react-bootstrap": "^0.32.29",
|
||||||
"@types/react-color": "^3.0.6",
|
"@types/react-color": "^3.0.6",
|
||||||
"@types/react-dom": "^17.0.13",
|
"@types/react-dom": "^17.0.13",
|
||||||
|
"@types/react-google-recaptcha": "^2.1.5",
|
||||||
"@types/react-linkify": "^1.0.0",
|
"@types/react-linkify": "^1.0.0",
|
||||||
"@types/recurly__recurly-js": "^4.22.0",
|
"@types/recurly__recurly-js": "^4.22.0",
|
||||||
"@types/sinon-chai": "^3.2.8",
|
"@types/sinon-chai": "^3.2.8",
|
||||||
|
@ -50187,7 +50222,8 @@
|
||||||
"@types/react-bootstrap": "^0.32.29",
|
"@types/react-bootstrap": "^0.32.29",
|
||||||
"@types/react-color": "^3.0.6",
|
"@types/react-color": "^3.0.6",
|
||||||
"@types/react-dom": "^17.0.13",
|
"@types/react-dom": "^17.0.13",
|
||||||
"@types/react-linkify": "1.0.0",
|
"@types/react-google-recaptcha": "^2.1.5",
|
||||||
|
"@types/react-linkify": "^1.0.0",
|
||||||
"@types/recurly__recurly-js": "^4.22.0",
|
"@types/recurly__recurly-js": "^4.22.0",
|
||||||
"@types/sinon-chai": "^3.2.8",
|
"@types/sinon-chai": "^3.2.8",
|
||||||
"@types/uuid": "^8.3.4",
|
"@types/uuid": "^8.3.4",
|
||||||
|
@ -50353,6 +50389,7 @@
|
||||||
"react-dnd-html5-backend": "^11.1.3",
|
"react-dnd-html5-backend": "^11.1.3",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-error-boundary": "^2.3.1",
|
"react-error-boundary": "^2.3.1",
|
||||||
|
"react-google-recaptcha": "^3.1.0",
|
||||||
"react-i18next": "^11.18.6",
|
"react-i18next": "^11.18.6",
|
||||||
"react-linkify": "^1.0.0-alpha",
|
"react-linkify": "^1.0.0-alpha",
|
||||||
"react-refresh": "^0.14.0",
|
"react-refresh": "^0.14.0",
|
||||||
|
@ -54056,6 +54093,15 @@
|
||||||
"@types/react": "*"
|
"@types/react": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/react-google-recaptcha": {
|
||||||
|
"version": "2.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.5.tgz",
|
||||||
|
"integrity": "sha512-iWTjmVttlNgp0teyh7eBXqNOQzVq2RWNiFROWjraOptRnb1OcHJehQnji0sjqIRAk9K0z8stjyhU+OLpPb0N6w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/react": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/react-linkify": {
|
"@types/react-linkify": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-linkify/-/react-linkify-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-linkify/-/react-linkify-1.0.0.tgz",
|
||||||
|
@ -70114,6 +70160,15 @@
|
||||||
"object-assign": "^4.1.1"
|
"object-assign": "^4.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-async-script": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==",
|
||||||
|
"requires": {
|
||||||
|
"hoist-non-react-statics": "^3.3.0",
|
||||||
|
"prop-types": "^15.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-bootstrap": {
|
"react-bootstrap": {
|
||||||
"version": "0.33.1",
|
"version": "0.33.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.33.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.33.1.tgz",
|
||||||
|
@ -70248,6 +70303,15 @@
|
||||||
"@babel/runtime": "^7.11.2"
|
"@babel/runtime": "^7.11.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-google-recaptcha": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==",
|
||||||
|
"requires": {
|
||||||
|
"prop-types": "^15.5.0",
|
||||||
|
"react-async-script": "^1.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-i18next": {
|
"react-i18next": {
|
||||||
"version": "11.18.6",
|
"version": "11.18.6",
|
||||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz",
|
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz",
|
||||||
|
|
|
@ -393,10 +393,9 @@ module.exports = function (webRouter, privateApiRouter, publicApiRouter) {
|
||||||
emailConfirmationDisabled: Settings.emailConfirmationDisabled,
|
emailConfirmationDisabled: Settings.emailConfirmationDisabled,
|
||||||
maxEntitiesPerProject: Settings.maxEntitiesPerProject,
|
maxEntitiesPerProject: Settings.maxEntitiesPerProject,
|
||||||
maxUploadSize: Settings.maxUploadSize,
|
maxUploadSize: Settings.maxUploadSize,
|
||||||
recaptchaSiteKeyV3:
|
recaptchaSiteKey: Settings.recaptcha?.siteKey,
|
||||||
Settings.recaptcha != null ? Settings.recaptcha.siteKeyV3 : undefined,
|
recaptchaSiteKeyV3: Settings.recaptcha?.siteKeyV3,
|
||||||
recaptchaDisabled:
|
recaptchaDisabled: Settings.recaptcha?.disabled,
|
||||||
Settings.recaptcha != null ? Settings.recaptcha.disabled : undefined,
|
|
||||||
textExtensions: Settings.textExtensions,
|
textExtensions: Settings.textExtensions,
|
||||||
validRootDocExtensions: Settings.validRootDocExtensions,
|
validRootDocExtensions: Settings.validRootDocExtensions,
|
||||||
sentryAllowedOriginRegex: Settings.sentry.allowedOriginRegex,
|
sentryAllowedOriginRegex: Settings.sentry.allowedOriginRegex,
|
||||||
|
|
|
@ -349,6 +349,7 @@ function initialize(webRouter, privateApiRouter, publicApiRouter) {
|
||||||
'/user/emails',
|
'/user/emails',
|
||||||
AuthenticationController.requireLogin(),
|
AuthenticationController.requireLogin(),
|
||||||
RateLimiterMiddleware.rateLimit(rateLimiters.addEmail),
|
RateLimiterMiddleware.rateLimit(rateLimiters.addEmail),
|
||||||
|
CaptchaMiddleware.validateCaptcha('addEmail'),
|
||||||
UserEmailsController.add
|
UserEmailsController.add
|
||||||
)
|
)
|
||||||
webRouter.post(
|
webRouter.post(
|
||||||
|
|
|
@ -642,6 +642,7 @@ module.exports = {
|
||||||
login: true,
|
login: true,
|
||||||
passwordReset: true,
|
passwordReset: true,
|
||||||
register: true,
|
register: true,
|
||||||
|
addEmail: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ import { University } from '../../../../../../types/university'
|
||||||
import { CountryCode } from '../../data/countries-list'
|
import { CountryCode } from '../../data/countries-list'
|
||||||
import { isValidEmail } from '../../../../shared/utils/email'
|
import { isValidEmail } from '../../../../shared/utils/email'
|
||||||
import getMeta from '../../../../utils/meta'
|
import getMeta from '../../../../utils/meta'
|
||||||
|
import { ReCaptcha2 } from '../../../../shared/components/recaptcha-2'
|
||||||
|
import { useRecaptcha } from '../../../../shared/hooks/use-recaptcha'
|
||||||
|
|
||||||
function AddEmail() {
|
function AddEmail() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
@ -40,6 +42,7 @@ function AddEmail() {
|
||||||
} = useUserEmailsContext()
|
} = useUserEmailsContext()
|
||||||
|
|
||||||
const emailAddressLimit = getMeta('ol-emailAddressLimit', 10)
|
const emailAddressLimit = getMeta('ol-emailAddressLimit', 10)
|
||||||
|
const { ref: recaptchaRef, getReCaptchaToken } = useRecaptcha()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setUserEmailsContextLoading(isLoading)
|
setUserEmailsContextLoading(isLoading)
|
||||||
|
@ -84,13 +87,17 @@ function AddEmail() {
|
||||||
}
|
}
|
||||||
|
|
||||||
runAsync(
|
runAsync(
|
||||||
postJSON('/user/emails', {
|
(async () => {
|
||||||
|
const token = await getReCaptchaToken()
|
||||||
|
await postJSON('/user/emails', {
|
||||||
body: {
|
body: {
|
||||||
email: newEmail,
|
email: newEmail,
|
||||||
...knownUniversityData,
|
...knownUniversityData,
|
||||||
...unknownUniversityData,
|
...unknownUniversityData,
|
||||||
|
'g-recaptcha-response': token,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
})()
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
getEmails()
|
getEmails()
|
||||||
|
@ -137,6 +144,7 @@ function AddEmail() {
|
||||||
if (!isValidEmail(newEmail)) {
|
if (!isValidEmail(newEmail)) {
|
||||||
return (
|
return (
|
||||||
<Layout isError={isError} error={error}>
|
<Layout isError={isError} error={error}>
|
||||||
|
<ReCaptcha2 page="addEmail" ref={recaptchaRef} />
|
||||||
<form>
|
<form>
|
||||||
<Col md={8}>
|
<Col md={8}>
|
||||||
<Cell>
|
<Cell>
|
||||||
|
@ -161,6 +169,7 @@ function AddEmail() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout isError={isError} error={error}>
|
<Layout isError={isError} error={error}>
|
||||||
|
<ReCaptcha2 page="addEmail" ref={recaptchaRef} />
|
||||||
<form>
|
<form>
|
||||||
<Col md={8}>
|
<Col md={8}>
|
||||||
<Cell>
|
<Cell>
|
||||||
|
|
|
@ -8,6 +8,10 @@ import ReactDOM from 'react-dom'
|
||||||
import SettingsPageRoot from '../../features/settings/components/root.tsx'
|
import SettingsPageRoot from '../../features/settings/components/root.tsx'
|
||||||
|
|
||||||
const element = document.getElementById('settings-page-root')
|
const element = document.getElementById('settings-page-root')
|
||||||
|
// For react-google-recaptcha
|
||||||
|
window.recaptchaOptions = {
|
||||||
|
enterprise: true,
|
||||||
|
}
|
||||||
if (element) {
|
if (element) {
|
||||||
ReactDOM.render(<SettingsPageRoot />, element)
|
ReactDOM.render(<SettingsPageRoot />, element)
|
||||||
}
|
}
|
||||||
|
|
27
services/web/frontend/js/shared/components/recaptcha-2.tsx
Normal file
27
services/web/frontend/js/shared/components/recaptcha-2.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { forwardRef } from 'react'
|
||||||
|
import ReCAPTCHA from 'react-google-recaptcha'
|
||||||
|
|
||||||
|
const siteKey = window.ExposedSettings.recaptchaSiteKey
|
||||||
|
const recaptchaDisabled = window.ExposedSettings.recaptchaDisabled
|
||||||
|
type Page = keyof typeof recaptchaDisabled
|
||||||
|
|
||||||
|
export const ReCaptcha2 = forwardRef<
|
||||||
|
ReCAPTCHA,
|
||||||
|
{ page: Page; onChange?: (token: string | null) => void }
|
||||||
|
>(function ReCaptcha2({ page: site, onChange }, ref) {
|
||||||
|
if (!siteKey) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
if (site && recaptchaDisabled[site]) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<ReCAPTCHA
|
||||||
|
ref={ref}
|
||||||
|
size="invisible"
|
||||||
|
sitekey={siteKey}
|
||||||
|
onChange={onChange}
|
||||||
|
badge="inline"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
13
services/web/frontend/js/shared/hooks/use-recaptcha.ts
Normal file
13
services/web/frontend/js/shared/hooks/use-recaptcha.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { LegacyRef, createRef } from 'react'
|
||||||
|
import ReCAPTCHA from 'react-google-recaptcha'
|
||||||
|
|
||||||
|
export const useRecaptcha = () => {
|
||||||
|
const ref: LegacyRef<ReCAPTCHA> = createRef<ReCAPTCHA>()
|
||||||
|
const getReCaptchaToken = async (): Promise<string | null> => {
|
||||||
|
if (!ref.current) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return await ref.current.executeAsync()
|
||||||
|
}
|
||||||
|
return { ref, getReCaptchaToken }
|
||||||
|
}
|
|
@ -149,6 +149,7 @@ const initialize = () => {
|
||||||
login: true,
|
login: true,
|
||||||
passwordReset: true,
|
passwordReset: true,
|
||||||
register: true,
|
register: true,
|
||||||
|
addEmail: true,
|
||||||
},
|
},
|
||||||
sentryAllowedOriginRegex: '',
|
sentryAllowedOriginRegex: '',
|
||||||
siteUrl: 'http://localhost',
|
siteUrl: 'http://localhost',
|
||||||
|
|
|
@ -229,6 +229,7 @@
|
||||||
"react-dnd-html5-backend": "^11.1.3",
|
"react-dnd-html5-backend": "^11.1.3",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-error-boundary": "^2.3.1",
|
"react-error-boundary": "^2.3.1",
|
||||||
|
"react-google-recaptcha": "^3.1.0",
|
||||||
"react-i18next": "^11.18.6",
|
"react-i18next": "^11.18.6",
|
||||||
"react-linkify": "^1.0.0-alpha",
|
"react-linkify": "^1.0.0-alpha",
|
||||||
"react-refresh": "^0.14.0",
|
"react-refresh": "^0.14.0",
|
||||||
|
@ -272,6 +273,7 @@
|
||||||
"@types/react-bootstrap": "^0.32.29",
|
"@types/react-bootstrap": "^0.32.29",
|
||||||
"@types/react-color": "^3.0.6",
|
"@types/react-color": "^3.0.6",
|
||||||
"@types/react-dom": "^17.0.13",
|
"@types/react-dom": "^17.0.13",
|
||||||
|
"@types/react-google-recaptcha": "^2.1.5",
|
||||||
"@types/react-linkify": "^1.0.0",
|
"@types/react-linkify": "^1.0.0",
|
||||||
"@types/recurly__recurly-js": "^4.22.0",
|
"@types/recurly__recurly-js": "^4.22.0",
|
||||||
"@types/sinon-chai": "^3.2.8",
|
"@types/sinon-chai": "^3.2.8",
|
||||||
|
|
|
@ -251,6 +251,7 @@ module.exports = {
|
||||||
login: false,
|
login: false,
|
||||||
passwordReset: true,
|
passwordReset: true,
|
||||||
register: true,
|
register: true,
|
||||||
|
addEmail: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -349,7 +349,7 @@ describe('<EmailsSection />', function () {
|
||||||
|
|
||||||
const [[, request]] = fetchMock.calls(/\/user\/emails/)
|
const [[, request]] = fetchMock.calls(/\/user\/emails/)
|
||||||
|
|
||||||
expect(JSON.parse(request?.body?.toString() || '{}')).to.deep.equal({
|
expect(JSON.parse(request?.body?.toString() || '{}')).to.deep.include({
|
||||||
email: userEmailData.email,
|
email: userEmailData.email,
|
||||||
university: {
|
university: {
|
||||||
id: userEmailData.affiliation?.institution.id,
|
id: userEmailData.affiliation?.institution.id,
|
||||||
|
@ -494,7 +494,7 @@ describe('<EmailsSection />', function () {
|
||||||
|
|
||||||
const [[, request]] = fetchMock.calls(/\/user\/emails/)
|
const [[, request]] = fetchMock.calls(/\/user\/emails/)
|
||||||
|
|
||||||
expect(JSON.parse(request?.body?.toString() || '{}')).to.deep.equal({
|
expect(JSON.parse(request?.body?.toString() || '{}')).to.deep.include({
|
||||||
email: userEmailData.email,
|
email: userEmailData.email,
|
||||||
university: {
|
university: {
|
||||||
name: newUniversity,
|
name: newUniversity,
|
||||||
|
|
|
@ -27,8 +27,10 @@ export type ExposedSettings = {
|
||||||
login: boolean
|
login: boolean
|
||||||
passwordReset: boolean
|
passwordReset: boolean
|
||||||
register: boolean
|
register: boolean
|
||||||
|
addEmail: boolean
|
||||||
}
|
}
|
||||||
recaptchaSiteKeyV3?: string
|
recaptchaSiteKeyV3?: string
|
||||||
|
recaptchaSiteKey?: string
|
||||||
samlInitPath?: string
|
samlInitPath?: string
|
||||||
sentryAllowedOriginRegex: string
|
sentryAllowedOriginRegex: string
|
||||||
sentryDsn?: string
|
sentryDsn?: string
|
||||||
|
|
|
@ -35,5 +35,10 @@ declare global {
|
||||||
crypto: {
|
crypto: {
|
||||||
randomUUID: () => string
|
randomUUID: () => string
|
||||||
}
|
}
|
||||||
|
// For react-google-recaptcha
|
||||||
|
recaptchaOptions?: {
|
||||||
|
enterprise?: boolean
|
||||||
|
useRecaptchaNet?: boolean
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue