UserDeleter.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. const { callbackify } = require('util')
  2. const logger = require('@overleaf/logger')
  3. const moment = require('moment')
  4. const { User } = require('../../models/User')
  5. const { DeletedUser } = require('../../models/DeletedUser')
  6. const { UserAuditLogEntry } = require('../../models/UserAuditLogEntry')
  7. const { Feedback } = require('../../models/Feedback')
  8. const NewsletterManager = require('../Newsletter/NewsletterManager')
  9. const ProjectDeleter = require('../Project/ProjectDeleter')
  10. const SubscriptionHandler = require('../Subscription/SubscriptionHandler')
  11. const SubscriptionUpdater = require('../Subscription/SubscriptionUpdater')
  12. const SubscriptionLocator = require('../Subscription/SubscriptionLocator')
  13. const UserMembershipsHandler = require('../UserMembership/UserMembershipsHandler')
  14. const UserSessionsManager = require('./UserSessionsManager')
  15. const UserAuditLogHandler = require('./UserAuditLogHandler')
  16. const InstitutionsAPI = require('../Institutions/InstitutionsAPI')
  17. const Modules = require('../../infrastructure/Modules')
  18. const Errors = require('../Errors/Errors')
  19. const OnboardingDataCollectionManager = require('../OnboardingDataCollection/OnboardingDataCollectionManager')
  20. const EmailHandler = require('../Email/EmailHandler')
  21. module.exports = {
  22. deleteUser: callbackify(deleteUser),
  23. deleteMongoUser: callbackify(deleteMongoUser),
  24. expireDeletedUser: callbackify(expireDeletedUser),
  25. ensureCanDeleteUser: callbackify(ensureCanDeleteUser),
  26. expireDeletedUsersAfterDuration: callbackify(expireDeletedUsersAfterDuration),
  27. promises: {
  28. deleteUser,
  29. deleteMongoUser,
  30. expireDeletedUser,
  31. ensureCanDeleteUser,
  32. expireDeletedUsersAfterDuration,
  33. },
  34. }
  35. async function deleteUser(userId, options) {
  36. if (!userId) {
  37. logger.warn('user_id is null when trying to delete user')
  38. throw new Error('no user_id')
  39. }
  40. try {
  41. const user = await User.findById(userId).exec()
  42. logger.debug({ user }, 'deleting user')
  43. await ensureCanDeleteUser(user)
  44. await _cleanupUser(user)
  45. await Modules.promises.hooks.fire('deleteUser', userId)
  46. await UserAuditLogHandler.promises.addEntry(
  47. userId,
  48. 'delete-account',
  49. options.deleterUser ? options.deleterUser._id : userId,
  50. options.ipAddress
  51. )
  52. await _createDeletedUser(user, options)
  53. await ProjectDeleter.promises.deleteUsersProjects(user._id)
  54. await _sendDeleteEmail(user)
  55. await deleteMongoUser(user._id)
  56. } catch (error) {
  57. logger.warn({ error, userId }, 'something went wrong deleting the user')
  58. throw error
  59. }
  60. }
  61. /**
  62. * delete a user document only
  63. */
  64. async function deleteMongoUser(userId) {
  65. if (!userId) {
  66. throw new Error('no user_id')
  67. }
  68. await User.deleteOne({ _id: userId }).exec()
  69. }
  70. async function expireDeletedUser(userId) {
  71. await Modules.promises.hooks.fire('expireDeletedUser', userId)
  72. const deletedUser = await DeletedUser.findOne({
  73. 'deleterData.deletedUserId': userId,
  74. }).exec()
  75. await Feedback.deleteMany({ userId }).exec()
  76. await OnboardingDataCollectionManager.deleteOnboardingDataCollection(userId)
  77. deletedUser.user = undefined
  78. deletedUser.deleterData.deleterIpAddress = undefined
  79. await deletedUser.save()
  80. }
  81. async function expireDeletedUsersAfterDuration() {
  82. const DURATION = 90
  83. const deletedUsers = await DeletedUser.find({
  84. 'deleterData.deletedAt': {
  85. $lt: new Date(moment().subtract(DURATION, 'days')),
  86. },
  87. user: {
  88. $ne: null,
  89. },
  90. }).exec()
  91. if (deletedUsers.length === 0) {
  92. return
  93. }
  94. for (let i = 0; i < deletedUsers.length; i++) {
  95. const deletedUserId = deletedUsers[i].deleterData.deletedUserId
  96. await expireDeletedUser(deletedUserId)
  97. await UserAuditLogEntry.deleteMany({ userId: deletedUserId }).exec()
  98. }
  99. }
  100. async function ensureCanDeleteUser(user) {
  101. const subscription =
  102. await SubscriptionLocator.promises.getUsersSubscription(user)
  103. if (subscription) {
  104. throw new Errors.SubscriptionAdminDeletionError({})
  105. }
  106. }
  107. async function _sendDeleteEmail(user) {
  108. const emailOptions = {
  109. to: user.email,
  110. action: 'account deleted',
  111. actionDescribed: 'your Overleaf account was deleted',
  112. }
  113. await EmailHandler.promises.sendEmail('securityAlert', emailOptions)
  114. }
  115. async function _createDeletedUser(user, options) {
  116. await DeletedUser.updateOne(
  117. { 'deleterData.deletedUserId': user._id },
  118. {
  119. user,
  120. deleterData: {
  121. deletedAt: new Date(),
  122. deleterId: options.deleterUser ? options.deleterUser._id : undefined,
  123. deleterIpAddress: options.ipAddress,
  124. deletedUserId: user._id,
  125. deletedUserLastLoggedIn: user.lastLoggedIn,
  126. deletedUserSignUpDate: user.signUpDate,
  127. deletedUserLoginCount: user.loginCount,
  128. deletedUserReferralId: user.referal_id,
  129. deletedUserReferredUsers: user.refered_users,
  130. deletedUserReferredUserCount: user.refered_user_count,
  131. deletedUserOverleafId: user.overleaf ? user.overleaf.id : undefined,
  132. },
  133. },
  134. { upsert: true }
  135. )
  136. }
  137. async function _cleanupUser(user) {
  138. await UserSessionsManager.promises.revokeAllUserSessions(user._id, [])
  139. await NewsletterManager.promises.unsubscribe(user, { delete: true })
  140. await SubscriptionHandler.promises.cancelSubscription(user)
  141. await InstitutionsAPI.promises.deleteAffiliations(user._id)
  142. await SubscriptionUpdater.promises.removeUserFromAllGroups(user._id)
  143. await UserMembershipsHandler.promises.removeUserFromAllEntities(user._id)
  144. }