overleaf/services/web/app/src/Features/User/UserAuditLogHandler.js

68 lines
1.6 KiB
JavaScript
Raw Normal View History

const OError = require('@overleaf/o-error')
const { User } = require('../../models/User')
const { callbackify } = require('util')
const MAX_AUDIT_LOG_ENTRIES = 200
function _canHaveNoInitiatorId(operation, info) {
if (operation === 'reset-password') return true
if (operation === 'unlink-sso' && info.providerId === 'collabratec')
return true
}
/**
* Add an audit log entry
*
* The entry should include at least the following fields:
*
* - userId: the user on behalf of whom the operation was performed
* - operation: a string identifying the type of operation
* - initiatorId: who performed the operation
* - ipAddress: the IP address of the initiator
* - info: an object detailing what happened
*/
async function addEntry(userId, operation, initiatorId, ipAddress, info = {}) {
if (!operation || !ipAddress)
throw new OError('missing required audit log data', {
operation,
initiatorId,
ipAddress,
})
if (!initiatorId && !_canHaveNoInitiatorId(operation, info)) {
throw new OError('missing initiatorId for audit log', {
operation,
ipAddress,
})
}
const timestamp = new Date()
const entry = {
operation,
initiatorId,
info,
ipAddress,
timestamp,
}
const result = await User.updateOne(
{ _id: userId },
{
$push: {
auditLog: { $each: [entry], $slice: -MAX_AUDIT_LOG_ENTRIES },
},
}
).exec()
if (result.nModified === 0) {
throw new OError('user not found', { userId })
}
}
const UserAuditLogHandler = {
addEntry: callbackify(addEntry),
promises: {
addEntry,
},
}
module.exports = UserAuditLogHandler