ProjectAuditLogHandler.mjs 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import logger from '@overleaf/logger'
  2. import { ProjectAuditLogEntry } from '../../models/ProjectAuditLogEntry.js'
  3. import { callbackify } from '@overleaf/promise-utils'
  4. import SubscriptionLocator from '../Subscription/SubscriptionLocator.mjs'
  5. const MANAGED_GROUP_PROJECT_EVENTS = ['accept-invite', 'project-created']
  6. export default {
  7. promises: {
  8. addEntry,
  9. addEntryIfManaged,
  10. },
  11. addEntry: callbackify(addEntry),
  12. addEntryIfManaged: callbackify(addEntryIfManaged),
  13. addEntryInBackground,
  14. addEntryIfManagedInBackground,
  15. MANAGED_GROUP_PROJECT_EVENTS,
  16. }
  17. /**
  18. * Add an audit log entry
  19. *
  20. * The entry should include at least the following fields:
  21. *
  22. * - operation: a string identifying the type of operation
  23. * - userId: the user on behalf of whom the operation was performed
  24. * - message: a string detailing what happened
  25. */
  26. async function addEntry(
  27. projectId,
  28. operation,
  29. initiatorId,
  30. ipAddress,
  31. info = {}
  32. ) {
  33. const entry = {
  34. projectId,
  35. operation,
  36. initiatorId,
  37. ipAddress,
  38. info,
  39. }
  40. if (MANAGED_GROUP_PROJECT_EVENTS.includes(operation)) {
  41. const managedSubscription =
  42. await SubscriptionLocator.promises.getUniqueManagedSubscriptionMemberOf(
  43. info.userId || initiatorId
  44. )
  45. if (managedSubscription) {
  46. entry.managedSubscriptionId = managedSubscription._id
  47. }
  48. }
  49. await ProjectAuditLogEntry.create(entry)
  50. }
  51. async function addEntryIfManaged(
  52. projectId,
  53. operation,
  54. initiatorId,
  55. ipAddress,
  56. info = {}
  57. ) {
  58. if (!MANAGED_GROUP_PROJECT_EVENTS.includes(operation)) {
  59. return
  60. }
  61. const managedSubscription =
  62. await SubscriptionLocator.promises.getUniqueManagedSubscriptionMemberOf(
  63. info.userId || initiatorId
  64. )
  65. if (!managedSubscription) {
  66. return
  67. }
  68. const entry = {
  69. projectId,
  70. operation,
  71. initiatorId,
  72. ipAddress,
  73. info,
  74. managedSubscriptionId: managedSubscription._id,
  75. }
  76. await ProjectAuditLogEntry.create(entry)
  77. }
  78. /**
  79. * Add an audit log entry in the background
  80. *
  81. * This function doesn't return a promise. Instead, it catches any error and logs it.
  82. */
  83. function addEntryInBackground(
  84. projectId,
  85. operation,
  86. initiatorId,
  87. ipAddress,
  88. info = {}
  89. ) {
  90. addEntry(projectId, operation, initiatorId, ipAddress, info).catch(err => {
  91. logger.error(
  92. { err, projectId, operation, initiatorId, ipAddress, info },
  93. 'Failed to write audit log'
  94. )
  95. })
  96. }
  97. function addEntryIfManagedInBackground(
  98. projectId,
  99. operation,
  100. initiatorId,
  101. ipAddress,
  102. info = {}
  103. ) {
  104. addEntryIfManaged(projectId, operation, initiatorId, ipAddress, info).catch(
  105. err => {
  106. logger.error(
  107. { err, projectId, operation, initiatorId, ipAddress, info },
  108. 'Failed to write audit log'
  109. )
  110. }
  111. )
  112. }