From 9416a94a2354278f0b6345568c64921e4c02add5 Mon Sep 17 00:00:00 2001 From: Tom Butcher Date: Tue, 1 Sep 2026 12:34:31 +0100 Subject: [PATCH] Refactor database utility functions and enhance audit logging - Removed unnecessary console logging in the `SocketUser` class for cleaner output. - Updated the `distributeNew` function to accept the entire object instead of just the ID, improving flexibility in handling new entries. - Enhanced the `newAuditLog` and `editAuditLog` functions to filter out excluded models and changes, ensuring sensitive data is not logged. - Introduced new utility functions for omitting specific paths and excluded changes from audit logs, enhancing data privacy and integrity. --- src/database/database.js | 24 +++++++---- src/database/utils.js | 88 ++++++++++++++++++++++++++++++++++++---- src/socket/socketuser.js | 1 - 3 files changed, 95 insertions(+), 18 deletions(-) diff --git a/src/database/database.js b/src/database/database.js index c8acb70..3585920 100644 --- a/src/database/database.js +++ b/src/database/database.js @@ -143,7 +143,7 @@ export const listObjects = async ({ sort, order, project, - cached, + cached })}` ); @@ -199,7 +199,7 @@ export const listObjects = async ({ order, project, cached, - length: finalResult.length, + length: finalResult.length })}` ); return finalResult; @@ -221,7 +221,7 @@ export const getObject = async ({ `Getting object: ${formatTraceData({ model, id, - populate, + populate })}` ); @@ -259,7 +259,7 @@ export const getObject = async ({ `Retreived object from database: ${formatTraceData({ model, id, - populate, + populate })}` ); @@ -394,9 +394,15 @@ export const aggregateRollupsHistory = async ({ if (rollup.operation === 'count') { value = matchingObjects.length; } else if (rollup.operation === 'sum') { - value = _.sumBy(matchingObjects, obj => _.get(obj, rollup.property) || 0); + value = _.sumBy( + matchingObjects, + obj => _.get(obj, rollup.property) || 0 + ); } else if (rollup.operation === 'avg') { - const sum = _.sumBy(matchingObjects, obj => _.get(obj, rollup.property) || 0); + const sum = _.sumBy( + matchingObjects, + obj => _.get(obj, rollup.property) || 0 + ); value = matchingObjects.length ? sum / matchingObjects.length : 0; } @@ -486,7 +492,9 @@ export const aggregateRollupsHistory = async ({ logIndex++; } - results.push(snapshotRollups(Array.from(workingObjects.values()), bucketDate)); + results.push( + snapshotRollups(Array.from(workingObjects.values()), bucketDate) + ); } return results.reverse(); @@ -616,7 +624,7 @@ export const newObject = async ({ await newAuditLog(newData, created._id, parentType, owner, ownerType); } - await distributeNew(created._id, parentType); + await distributeNew(created, parentType); await updateObjectCache({ model: model, diff --git a/src/database/utils.js b/src/database/utils.js index a885ccd..927c201 100644 --- a/src/database/utils.js +++ b/src/database/utils.js @@ -11,6 +11,12 @@ const NOTIFICATION_EXCLUDED_MODELS = [ 'userNotifier', 'auditLog' ]; +const AUDIT_EXCLUDED_MODELS = [ + 'notification', + 'userNotifier', + 'marketplaceEvent' +]; +const AUDIT_EXCLUDED_CHANGES = ['state.message']; const SENSITIVE_KEYS = ['secret']; function omitSensitive(obj) { @@ -24,6 +30,58 @@ function omitSensitive(obj) { return result; } +function omitPath(obj, path) { + if (obj == null || typeof obj !== 'object') return obj; + const keys = path.split('.'); + if (keys.length === 1) { + const result = { ...obj }; + delete result[keys[0]]; + return result; + } + const [first, ...rest] = keys; + if ( + obj[first] == null || + typeof obj[first] !== 'object' || + Array.isArray(obj[first]) + ) { + return obj; + } + const nested = obj[first]; + const leafKey = rest[rest.length - 1]; + const result = { ...obj }; + + if (rest.length === 1) { + const nestedKeys = Object.keys(nested); + if (nestedKeys.length === 1 && nestedKeys[0] === leafKey) { + delete result[first]; + } + return result; + } + + const nestedKeys = Object.keys(nested); + if ( + nestedKeys.length > 1 || + (nestedKeys.length === 1 && nestedKeys[0] !== rest[0]) + ) { + return obj; + } + + const updatedNested = omitPath({ ...nested }, rest.join('.')); + if (updatedNested == null || Object.keys(updatedNested).length === 0) { + delete result[first]; + } else { + result[first] = updatedNested; + } + return result; +} + +function omitExcludedChanges(obj) { + if (obj == null || typeof obj !== 'object') return obj; + return AUDIT_EXCLUDED_CHANGES.reduce((acc, path) => omitPath(acc, path), { + ...obj + }); +} + let modelsCache = null; async function getModelEntryByType(parentType) { @@ -391,8 +449,10 @@ function getChangedValues(oldObj, newObj, old = false) { } async function newAuditLog(newValue, parentId, parentType, owner, ownerType) { - // Filter out createdAt and updatedAt from newValue - const filteredNewValue = { ...newValue }; + if (AUDIT_EXCLUDED_MODELS.includes(parentType)) return; + + // Filter out createdAt, updatedAt, and sensitive fields from newValue + const filteredNewValue = omitSensitive({ ...newValue }); delete filteredNewValue.createdAt; delete filteredNewValue.updatedAt; const auditLog = new auditLogModel({ @@ -408,7 +468,7 @@ async function newAuditLog(newValue, parentId, parentType, owner, ownerType) { await auditLog.save(); - await distributeNew(auditLog._id, 'auditLog'); + await distributeNew(auditLog, 'auditLog'); } async function editAuditLog( @@ -422,9 +482,19 @@ async function editAuditLog( if (parentType === 'stockEvent') { return; } + const filteredOldValue = omitExcludedChanges(oldValue); + const filteredNewValue = omitExcludedChanges(newValue); // Get only the changed values - const changedOldValues = getChangedValues(oldValue, newValue, true); - const changedNewValues = getChangedValues(oldValue, newValue, false); + const changedOldValues = getChangedValues( + filteredOldValue, + filteredNewValue, + true + ); + const changedNewValues = getChangedValues( + filteredOldValue, + filteredNewValue, + false + ); // If no values changed, don't create an audit log if ( @@ -448,7 +518,7 @@ async function editAuditLog( await auditLog.save(); - await distributeNew(auditLog._id, 'auditLog'); + await distributeNew(auditLog, 'auditLog'); } async function deleteAuditLog( @@ -471,7 +541,7 @@ async function deleteAuditLog( await auditLog.save(); - await distributeNew(auditLog._id, 'auditLog'); + await distributeNew(auditLog, 'auditLog'); } async function getAuditLogs(idOrIds) { @@ -490,8 +560,8 @@ async function distributeStats(value, type) { await natsServer.publish(`${type}s.stats`, value); } -async function distributeNew(id, type) { - await natsServer.publish(`${type}s.new`, id); +async function distributeNew(value, type) { + await natsServer.publish(`${type}s.new`, value); } async function editNotification( diff --git a/src/socket/socketuser.js b/src/socket/socketuser.js index 840c35c..33c01f0 100644 --- a/src/socket/socketuser.js +++ b/src/socket/socketuser.js @@ -113,7 +113,6 @@ export class SocketUser { logger.info('User authenticated and valid.'); this.user = result.user; - console.log('user', this.user); this.id = this.user._id.toString(); this.authenticated = true; await this.notificationManager.subscribe();