PasswordResetHandler.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. const settings = require('@overleaf/settings')
  2. const UserAuditLogHandler = require('../User/UserAuditLogHandler')
  3. const UserGetter = require('../User/UserGetter')
  4. const OneTimeTokenHandler = require('../Security/OneTimeTokenHandler')
  5. const EmailHandler = require('../Email/EmailHandler')
  6. const AuthenticationManager = require('../Authentication/AuthenticationManager')
  7. const { callbackify, promisify } = require('util')
  8. const AUDIT_LOG_TOKEN_PREFIX_LENGTH = 10
  9. async function generateAndEmailResetToken(email) {
  10. const user = await UserGetter.promises.getUserByAnyEmail(email)
  11. if (!user) {
  12. return null
  13. }
  14. if (user.email !== email) {
  15. return 'secondary'
  16. }
  17. const data = { user_id: user._id.toString(), email }
  18. const token = await OneTimeTokenHandler.promises.getNewToken('password', data)
  19. const emailOptions = {
  20. to: email,
  21. setNewPasswordUrl: `${
  22. settings.siteUrl
  23. }/user/password/set?passwordResetToken=${token}&email=${encodeURIComponent(
  24. email
  25. )}`,
  26. }
  27. await EmailHandler.promises.sendEmail('passwordResetRequested', emailOptions)
  28. return 'primary'
  29. }
  30. function expirePasswordResetToken(token, callback) {
  31. OneTimeTokenHandler.expireToken('password', token, err => {
  32. return callback(err)
  33. })
  34. }
  35. function getUserForPasswordResetToken(token, callback) {
  36. OneTimeTokenHandler.peekValueFromToken(
  37. 'password',
  38. token,
  39. (err, data, remainingUses) => {
  40. if (err != null) {
  41. if (err.name === 'NotFoundError') {
  42. return callback(null, null)
  43. } else {
  44. return callback(err)
  45. }
  46. }
  47. if (data == null || data.email == null) {
  48. return callback(null, null, remainingUses)
  49. }
  50. UserGetter.getUserByMainEmail(
  51. data.email,
  52. { _id: 1, 'overleaf.id': 1, email: 1 },
  53. (err, user) => {
  54. if (err != null) {
  55. callback(err)
  56. } else if (user == null) {
  57. callback(null, null, 0)
  58. } else if (
  59. data.user_id != null &&
  60. data.user_id === user._id.toString()
  61. ) {
  62. callback(null, user, remainingUses)
  63. } else if (
  64. data.v1_user_id != null &&
  65. user.overleaf != null &&
  66. data.v1_user_id === user.overleaf.id
  67. ) {
  68. callback(null, user, remainingUses)
  69. } else {
  70. callback(null, null, 0)
  71. }
  72. }
  73. )
  74. }
  75. )
  76. }
  77. async function setNewUserPassword(token, password, auditLog) {
  78. const user = await PasswordResetHandler.promises.getUserForPasswordResetToken(
  79. token
  80. )
  81. if (!user) {
  82. return {
  83. found: false,
  84. reset: false,
  85. userId: null,
  86. }
  87. }
  88. await UserAuditLogHandler.promises.addEntry(
  89. user._id,
  90. 'reset-password',
  91. auditLog.initiatorId,
  92. auditLog.ip,
  93. { token: token.substring(0, AUDIT_LOG_TOKEN_PREFIX_LENGTH) }
  94. )
  95. const reset = await AuthenticationManager.promises.setUserPassword(
  96. user,
  97. password
  98. )
  99. await PasswordResetHandler.promises.expirePasswordResetToken(token)
  100. return { found: true, reset, userId: user._id }
  101. }
  102. const PasswordResetHandler = {
  103. generateAndEmailResetToken: callbackify(generateAndEmailResetToken),
  104. setNewUserPassword: callbackify(setNewUserPassword),
  105. getUserForPasswordResetToken,
  106. expirePasswordResetToken,
  107. }
  108. PasswordResetHandler.promises = {
  109. generateAndEmailResetToken,
  110. getUserForPasswordResetToken: promisify(
  111. PasswordResetHandler.getUserForPasswordResetToken
  112. ),
  113. expirePasswordResetToken: promisify(
  114. PasswordResetHandler.expirePasswordResetToken
  115. ),
  116. setNewUserPassword,
  117. }
  118. module.exports = PasswordResetHandler