UserAuditLogHandler.test.mjs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. import { vi, expect } from 'vitest'
  2. import sinon from 'sinon'
  3. import mongodb from 'mongodb-legacy'
  4. import { UserAuditLogEntry } from '../../../../app/src/models/UserAuditLogEntry.mjs'
  5. const { ObjectId } = mongodb
  6. const MODULE_PATH = '../../../../app/src/Features/User/UserAuditLogHandler'
  7. describe('UserAuditLogHandler', function () {
  8. beforeEach(async function (ctx) {
  9. ctx.userId = new ObjectId()
  10. ctx.initiatorId = new ObjectId()
  11. ctx.subscriptionId = new ObjectId()
  12. ctx.action = {
  13. operation: 'clear-sessions',
  14. initiatorId: ctx.initiatorId,
  15. info: {
  16. sessions: [
  17. {
  18. ip_address: '0:0:0:0',
  19. session_created: '2020-07-15T16:07:57.652Z',
  20. },
  21. ],
  22. },
  23. ip: '0:0:0:0',
  24. }
  25. ctx.UserAuditLogEntryMock = sinon.mock(UserAuditLogEntry)
  26. ctx.getUniqueManagedSubscriptionMemberOfMock = sinon.stub().resolves()
  27. vi.doMock(
  28. '../../../../app/src/Features/Subscription/SubscriptionLocator',
  29. () => ({
  30. default: {
  31. promises: {
  32. getUniqueManagedSubscriptionMemberOf:
  33. ctx.getUniqueManagedSubscriptionMemberOfMock,
  34. },
  35. },
  36. })
  37. )
  38. vi.doMock('../../../../app/src/models/UserAuditLogEntry', () => ({
  39. UserAuditLogEntry,
  40. }))
  41. ctx.UserAuditLogHandler = (await import(MODULE_PATH)).default
  42. })
  43. afterEach(function (ctx) {
  44. ctx.UserAuditLogEntryMock.restore()
  45. })
  46. describe('addEntry', function () {
  47. describe('success', function () {
  48. beforeEach(function (ctx) {
  49. ctx.dbUpdate = ctx.UserAuditLogEntryMock.expects('create')
  50. .chain('exec')
  51. .resolves({ modifiedCount: 1 })
  52. })
  53. it('writes a log', async function (ctx) {
  54. await ctx.UserAuditLogHandler.promises.addEntry(
  55. ctx.userId,
  56. ctx.action.operation,
  57. ctx.action.initiatorId,
  58. ctx.action.ip,
  59. ctx.action.info
  60. )
  61. ctx.UserAuditLogEntryMock.verify()
  62. })
  63. it('updates the log for password reset operation without a initiatorId', async function (ctx) {
  64. await ctx.UserAuditLogHandler.promises.addEntry(
  65. ctx.userId,
  66. 'reset-password',
  67. undefined,
  68. ctx.action.ip,
  69. ctx.action.info
  70. )
  71. ctx.UserAuditLogEntryMock.verify()
  72. })
  73. it('updates the log for a email removal via script', async function (ctx) {
  74. await ctx.UserAuditLogHandler.promises.addEntry(
  75. ctx.userId,
  76. 'remove-email',
  77. undefined,
  78. ctx.action.ip,
  79. {
  80. removedEmail: 'foo',
  81. script: true,
  82. }
  83. )
  84. ctx.UserAuditLogEntryMock.verify()
  85. })
  86. it('updates the log when no ip address or initiatorId is specified for a group join event', async function (ctx) {
  87. await ctx.UserAuditLogHandler.promises.addEntry(
  88. ctx.userId,
  89. 'join-group-subscription',
  90. undefined,
  91. undefined,
  92. {
  93. subscriptionId: 'foo',
  94. }
  95. )
  96. ctx.UserAuditLogEntryMock.verify()
  97. })
  98. it('includes managedSubscriptionId for managed group user events ', async function (ctx) {
  99. await ctx.UserAuditLogHandler.promises.addEntry(
  100. ctx.userId,
  101. 'reset-password',
  102. undefined,
  103. ctx.action.ip
  104. )
  105. ctx.UserAuditLogEntryMock.verify()
  106. expect(ctx.getUniqueManagedSubscriptionMemberOfMock).to.have.been.called
  107. })
  108. it('does not includes managedSubscriptionId for events not in the managed group event list', async function (ctx) {
  109. await ctx.UserAuditLogHandler.promises.addEntry(
  110. ctx.userId,
  111. 'foo',
  112. ctx.action.initiatorId,
  113. ctx.action.ip
  114. )
  115. ctx.UserAuditLogEntryMock.verify()
  116. expect(ctx.getUniqueManagedSubscriptionMemberOfMock).not.to.have.been
  117. .called
  118. })
  119. })
  120. describe('errors', function () {
  121. describe('missing parameters', function () {
  122. it('throws an error when no operation', async function (ctx) {
  123. await expect(
  124. ctx.UserAuditLogHandler.promises.addEntry(
  125. ctx.userId,
  126. undefined,
  127. ctx.action.initiatorId,
  128. ctx.action.ip,
  129. ctx.action.info
  130. )
  131. ).to.be.rejected
  132. })
  133. it('throws an error when no IP and not excempt', async function (ctx) {
  134. await expect(
  135. ctx.UserAuditLogHandler.promises.addEntry(
  136. ctx.userId,
  137. ctx.action.operation,
  138. ctx.action.initiatorId,
  139. undefined,
  140. ctx.action.info
  141. )
  142. ).to.be.rejected
  143. })
  144. it('throws an error when no initiatorId and not a password reset operation', async function (ctx) {
  145. await expect(
  146. ctx.UserAuditLogHandler.promises.addEntry(
  147. ctx.userId,
  148. ctx.action.operation,
  149. undefined,
  150. ctx.action.ip,
  151. ctx.action.info
  152. )
  153. ).to.be.rejected
  154. })
  155. it('throws an error when remove-email is not from a script, but has no initiatorId', async function (ctx) {
  156. await expect(
  157. ctx.UserAuditLogHandler.promises.addEntry(
  158. ctx.userId,
  159. 'remove-email',
  160. undefined,
  161. ctx.action.ip,
  162. {
  163. removedEmail: 'foo',
  164. }
  165. )
  166. ).to.be.rejected
  167. })
  168. })
  169. })
  170. })
  171. })