overleaf/services/web/app/views/user/passwordReset.pug
June Kelly 3288f87dbe [web] Password set/reset: reject current password (redux) (#8956)
* [web] set-password: reject same as current password

* [web] Add 'peek' operation on tokens

This allows us to improve the UX of the reset-password form,
by not invalidating the token in the case where the new
password will be rejected by validation logic.

We give up to three attempts before invalidating the token.

* [web] Add hide-on-error feature to async forms

This allows us to hide the form elements when certain
named error conditions occur.

* [web] reset-password: handle same-password rejection

We also change the implementation to use the new
peekValueFromToken API, and to expire the token explicitely
after it has been used to set the new password.

* [web] Validate OneTimeToken when loading password reset form

* [web] Rate limit GET: /user/password/set

Now that we are peeking at OneTimeToken when accessing this page,
we add rate to the GET request, matching that of the POST request.

* [web] Tidy up pug layout and mongo query for token peeking

Co-authored-by: Mathias Jakobsen <mathias.jakobsen@overleaf.com>
GitOrigin-RevId: 835205cc7c7ebe1209ee8e5b693efeb939a3056a
2022-09-28 08:06:54 +00:00

74 lines
2.2 KiB
Text

extends ../layout-marketing
include ../_mixins/recaptcha
block content
- var showCaptcha = settings.recaptcha && settings.recaptcha.siteKey && !(settings.recaptcha.disabled && settings.recaptcha.disabled.passwordReset)
if showCaptcha
script(type="text/javascript", nonce=scriptNonce, src="https://www.recaptcha.net/recaptcha/api.js?render=explicit")
div(
id="recaptcha"
class="g-recaptcha"
data-sitekey=settings.recaptcha.siteKey
data-size="invisible"
data-badge="inline"
)
main.content.content-alt#main-content
.container
.row
.col-md-6.col-md-offset-3.col-lg-4.col-lg-offset-4
.card
.page-header
h1 #{translate("password_reset")}
.messageArea
form(
data-ol-async-form
name="passwordResetForm"
action="/user/password/reset",
method="POST",
captcha=(showCaptcha ? '' : false),
captcha-action-name=(showCaptcha ? "passwordReset" : false),
)
div(data-ol-not-sent)
+formMessages()
if error
div.alert.alert-danger(
role="alert"
aria-live="assertive"
)
| #{translate(error)}
input(type="hidden", name="_csrf", value=csrfToken)
.form-group
label(for='email') #{translate("please_enter_email")}
input.form-control#email(
aria-label="email"
type='email',
name='email',
placeholder='email@example.com',
required,
autocomplete="username",
autofocus
)
.actions
button.btn.btn-primary(
type='submit',
data-ol-disabled-inflight,
aria-label=translate('request_password_reset_to_reconfirm')
)
span(data-ol-inflight="idle")
| #{translate("request_password_reset")}
span(hidden data-ol-inflight="pending")
| #{translate("requesting_password_reset")}…
div(hidden data-ol-sent)
div.alert.alert-success(
role="alert"
aria-live="polite"
)
span #{translate('password_reset_email_sent')}
.row
.col-md-6.col-md-offset-3.col-lg-4.col-lg-offset-4
if showCaptcha
+recaptchaConditions