@dynamatix/gb-schemas 0.21.14 → 0.21.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dynamatix/gb-schemas",
3
- "version": "0.21.14",
4
- "description": "All the schemas for gatehouse bank back-end",
3
+ "version": "0.21.16",
4
+ "description": "All the schemas for gatehouse bank back-end.",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -26,7 +26,26 @@ const isObjectIdOrArray = (value) => {
26
26
  return mongoose.isValidObjectId(value);
27
27
  };
28
28
 
29
- // Encrypt an object (excluding _id and ObjectId references)
29
+ // **Deterministic IV Generation (for consistent encryption)**
30
+ const deriveIV = (value) => {
31
+ const hash = crypto.createHash('sha256').update(value.toString()).digest();
32
+ return hash.slice(0, IV_LENGTH); // First 16 bytes as IV
33
+ };
34
+
35
+ // **Encrypt a Single Value Deterministically**
36
+ const encryptValue = (value) => {
37
+ const iv = deriveIV(value); // Same IV for same value (allows searching)
38
+ const cipher = crypto.createCipheriv('aes-256-gcm', SECRET_KEY, iv);
39
+
40
+ let encrypted = cipher.update(JSON.stringify(value), 'utf8', 'hex');
41
+ encrypted += cipher.final('hex');
42
+
43
+ const authTag = cipher.getAuthTag().toString('hex'); // Authentication tag
44
+
45
+ return `${iv.toString('hex')}:${authTag}:${encrypted}`;
46
+ };
47
+
48
+ // **Encrypt an Object (excluding ObjectId references & _id)**
30
49
  export const encryptObject = (obj, collectionName) => {
31
50
  if (EXCLUDED_COLLECTIONS.includes(collectionName) || !obj || typeof obj !== 'object') {
32
51
  return obj;
@@ -35,18 +54,13 @@ export const encryptObject = (obj, collectionName) => {
35
54
  let encryptedObj = {};
36
55
  for (const key in obj) {
37
56
  if (key === '_id' || isObjectIdOrArray(obj[key])) {
38
- encryptedObj[key] = obj[key]; // Skip _id and ObjectIds
57
+ encryptedObj[key] = obj[key]; // Keep _id and ObjectId references unchanged
39
58
  } else {
40
59
  try {
41
- const iv = crypto.randomBytes(IV_LENGTH);
42
- const cipher = crypto.createCipheriv('aes-256-gcm', SECRET_KEY, iv);
43
- let encrypted = cipher.update(JSON.stringify(obj[key]), 'utf8', 'hex');
44
- encrypted += cipher.final('hex');
45
- const authTag = cipher.getAuthTag().toString('hex');
46
- encryptedObj[key] = `${iv.toString('hex')}:${authTag}:${encrypted}`;
60
+ encryptedObj[key] = encryptValue(obj[key]);
47
61
  } catch (error) {
48
- console.error(`Encryption error for key ${key}:`, error);
49
- encryptedObj[key] = obj[key]; // Store original value if encryption fails
62
+ console.error(`Encryption error for key "${key}":`, error);
63
+ encryptedObj[key] = obj[key]; // Fallback to original value
50
64
  }
51
65
  }
52
66
  }
@@ -54,7 +68,7 @@ export const encryptObject = (obj, collectionName) => {
54
68
  return encryptedObj;
55
69
  };
56
70
 
57
- // Decrypt an object (excluding _id and ObjectId references)
71
+ // **Decrypt an Object (excluding ObjectId references & _id)**
58
72
  export const decryptObject = (obj, collectionName) => {
59
73
  if (EXCLUDED_COLLECTIONS.includes(collectionName) || !obj || typeof obj !== 'object') {
60
74
  return obj;
@@ -63,7 +77,7 @@ export const decryptObject = (obj, collectionName) => {
63
77
  let decryptedObj = {};
64
78
  for (const key in obj) {
65
79
  if (key === '_id' || isObjectIdOrArray(obj[key])) {
66
- decryptedObj[key] = obj[key]; // Skip _id and ObjectIds
80
+ decryptedObj[key] = obj[key]; // Keep _id and ObjectId references unchanged
67
81
  } else {
68
82
  try {
69
83
  const [ivHex, authTagHex, encryptedData] = obj[key].split(':');
@@ -75,11 +89,11 @@ export const decryptObject = (obj, collectionName) => {
75
89
  decrypted += decipher.final('utf8');
76
90
  decryptedObj[key] = JSON.parse(decrypted);
77
91
  } catch (error) {
78
- console.error(`Decryption error for key ${key}:`, error);
79
- decryptedObj[key] = obj[key]; // Store original value if decryption fails
92
+ console.error(`Decryption error for key "${key}":`, error);
93
+ decryptedObj[key] = obj[key]; // Fallback to original value
80
94
  }
81
95
  }
82
96
  }
83
97
 
84
98
  return decryptedObj;
85
- };
99
+ };
@@ -7,7 +7,7 @@ dotenv.config();
7
7
  const EXCLUDED_COLLECTIONS = process.env.EXCLUDED_COLLECTIONS?.split(",") || [];
8
8
 
9
9
  export default function mongooseEncryption(schema, options) {
10
- console.log("========MONGOOSE ENCRYPTION IS IN PROGRESS========");
10
+ console.log("========MONGOOSE ENCRYPTION IS IN PROGRESS");
11
11
 
12
12
  const collectionName = options?.collection || schema.options.collection;
13
13
 
@@ -16,74 +16,90 @@ export default function mongooseEncryption(schema, options) {
16
16
  return;
17
17
  }
18
18
 
19
- // ** Encrypt query parameters before execution **
19
+ // Encrypt query parameters before execution
20
20
  schema.pre(['find', 'findOne', 'findById'], function (next) {
21
- const query = this.getQuery();
22
- this.setQuery(encryptObject(query, collectionName));
21
+ this.getQuery(); // Ensure the query is processed
22
+ const encryptedQuery = encryptObject(this.getQuery(), collectionName);
23
+ this.setQuery(encryptedQuery);
23
24
  next();
24
25
  });
25
26
 
26
- // ** Decrypt result after querying **
27
- schema.post(['find', 'findOne', 'findById'], function (docs) {
28
- if (Array.isArray(docs)) {
29
- docs.forEach((doc) => doc && Object.assign(doc, decryptObject(doc.toObject(), collectionName)));
30
- } else if (docs) {
31
- Object.assign(docs, decryptObject(docs.toObject(), collectionName));
32
- }
33
- });
34
27
 
35
- // ** Encrypt before saving (insert, update) **
36
- schema.pre(['save', 'create'], function (next) {
37
- this.set(encryptObject(this.toObject(), collectionName));
28
+ // Encrypt before saving (e.g., insert, update)
29
+ schema.pre(['save','create'], function (next) {
30
+ // Encrypt the document before saving to the database
31
+ this.set(encryptObject(this.toObject(), collectionName)); // Encrypt the document
38
32
  next();
39
33
  });
40
34
 
41
- // ** Encrypt update operations **
42
- schema.pre(['updateOne', 'findOneAndUpdate'], function (next) {
43
- const update = this.getUpdate();
44
- if (update) {
45
- this.setUpdate(encryptObject(update, collectionName));
35
+ // Encrypt before update operations (single or multiple documents)
36
+ schema.pre("update", function (result) {
37
+ if (Array.isArray(result)) {
38
+ result.forEach(doc => doc.set(decryptObject(doc.toObject(), collectionName)));
39
+ } else {
40
+ result.set(encryptObject(result.toObject(), collectionName)); // Decrypt single document
46
41
  }
47
- next();
48
42
  });
49
43
 
50
- // ** Encrypt before bulkWrite operations **
51
- schema.pre("bulkWrite", function (next) {
52
- const operations = this.getUpdate();
53
- if (operations) {
54
- operations.forEach((operation) => {
55
- if (operation.insertOne?.document) {
56
- operation.insertOne.document = encryptObject(operation.insertOne.document, collectionName);
57
- } else if (operation.updateOne?.update) {
58
- operation.updateOne.update = encryptObject(operation.updateOne.update, collectionName);
59
- } else if (operation.updateMany?.update) {
60
- operation.updateMany.update = encryptObject(operation.updateMany.update, collectionName);
61
- }
62
- });
44
+ // Encrypt after updateOne operations
45
+ schema.pre(["updateOne","findOneAndUpdate"], function (result) {
46
+ if (result && result.toObject) {
47
+ result.set(encryptObject(result.toObject(), collectionName)); // Decrypt single document
63
48
  }
49
+ });
50
+
51
+ // Encrypt before bulkWrite operations
52
+ schema.pre("bulkWrite", function (next, operations) {
53
+ operations.forEach(operation => {
54
+ if (operation.insertOne && operation.insertOne.document) {
55
+ operation.insertOne.document = encryptObject(operation.insertOne.document, collectionName);
56
+ } else if (operation.updateOne && operation.updateOne.update) {
57
+ operation.updateOne.update = encryptObject(operation.updateOne.update, collectionName);
58
+ } else if (operation.updateMany && operation.updateMany.update) {
59
+ operation.updateMany.update = encryptObject(operation.updateMany.update, collectionName);
60
+ }
61
+ });
64
62
  next();
65
63
  });
64
+
66
65
 
67
- // ** Decrypt after creating a document **
68
- schema.post("create", function (docs) {
66
+ // Decrypt result after querying
67
+ schema.post(['find', 'findOne', 'findById'], function (docs) {
69
68
  if (Array.isArray(docs)) {
70
- docs.forEach((doc) => Object.assign(doc, decryptObject(doc.toObject(), collectionName)));
69
+ docs.forEach((doc) => doc && doc.set(decryptObject(doc.toObject(), collectionName)));
70
+ } else if (docs) {
71
+ docs.set(decryptObject(docs.toObject(), collectionName));
72
+ }
73
+ });
74
+
75
+ // Decrypt after update operations (single or multiple documents)
76
+ schema.post("update", function (result) {
77
+ if (Array.isArray(result)) {
78
+ result.forEach(doc => doc.set(decryptObject(doc.toObject(), collectionName)));
71
79
  } else {
72
- Object.assign(docs, decryptObject(docs.toObject(), collectionName));
80
+ result.set(decryptObject(result.toObject(), collectionName)); // Decrypt single document
73
81
  }
74
82
  });
75
83
 
76
- // ** Decrypt after update operations **
77
- schema.post(["updateOne", "findOneAndUpdate"], function (result) {
84
+ // Decrypt after updateOne operations
85
+ schema.post("updateOne", function (result) {
78
86
  if (result && result.toObject) {
79
- Object.assign(result, decryptObject(result.toObject(), collectionName));
87
+ result.set(decryptObject(result.toObject(), collectionName)); // Decrypt single document
80
88
  }
81
89
  });
82
90
 
83
- // ** Decrypt after findOneAndUpdate, findOneAndDelete, deleteOne, remove **
84
- schema.post(["findOneAndUpdate", "findOneAndDelete", "deleteOne"], function (doc) {
91
+
92
+ // Decrypt after findOneAndUpdate operations
93
+ schema.post(["findOneAndUpdate","findOneAndDelete","deleteOne","remove"], function (doc) {
85
94
  if (doc) {
86
- Object.assign(doc, decryptObject(doc.toObject(), collectionName));
95
+ doc.set(decryptObject(doc.toObject(), collectionName)); // Decrypt single document
96
+ }
97
+ });
98
+
99
+ // Decrypt after deleteMany operations
100
+ schema.post("deleteMany", function (result) {
101
+ if (Array.isArray(result)) {
102
+ result.forEach(doc => doc.set(decryptObject(doc.toObject(), collectionName))); // Decrypt document fields
87
103
  }
88
104
  });
89
105
  }