2019-05-29 05:21:06 -04:00
|
|
|
const PasswordResetHandler = require('./PasswordResetHandler')
|
|
|
|
const RateLimiter = require('../../infrastructure/RateLimiter')
|
|
|
|
const AuthenticationController = require('../Authentication/AuthenticationController')
|
|
|
|
const UserGetter = require('../User/UserGetter')
|
|
|
|
const UserUpdater = require('../User/UserUpdater')
|
|
|
|
const UserSessionsManager = require('../User/UserSessionsManager')
|
2020-09-28 06:51:57 -04:00
|
|
|
const OError = require('@overleaf/o-error')
|
2021-03-31 05:35:29 -04:00
|
|
|
const EmailsHelper = require('../Helpers/EmailHelper')
|
2020-08-13 09:42:28 -04:00
|
|
|
const { expressify } = require('../../util/promises')
|
|
|
|
|
|
|
|
async function setNewUserPassword(req, res, next) {
|
|
|
|
let user
|
|
|
|
let { passwordResetToken, password } = req.body
|
|
|
|
if (!passwordResetToken || !password) {
|
|
|
|
return res.sendStatus(400)
|
|
|
|
}
|
|
|
|
passwordResetToken = passwordResetToken.trim()
|
|
|
|
delete req.session.resetToken
|
|
|
|
|
|
|
|
const initiatorId = AuthenticationController.getLoggedInUserId(req)
|
|
|
|
// password reset via tokens can be done while logged in, or not
|
|
|
|
const auditLog = {
|
|
|
|
initiatorId,
|
2021-04-27 03:52:58 -04:00
|
|
|
ip: req.ip,
|
2020-08-13 09:42:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const result = await PasswordResetHandler.promises.setNewUserPassword(
|
|
|
|
passwordResetToken,
|
|
|
|
password,
|
|
|
|
auditLog
|
|
|
|
)
|
2021-05-05 09:05:04 -04:00
|
|
|
const { found, reset, userId } = result
|
2020-08-13 09:42:28 -04:00
|
|
|
if (!found) return res.sendStatus(404)
|
|
|
|
if (!reset) return res.sendStatus(500)
|
|
|
|
await UserSessionsManager.promises.revokeAllUserSessions(
|
|
|
|
{ _id: userId },
|
|
|
|
[]
|
|
|
|
)
|
|
|
|
await UserUpdater.promises.removeReconfirmFlag(userId)
|
|
|
|
if (!req.session.doLoginAfterPasswordReset) {
|
|
|
|
return res.sendStatus(200)
|
|
|
|
}
|
|
|
|
user = await UserGetter.promises.getUser(userId)
|
|
|
|
} catch (error) {
|
|
|
|
if (error.name === 'NotFoundError') {
|
|
|
|
return res.sendStatus(404)
|
|
|
|
} else if (error.name === 'InvalidPasswordError') {
|
|
|
|
return res.sendStatus(400)
|
|
|
|
} else {
|
|
|
|
return res.sendStatus(500)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AuthenticationController.finishLogin(user, req, res, next)
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
renderRequestResetForm(req, res) {
|
2019-07-04 08:40:12 -04:00
|
|
|
res.render('user/passwordReset', { title: 'reset_password' })
|
2019-05-29 05:21:06 -04:00
|
|
|
},
|
|
|
|
|
2019-07-04 08:40:12 -04:00
|
|
|
requestReset(req, res, next) {
|
2019-05-29 05:21:06 -04:00
|
|
|
const email = req.body.email.trim().toLowerCase()
|
|
|
|
const opts = {
|
|
|
|
endpointName: 'password_reset_rate_limit',
|
|
|
|
timeInterval: 60,
|
|
|
|
subjectName: req.ip,
|
2021-04-27 03:52:58 -04:00
|
|
|
throttle: 6,
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
2019-06-14 12:31:46 -04:00
|
|
|
RateLimiter.addCount(opts, (err, canContinue) => {
|
2019-07-04 08:40:12 -04:00
|
|
|
if (err != null) {
|
2020-09-28 06:51:57 -04:00
|
|
|
return next(
|
|
|
|
new OError('rate-limit password reset failed').withCause(err)
|
|
|
|
)
|
2019-07-04 08:40:12 -04:00
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
if (!canContinue) {
|
2020-05-06 06:02:16 -04:00
|
|
|
return res.status(429).send({
|
2021-04-27 03:52:58 -04:00
|
|
|
message: req.i18n.translate('rate_limit_hit_wait'),
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
}
|
2019-06-14 12:31:46 -04:00
|
|
|
PasswordResetHandler.generateAndEmailResetToken(email, (err, status) => {
|
2019-05-29 05:21:06 -04:00
|
|
|
if (err != null) {
|
2020-09-28 06:51:57 -04:00
|
|
|
OError.tag(err, 'failed to generate and email password reset token', {
|
2021-04-27 03:52:58 -04:00
|
|
|
email,
|
2020-09-28 06:51:57 -04:00
|
|
|
})
|
|
|
|
next(err)
|
2019-05-29 05:21:06 -04:00
|
|
|
} else if (status === 'primary') {
|
2020-05-06 06:02:16 -04:00
|
|
|
res.status(200).send({
|
2021-04-27 03:52:58 -04:00
|
|
|
message: { text: req.i18n.translate('password_reset_email_sent') },
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
} else if (status === 'secondary') {
|
2020-05-06 06:02:16 -04:00
|
|
|
res.status(404).send({
|
2021-04-27 03:52:58 -04:00
|
|
|
message: req.i18n.translate('secondary_email_password_reset'),
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
} else {
|
2020-05-06 06:02:16 -04:00
|
|
|
res.status(404).send({
|
2021-04-27 03:52:58 -04:00
|
|
|
message: req.i18n.translate('cant_find_email'),
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
|
|
|
renderSetPasswordForm(req, res) {
|
|
|
|
if (req.query.passwordResetToken != null) {
|
|
|
|
req.session.resetToken = req.query.passwordResetToken
|
2021-03-31 05:35:29 -04:00
|
|
|
let emailQuery = ''
|
|
|
|
if (typeof req.query.email === 'string') {
|
|
|
|
const email = EmailsHelper.parseEmail(req.query.email)
|
|
|
|
if (email) {
|
|
|
|
emailQuery = `?email=${encodeURIComponent(email)}`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res.redirect('/user/password/set' + emailQuery)
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|
|
|
|
if (req.session.resetToken == null) {
|
|
|
|
return res.redirect('/user/password/reset')
|
|
|
|
}
|
2019-07-04 08:40:12 -04:00
|
|
|
res.render('user/setPassword', {
|
2019-05-29 05:21:06 -04:00
|
|
|
title: 'set_password',
|
2021-04-27 03:52:58 -04:00
|
|
|
passwordResetToken: req.session.resetToken,
|
2019-05-29 05:21:06 -04:00
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2021-04-27 03:52:58 -04:00
|
|
|
setNewUserPassword: expressify(setNewUserPassword),
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|