overleaf/services/web/app/src/Features/PasswordReset/PasswordResetController.js

128 lines
3.9 KiB
JavaScript
Raw Normal View History

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')
const OError = require('@overleaf/o-error')
const EmailsHelper = require('../Helpers/EmailHelper')
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,
ip: req.ip,
}
try {
const result = await PasswordResetHandler.promises.setNewUserPassword(
passwordResetToken,
password,
auditLog
)
let { found, reset, userId } = result
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)
}
module.exports = {
renderRequestResetForm(req, res) {
res.render('user/passwordReset', { title: 'reset_password' })
},
requestReset(req, res, next) {
const email = req.body.email.trim().toLowerCase()
const opts = {
endpointName: 'password_reset_rate_limit',
timeInterval: 60,
subjectName: req.ip,
throttle: 6,
}
RateLimiter.addCount(opts, (err, canContinue) => {
if (err != null) {
return next(
new OError('rate-limit password reset failed').withCause(err)
)
}
if (!canContinue) {
return res.status(429).send({
message: req.i18n.translate('rate_limit_hit_wait'),
})
}
PasswordResetHandler.generateAndEmailResetToken(email, (err, status) => {
if (err != null) {
OError.tag(err, 'failed to generate and email password reset token', {
email,
})
next(err)
} else if (status === 'primary') {
res.status(200).send({
message: { text: req.i18n.translate('password_reset_email_sent') },
})
} else if (status === 'secondary') {
res.status(404).send({
message: req.i18n.translate('secondary_email_password_reset'),
})
} else {
res.status(404).send({
message: req.i18n.translate('cant_find_email'),
})
}
})
})
},
renderSetPasswordForm(req, res) {
if (req.query.passwordResetToken != null) {
req.session.resetToken = req.query.passwordResetToken
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)
}
if (req.session.resetToken == null) {
return res.redirect('/user/password/reset')
}
res.render('user/setPassword', {
title: 'set_password',
passwordResetToken: req.session.resetToken,
})
},
setNewUserPassword: expressify(setNewUserPassword),
}