| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405 |
- const UserHandler = require('./UserHandler')
- const UserDeleter = require('./UserDeleter')
- const UserGetter = require('./UserGetter')
- const { User } = require('../../models/User')
- const NewsletterManager = require('../Newsletter/NewsletterManager')
- const UserRegistrationHandler = require('./UserRegistrationHandler')
- const logger = require('logger-sharelatex')
- const metrics = require('metrics-sharelatex')
- const AuthenticationManager = require('../Authentication/AuthenticationManager')
- const AuthenticationController = require('../Authentication/AuthenticationController')
- const UserSessionsManager = require('./UserSessionsManager')
- const UserUpdater = require('./UserUpdater')
- const SudoModeHandler = require('../SudoMode/SudoModeHandler')
- const Errors = require('../Errors/Errors')
- const OError = require('@overleaf/o-error')
- const HttpErrors = require('@overleaf/o-error/http')
- const EmailHandler = require('../Email/EmailHandler')
- const UrlHelper = require('../Helpers/UrlHelper')
- const { promisify } = require('util')
- const UserController = {
- tryDeleteUser(req, res, next) {
- const userId = AuthenticationController.getLoggedInUserId(req)
- const { password } = req.body
- if (password == null || password === '') {
- logger.err(
- { userId },
- 'no password supplied for attempt to delete account'
- )
- return res.sendStatus(403)
- }
- AuthenticationManager.authenticate(
- { _id: userId },
- password,
- (err, user) => {
- if (err != null) {
- logger.warn(
- { userId },
- 'error authenticating during attempt to delete account'
- )
- return next(err)
- }
- if (!user) {
- logger.err({ userId }, 'auth failed during attempt to delete account')
- return res.sendStatus(403)
- }
- UserDeleter.deleteUser(
- userId,
- { deleterUser: user, ipAddress: req.ip },
- err => {
- if (err) {
- let errorData = {
- message: 'error while deleting user account',
- info: { userId }
- }
- if (err instanceof Errors.SubscriptionAdminDeletionError) {
- // set info.public.error for JSON response so frontend can display
- // a specific message
- errorData.info.public = {
- error: 'SubscriptionAdminDeletionError'
- }
- return next(
- new HttpErrors.UnprocessableEntityError(errorData).withCause(
- err
- )
- )
- } else {
- return next(new OError(errorData).withCause(err))
- }
- }
- const sessionId = req.sessionID
- if (typeof req.logout === 'function') {
- req.logout()
- }
- req.session.destroy(err => {
- if (err != null) {
- logger.warn({ err }, 'error destorying session')
- return next(err)
- }
- UserSessionsManager.untrackSession(user, sessionId)
- res.sendStatus(200)
- })
- }
- )
- }
- )
- },
- unsubscribe(req, res, next) {
- const userId = AuthenticationController.getLoggedInUserId(req)
- UserGetter.getUser(userId, (err, user) => {
- if (err != null) {
- return next(err)
- }
- NewsletterManager.unsubscribe(user, err => {
- if (err != null) {
- logger.warn(
- { err, user },
- 'Failed to unsubscribe user from newsletter'
- )
- }
- res.send()
- })
- })
- },
- updateUserSettings(req, res, next) {
- const userId = AuthenticationController.getLoggedInUserId(req)
- User.findById(userId, (err, user) => {
- if (err != null || user == null) {
- logger.err({ err, userId }, 'problem updaing user settings')
- return res.sendStatus(500)
- }
- if (req.body.first_name != null) {
- user.first_name = req.body.first_name.trim()
- }
- if (req.body.last_name != null) {
- user.last_name = req.body.last_name.trim()
- }
- if (req.body.role != null) {
- user.role = req.body.role.trim()
- }
- if (req.body.institution != null) {
- user.institution = req.body.institution.trim()
- }
- if (req.body.mode != null) {
- user.ace.mode = req.body.mode
- }
- if (req.body.editorTheme != null) {
- user.ace.theme = req.body.editorTheme
- }
- if (req.body.overallTheme != null) {
- user.ace.overallTheme = req.body.overallTheme
- }
- if (req.body.fontSize != null) {
- user.ace.fontSize = req.body.fontSize
- }
- if (req.body.autoComplete != null) {
- user.ace.autoComplete = req.body.autoComplete
- }
- if (req.body.autoPairDelimiters != null) {
- user.ace.autoPairDelimiters = req.body.autoPairDelimiters
- }
- if (req.body.spellCheckLanguage != null) {
- user.ace.spellCheckLanguage = req.body.spellCheckLanguage
- }
- if (req.body.pdfViewer != null) {
- user.ace.pdfViewer = req.body.pdfViewer
- }
- if (req.body.syntaxValidation != null) {
- user.ace.syntaxValidation = req.body.syntaxValidation
- }
- if (req.body.fontFamily != null) {
- user.ace.fontFamily = req.body.fontFamily
- }
- if (req.body.lineHeight != null) {
- user.ace.lineHeight = req.body.lineHeight
- }
- user.save(err => {
- if (err != null) {
- return next(err)
- }
- const newEmail =
- req.body.email != null
- ? req.body.email.trim().toLowerCase()
- : undefined
- if (
- newEmail == null ||
- newEmail === user.email ||
- req.externalAuthenticationSystemUsed()
- ) {
- // end here, don't update email
- AuthenticationController.setInSessionUser(req, {
- first_name: user.first_name,
- last_name: user.last_name
- })
- res.sendStatus(200)
- } else if (newEmail.indexOf('@') === -1) {
- // email invalid
- res.sendStatus(400)
- } else {
- // update the user email
- UserUpdater.changeEmailAddress(userId, newEmail, err => {
- if (err) {
- let errorData = {
- message: 'problem updaing users email address',
- info: { userId, newEmail, public: {} }
- }
- if (err instanceof Errors.EmailExistsError) {
- errorData.info.public.message = req.i18n.translate(
- 'email_already_registered'
- )
- return next(
- new HttpErrors.ConflictError(errorData).withCause(err)
- )
- } else {
- errorData.info.public.message = req.i18n.translate(
- 'problem_changing_email_address'
- )
- next(
- new HttpErrors.InternalServerError(errorData).withCause(err)
- )
- }
- }
- User.findById(userId, (err, user) => {
- if (err != null) {
- logger.err(
- { err, userId },
- 'error getting user for email update'
- )
- return res.send(500)
- }
- AuthenticationController.setInSessionUser(req, {
- email: user.email,
- first_name: user.first_name,
- last_name: user.last_name
- })
- UserHandler.populateTeamInvites(user, err => {
- // need to refresh this in the background
- if (err != null) {
- logger.err({ err }, 'error populateTeamInvites')
- }
- res.sendStatus(200)
- })
- })
- })
- }
- })
- })
- },
- doLogout(req, cb) {
- metrics.inc('user.logout')
- const user = AuthenticationController.getSessionUser(req)
- logger.log({ user }, 'logging out')
- const sessionId = req.sessionID
- if (typeof req.logout === 'function') {
- req.logout()
- } // passport logout
- req.session.destroy(err => {
- if (err) {
- logger.warn({ err }, 'error destorying session')
- return cb(err)
- }
- if (user != null) {
- UserSessionsManager.untrackSession(user, sessionId)
- SudoModeHandler.clearSudoMode(user._id)
- }
- cb()
- })
- },
- logout(req, res, next) {
- const requestedRedirect = req.body.redirect
- ? UrlHelper.getSafeRedirectPath(req.body.redirect)
- : undefined
- const redirectUrl = requestedRedirect || '/login'
- UserController.doLogout(req, err => {
- if (err != null) {
- return next(err)
- }
- res.redirect(redirectUrl)
- })
- },
- expireDeletedUser(req, res, next) {
- const userId = req.params.userId
- UserDeleter.expireDeletedUser(userId, error => {
- if (error) {
- return next(error)
- }
- res.sendStatus(204)
- })
- },
- expireDeletedUsersAfterDuration(req, res, next) {
- UserDeleter.expireDeletedUsersAfterDuration(error => {
- if (error) {
- return next(error)
- }
- res.sendStatus(204)
- })
- },
- register(req, res, next) {
- const { email } = req.body
- if (email == null || email === '') {
- return res.sendStatus(422) // Unprocessable Entity
- }
- UserRegistrationHandler.registerNewUserAndSendActivationEmail(
- email,
- (error, user, setNewPasswordUrl) => {
- if (error != null) {
- return next(error)
- }
- res.json({
- email: user.email,
- setNewPasswordUrl
- })
- }
- )
- },
- clearSessions(req, res, next) {
- metrics.inc('user.clear-sessions')
- const user = AuthenticationController.getSessionUser(req)
- UserSessionsManager.revokeAllUserSessions(user, [req.sessionID], err => {
- if (err != null) {
- return next(err)
- }
- res.sendStatus(201)
- })
- },
- changePassword(req, res, next) {
- metrics.inc('user.password-change')
- const internalError = {
- message: { type: 'error', text: req.i18n.translate('internal_error') }
- }
- const userId = AuthenticationController.getLoggedInUserId(req)
- AuthenticationManager.authenticate(
- { _id: userId },
- req.body.currentPassword,
- (err, user) => {
- if (err) {
- return res.status(500).json(internalError)
- }
- if (!user) {
- return res.status(400).json({
- message: {
- type: 'error',
- text: 'Your old password is wrong'
- }
- })
- }
- if (req.body.newPassword1 !== req.body.newPassword2) {
- return res.status(400).json({
- message: {
- type: 'error',
- text: req.i18n.translate('password_change_passwords_do_not_match')
- }
- })
- }
- const validationError = AuthenticationManager.validatePassword(
- req.body.newPassword1
- )
- if (validationError != null) {
- return res.status(400).json({
- message: {
- type: 'error',
- text: validationError.message
- }
- })
- }
- AuthenticationManager.setUserPassword(
- user._id,
- req.body.newPassword1,
- err => {
- if (err) {
- return res.status(500).json(internalError)
- }
- // log errors but do not wait for response
- EmailHandler.sendEmail(
- 'passwordChanged',
- { to: user.email },
- err => {
- if (err) {
- logger.warn(err)
- }
- }
- )
- UserSessionsManager.revokeAllUserSessions(
- user,
- [req.sessionID],
- err => {
- if (err != null) {
- return res.status(500).json(internalError)
- }
- res.json({
- message: {
- type: 'success',
- email: user.email,
- text: req.i18n.translate('password_change_successful')
- }
- })
- }
- )
- }
- )
- }
- )
- }
- }
- UserController.promises = {
- doLogout: promisify(UserController.doLogout)
- }
- module.exports = UserController
|