mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-07 20:31:06 -05:00
Merge pull request #19141 from overleaf/ii-add-email-account-settings
[web] Reset recaptcha every time GitOrigin-RevId: 6db3571ad6dad3611c748a2d92dce47002a16a77
This commit is contained in:
parent
268291b52d
commit
687b56f18e
5 changed files with 62 additions and 14 deletions
|
@ -151,7 +151,7 @@ function AddEmail() {
|
|||
return (
|
||||
<form>
|
||||
<Layout isError={isError} error={error}>
|
||||
<ReCaptcha2 page="addEmail" ref={recaptchaRef} />
|
||||
<ReCaptcha2 page="addEmail" recaptchaRef={recaptchaRef} />
|
||||
<OLCol lg={8}>
|
||||
<Cell>
|
||||
{InputComponent}
|
||||
|
@ -176,7 +176,7 @@ function AddEmail() {
|
|||
return (
|
||||
<form>
|
||||
<Layout isError={isError} error={error}>
|
||||
<ReCaptcha2 page="addEmail" ref={recaptchaRef} />
|
||||
<ReCaptcha2 page="addEmail" recaptchaRef={recaptchaRef} />
|
||||
<OLCol lg={8}>
|
||||
<Cell>
|
||||
{InputComponent}
|
||||
|
|
|
@ -80,7 +80,7 @@ export function AddSecondaryEmailPrompt() {
|
|||
<>
|
||||
<Interstitial showLogo title={t('add_a_recovery_email_address')}>
|
||||
<form className="add-secondary-email" onSubmit={handleSubmit}>
|
||||
<ReCaptcha2 page="addEmail" ref={recaptchaRef} />
|
||||
<ReCaptcha2 page="addEmail" recaptchaRef={recaptchaRef} />
|
||||
<p>{t('keep_your_account_safe_add_another_email')}</p>
|
||||
|
||||
<EmailInput
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
import { forwardRef } from 'react'
|
||||
import ReCAPTCHA from 'react-google-recaptcha'
|
||||
import getMeta from '@/utils/meta'
|
||||
import { ExposedSettings } from '../../../../types/exposed-settings'
|
||||
|
||||
type Page = keyof ExposedSettings['recaptchaDisabled']
|
||||
interface ReCaptcha2Props
|
||||
extends Pick<React.ComponentProps<typeof ReCAPTCHA>, 'onChange'> {
|
||||
page: keyof ExposedSettings['recaptchaDisabled']
|
||||
recaptchaRef: React.LegacyRef<ReCAPTCHA>
|
||||
}
|
||||
|
||||
export const ReCaptcha2 = forwardRef<
|
||||
ReCAPTCHA,
|
||||
{ page: Page; onChange?: (token: string | null) => void }
|
||||
>(function ReCaptcha2({ page: site, onChange }, ref) {
|
||||
export function ReCaptcha2({
|
||||
page: site,
|
||||
onChange,
|
||||
recaptchaRef,
|
||||
}: ReCaptcha2Props) {
|
||||
const { recaptchaSiteKey, recaptchaDisabled } = getMeta('ol-ExposedSettings')
|
||||
|
||||
if (!recaptchaSiteKey) {
|
||||
|
@ -19,11 +23,11 @@ export const ReCaptcha2 = forwardRef<
|
|||
}
|
||||
return (
|
||||
<ReCAPTCHA
|
||||
ref={ref}
|
||||
ref={recaptchaRef}
|
||||
size="invisible"
|
||||
sitekey={recaptchaSiteKey}
|
||||
onChange={onChange}
|
||||
badge="inline"
|
||||
/>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,13 +1,20 @@
|
|||
import { LegacyRef, createRef } from 'react'
|
||||
import { useRef } from 'react'
|
||||
import ReCAPTCHA from 'react-google-recaptcha'
|
||||
|
||||
export const useRecaptcha = () => {
|
||||
const ref: LegacyRef<ReCAPTCHA> = createRef<ReCAPTCHA>()
|
||||
const getReCaptchaToken = async (): Promise<string | null> => {
|
||||
const ref = useRef<ReCAPTCHA | null>(null)
|
||||
|
||||
const getReCaptchaToken = async (): Promise<
|
||||
ReturnType<ReCAPTCHA['executeAsync']>
|
||||
> => {
|
||||
if (!ref.current) {
|
||||
return null
|
||||
}
|
||||
// Reset the reCAPTCHA before each submission.
|
||||
// The reCAPTCHA token is meant to be used once per validation
|
||||
ref.current.reset()
|
||||
return await ref.current.executeAsync()
|
||||
}
|
||||
|
||||
return { ref, getReCaptchaToken }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
import { useRecaptcha } from '@/shared/hooks/use-recaptcha'
|
||||
import * as ReactGoogleRecaptcha from 'react-google-recaptcha'
|
||||
|
||||
const ReCaptcha = () => {
|
||||
const { ref: recaptchaRef, getReCaptchaToken } = useRecaptcha()
|
||||
|
||||
const handleClick = async () => {
|
||||
await getReCaptchaToken()
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ReactGoogleRecaptcha.ReCAPTCHA
|
||||
ref={recaptchaRef}
|
||||
size="invisible"
|
||||
sitekey="123456"
|
||||
badge="inline"
|
||||
/>
|
||||
<button onClick={handleClick}>Click</button>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
describe('useRecaptcha', function () {
|
||||
it('should reset the captcha', function () {
|
||||
cy.spy(ReactGoogleRecaptcha.ReCAPTCHA.prototype, 'reset').as('resetSpy')
|
||||
cy.spy(ReactGoogleRecaptcha.ReCAPTCHA.prototype, 'executeAsync').as(
|
||||
'executeAsyncSpy'
|
||||
)
|
||||
|
||||
cy.mount(<ReCaptcha />)
|
||||
|
||||
cy.findByRole('button', { name: /click/i }).click()
|
||||
cy.get('@resetSpy').should('have.been.calledOnce')
|
||||
cy.get('@executeAsyncSpy').should('have.been.calledOnce')
|
||||
})
|
||||
})
|
Loading…
Reference in a new issue