UserController.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /* eslint-disable
  2. camelcase,
  3. handle-callback-err,
  4. max-len,
  5. no-unused-vars,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * DS207: Consider shorter variations of null checks
  13. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  14. */
  15. let UserController
  16. const UserHandler = require('./UserHandler')
  17. const UserDeleter = require('./UserDeleter')
  18. const UserGetter = require('./UserGetter')
  19. const { User } = require('../../models/User')
  20. const newsLetterManager = require('../Newsletter/NewsletterManager')
  21. const UserRegistrationHandler = require('./UserRegistrationHandler')
  22. const logger = require('logger-sharelatex')
  23. const metrics = require('metrics-sharelatex')
  24. const Url = require('url')
  25. const AuthenticationManager = require('../Authentication/AuthenticationManager')
  26. const AuthenticationController = require('../Authentication/AuthenticationController')
  27. const UserSessionsManager = require('./UserSessionsManager')
  28. const UserUpdater = require('./UserUpdater')
  29. const SudoModeHandler = require('../SudoMode/SudoModeHandler')
  30. const settings = require('settings-sharelatex')
  31. const Errors = require('../Errors/Errors')
  32. const OError = require('@overleaf/o-error')
  33. const HttpErrors = require('../Errors/HttpErrors')
  34. const EmailHandler = require('../Email/EmailHandler')
  35. module.exports = UserController = {
  36. tryDeleteUser(req, res, next) {
  37. const user_id = AuthenticationController.getLoggedInUserId(req)
  38. const { password } = req.body
  39. logger.log({ user_id }, 'trying to delete user account')
  40. if (password == null || password === '') {
  41. logger.err(
  42. { user_id },
  43. 'no password supplied for attempt to delete account'
  44. )
  45. return res.sendStatus(403)
  46. }
  47. AuthenticationManager.authenticate({ _id: user_id }, password, function(
  48. err,
  49. user
  50. ) {
  51. if (err != null) {
  52. logger.warn(
  53. { user_id },
  54. 'error authenticating during attempt to delete account'
  55. )
  56. return next(err)
  57. }
  58. if (!user) {
  59. logger.err({ user_id }, 'auth failed during attempt to delete account')
  60. return res.sendStatus(403)
  61. }
  62. UserDeleter.deleteUser(
  63. user_id,
  64. { deleterUser: user, ipAddress: req.ip },
  65. function(err) {
  66. if (err) {
  67. let errorData = {
  68. message: 'error while deleting user account',
  69. info: { user_id }
  70. }
  71. if (err instanceof Errors.SubscriptionAdminDeletionError) {
  72. // set info.public.error for JSON response so frontend can display
  73. // a specific message
  74. errorData.info.public = {
  75. error: 'SubscriptionAdminDeletionError'
  76. }
  77. return next(
  78. new HttpErrors.UnprocessableEntityError(errorData).withCause(
  79. err
  80. )
  81. )
  82. } else {
  83. return next(new OError(errorData).withCause(err))
  84. }
  85. }
  86. const sessionId = req.sessionID
  87. if (typeof req.logout === 'function') {
  88. req.logout()
  89. }
  90. req.session.destroy(function(err) {
  91. if (err != null) {
  92. logger.warn({ err }, 'error destorying session')
  93. return next(err)
  94. }
  95. UserSessionsManager.untrackSession(user, sessionId)
  96. return res.sendStatus(200)
  97. })
  98. }
  99. )
  100. })
  101. },
  102. unsubscribe(req, res) {
  103. const user_id = AuthenticationController.getLoggedInUserId(req)
  104. return UserGetter.getUser(user_id, (err, user) =>
  105. newsLetterManager.unsubscribe(user, () => res.send())
  106. )
  107. },
  108. updateUserSettings(req, res) {
  109. const user_id = AuthenticationController.getLoggedInUserId(req)
  110. logger.log({ user_id }, 'updating account settings')
  111. return User.findById(user_id, function(err, user) {
  112. if (err != null || user == null) {
  113. logger.err({ err, user_id }, 'problem updaing user settings')
  114. return res.sendStatus(500)
  115. }
  116. if (req.body.first_name != null) {
  117. user.first_name = req.body.first_name.trim()
  118. }
  119. if (req.body.last_name != null) {
  120. user.last_name = req.body.last_name.trim()
  121. }
  122. if (req.body.role != null) {
  123. user.role = req.body.role.trim()
  124. }
  125. if (req.body.institution != null) {
  126. user.institution = req.body.institution.trim()
  127. }
  128. if (req.body.mode != null) {
  129. user.ace.mode = req.body.mode
  130. }
  131. if (req.body.editorTheme != null) {
  132. user.ace.theme = req.body.editorTheme
  133. }
  134. if (req.body.overallTheme != null) {
  135. user.ace.overallTheme = req.body.overallTheme
  136. }
  137. if (req.body.fontSize != null) {
  138. user.ace.fontSize = req.body.fontSize
  139. }
  140. if (req.body.autoComplete != null) {
  141. user.ace.autoComplete = req.body.autoComplete
  142. }
  143. if (req.body.autoPairDelimiters != null) {
  144. user.ace.autoPairDelimiters = req.body.autoPairDelimiters
  145. }
  146. if (req.body.spellCheckLanguage != null) {
  147. user.ace.spellCheckLanguage = req.body.spellCheckLanguage
  148. }
  149. if (req.body.pdfViewer != null) {
  150. user.ace.pdfViewer = req.body.pdfViewer
  151. }
  152. if (req.body.syntaxValidation != null) {
  153. user.ace.syntaxValidation = req.body.syntaxValidation
  154. }
  155. if (req.body.fontFamily != null) {
  156. user.ace.fontFamily = req.body.fontFamily
  157. }
  158. if (req.body.lineHeight != null) {
  159. user.ace.lineHeight = req.body.lineHeight
  160. }
  161. return user.save(function(err) {
  162. const newEmail =
  163. req.body.email != null
  164. ? req.body.email.trim().toLowerCase()
  165. : undefined
  166. if (
  167. newEmail == null ||
  168. newEmail === user.email ||
  169. req.externalAuthenticationSystemUsed()
  170. ) {
  171. // end here, don't update email
  172. AuthenticationController.setInSessionUser(req, {
  173. first_name: user.first_name,
  174. last_name: user.last_name
  175. })
  176. return res.sendStatus(200)
  177. } else if (newEmail.indexOf('@') === -1) {
  178. // email invalid
  179. return res.sendStatus(400)
  180. } else {
  181. // update the user email
  182. return UserUpdater.changeEmailAddress(user_id, newEmail, function(
  183. err
  184. ) {
  185. if (err != null) {
  186. let message
  187. logger.err(
  188. { err, user_id, newEmail },
  189. 'problem updaing users email address'
  190. )
  191. if (err instanceof Errors.EmailExistsError) {
  192. message = req.i18n.translate('email_already_registered')
  193. } else {
  194. message = req.i18n.translate('problem_changing_email_address')
  195. }
  196. return res.send(500, { message })
  197. }
  198. return User.findById(user_id, function(err, user) {
  199. if (err != null) {
  200. logger.err(
  201. { err, user_id },
  202. 'error getting user for email update'
  203. )
  204. return res.send(500)
  205. }
  206. AuthenticationController.setInSessionUser(req, {
  207. email: user.email,
  208. first_name: user.first_name,
  209. last_name: user.last_name
  210. })
  211. return UserHandler.populateTeamInvites(user, function(err) {
  212. // need to refresh this in the background
  213. if (err != null) {
  214. logger.err({ err }, 'error populateTeamInvites')
  215. }
  216. return res.sendStatus(200)
  217. })
  218. })
  219. })
  220. }
  221. })
  222. })
  223. },
  224. _doLogout(req, cb) {
  225. if (cb == null) {
  226. cb = function(err) {}
  227. }
  228. metrics.inc('user.logout')
  229. const user = AuthenticationController.getSessionUser(req)
  230. logger.log({ user }, 'logging out')
  231. const sessionId = req.sessionID
  232. if (typeof req.logout === 'function') {
  233. req.logout()
  234. } // passport logout
  235. return req.session.destroy(function(err) {
  236. if (err) {
  237. logger.warn({ err }, 'error destorying session')
  238. cb(err)
  239. }
  240. if (user != null) {
  241. UserSessionsManager.untrackSession(user, sessionId)
  242. SudoModeHandler.clearSudoMode(user._id)
  243. }
  244. return cb()
  245. })
  246. },
  247. logout(req, res, next) {
  248. return UserController._doLogout(req, function(err) {
  249. if (err != null) {
  250. return next(err)
  251. }
  252. const redirect_url = '/login'
  253. return res.redirect(redirect_url)
  254. })
  255. },
  256. expireDeletedUser(req, res, next) {
  257. const userId = req.params.userId
  258. UserDeleter.expireDeletedUser(userId, error => {
  259. if (error) {
  260. return next(error)
  261. }
  262. res.sendStatus(204)
  263. })
  264. },
  265. expireDeletedUsersAfterDuration(req, res, next) {
  266. UserDeleter.expireDeletedUsersAfterDuration(error => {
  267. if (error) {
  268. return next(error)
  269. }
  270. res.sendStatus(204)
  271. })
  272. },
  273. register(req, res, next) {
  274. if (next == null) {
  275. next = function(error) {}
  276. }
  277. const { email } = req.body
  278. if (email == null || email === '') {
  279. res.sendStatus(422) // Unprocessable Entity
  280. return
  281. }
  282. return UserRegistrationHandler.registerNewUserAndSendActivationEmail(
  283. email,
  284. function(error, user, setNewPasswordUrl) {
  285. if (error != null) {
  286. return next(error)
  287. }
  288. return res.json({
  289. email: user.email,
  290. setNewPasswordUrl
  291. })
  292. }
  293. )
  294. },
  295. clearSessions(req, res, next) {
  296. if (next == null) {
  297. next = function(error) {}
  298. }
  299. metrics.inc('user.clear-sessions')
  300. const user = AuthenticationController.getSessionUser(req)
  301. logger.log({ user_id: user._id }, 'clearing sessions for user')
  302. return UserSessionsManager.revokeAllUserSessions(
  303. user,
  304. [req.sessionID],
  305. function(err) {
  306. if (err != null) {
  307. return next(err)
  308. }
  309. return res.sendStatus(201)
  310. }
  311. )
  312. },
  313. changePassword(req, res, next) {
  314. metrics.inc('user.password-change')
  315. const internalError = {
  316. message: { type: 'error', text: req.i18n.translate('internal_error') }
  317. }
  318. const user_id = AuthenticationController.getLoggedInUserId(req)
  319. AuthenticationManager.authenticate(
  320. { _id: user_id },
  321. req.body.currentPassword,
  322. (err, user) => {
  323. if (err) {
  324. return res.status(500).json(internalError)
  325. }
  326. if (!user) {
  327. return res.status(400).json({
  328. message: {
  329. type: 'error',
  330. text: 'Your old password is wrong'
  331. }
  332. })
  333. }
  334. if (req.body.newPassword1 !== req.body.newPassword2) {
  335. return res.status(400).json({
  336. message: {
  337. type: 'error',
  338. text: req.i18n.translate('password_change_passwords_do_not_match')
  339. }
  340. })
  341. }
  342. const validationError = AuthenticationManager.validatePassword(
  343. req.body.newPassword1
  344. )
  345. if (validationError != null) {
  346. return res.status(400).json({
  347. message: {
  348. type: 'error',
  349. text: validationError.message
  350. }
  351. })
  352. }
  353. AuthenticationManager.setUserPassword(
  354. user._id,
  355. req.body.newPassword1,
  356. err => {
  357. if (err) {
  358. return res.status(500).json(internalError)
  359. }
  360. // log errors but do not wait for response
  361. EmailHandler.sendEmail(
  362. 'passwordChanged',
  363. { to: user.email },
  364. err => {
  365. if (err) {
  366. logger.warn(err)
  367. }
  368. }
  369. )
  370. UserSessionsManager.revokeAllUserSessions(
  371. user,
  372. [req.sessionID],
  373. err => {
  374. if (err != null) {
  375. return res.status(500).json(internalError)
  376. }
  377. res.json({
  378. message: {
  379. type: 'success',
  380. email: user.email,
  381. text: req.i18n.translate('password_change_successful')
  382. }
  383. })
  384. }
  385. )
  386. }
  387. )
  388. }
  389. )
  390. }
  391. }