@vollcrypt/db-guard 0.1.2 → 0.9.1

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.
@@ -1,24 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.computeBlindIndex = computeBlindIndex;
4
- const security_1 = require("./security");
5
- /**
6
- * Computes a hardened, frequency-resistant blind index for a database field.
7
- *
8
- * Uses HKDF-SHA256 to derive a unique column key from the root salt,
9
- * preventing cross-column frequency analysis. Zeroizes intermediate keys immediately.
10
- */
11
- function computeBlindIndex(value, rootSalt, columnName) {
12
- if (value === null || value === undefined)
13
- return value;
14
- const plaintext = typeof value === 'string' ? value : JSON.stringify(value);
15
- const columnNameBuf = Buffer.from(columnName, 'utf8');
16
- // 1. Derive column-specific key using HKDF-SHA256
17
- const derivedColumnKey = (0, security_1.deriveHkdf)(rootSalt, null, columnNameBuf, 32);
18
- // 2. Compute the final blind index using the derived column key
19
- const plaintextBuf = Buffer.from(plaintext, 'utf8');
20
- const blindIndex = (0, security_1.deriveHkdf)(derivedColumnKey, null, plaintextBuf, 32);
21
- // 3. RAM Security: Zeroize the derived key immediately (Anti-Core Dump)
22
- derivedColumnKey.fill(0);
23
- return blindIndex.toString('hex');
24
- }
3
+ exports.computeBlindIndex = void 0;
4
+ var security_1 = require("./security");
5
+ Object.defineProperty(exports, "computeBlindIndex", { enumerable: true, get: function () { return security_1.computeBlindIndex; } });
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- const prisma_1 = require("./prisma");
4
+ const security_1 = require("./security");
5
5
  function printProgressBar(current, total) {
6
6
  const percentage = Math.min(100, Math.floor((current / total) * 100));
7
7
  const barLength = 40;
@@ -138,7 +138,7 @@ async function migratePostgres(url, table, column, idCol, key, version, chunkSiz
138
138
  // 3. Encrypt and update each row
139
139
  for (const row of batchRes.rows) {
140
140
  const rawVal = row[column];
141
- const encryptedVal = (0, prisma_1.encryptValue)(rawVal, key, version);
141
+ const encryptedVal = (0, security_1.encryptValue)(rawVal, key, version);
142
142
  await client.query(`UPDATE "${table}" SET "${column}" = $1 WHERE "${idCol}" = $2`, [encryptedVal, row[idCol]]);
143
143
  processed++;
144
144
  printProgressBar(processed, total);
@@ -190,7 +190,7 @@ async function migrateMongo(url, collectionName, field, idCol, key, version, chu
190
190
  }
191
191
  for (const doc of batch) {
192
192
  const rawVal = doc[field];
193
- const encryptedVal = (0, prisma_1.encryptValue)(rawVal, key, version);
193
+ const encryptedVal = (0, security_1.encryptValue)(rawVal, key, version);
194
194
  await collection.updateOne({ [idCol]: doc[idCol] }, { $set: { [field]: encryptedVal } });
195
195
  processed++;
196
196
  printProgressBar(processed, total);
package/dist/drivers.js CHANGED
@@ -2,40 +2,52 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.wrapSqliteDatabase = wrapSqliteDatabase;
4
4
  exports.wrapOracleConnection = wrapOracleConnection;
5
- const prisma_js_1 = require("./prisma.js");
6
5
  const security_js_1 = require("./security.js");
7
6
  function getKeys(options) {
8
- let keys;
7
+ let keys = {};
9
8
  let activeVersion;
10
9
  if (Buffer.isBuffer(options.key)) {
11
- keys = { '1': options.key };
10
+ keys = { '1': Buffer.from(options.key) };
12
11
  activeVersion = '1';
13
12
  }
14
13
  else {
15
- keys = options.key;
14
+ for (const [v, k] of Object.entries(options.key)) {
15
+ keys[v] = Buffer.from(k);
16
+ }
16
17
  activeVersion = options.activeKeyVersion || Object.keys(keys)[0];
17
18
  }
18
19
  return { keys, activeVersion };
19
20
  }
21
+ function cleanIdentifier(identifier) {
22
+ if (!identifier)
23
+ return identifier;
24
+ let cleaned = identifier.trim();
25
+ if ((cleaned.startsWith('"') && cleaned.endsWith('"')) ||
26
+ (cleaned.startsWith('`') && cleaned.endsWith('`')) ||
27
+ (cleaned.startsWith('[') && cleaned.endsWith(']'))) {
28
+ cleaned = cleaned.slice(1, -1);
29
+ }
30
+ return cleaned.trim();
31
+ }
20
32
  function getParamColumns(sql) {
21
33
  const sqlClean = sql.replace(/\s+/g, ' ').trim();
22
34
  // Match INSERT INTO table (col1, col2) ...
23
- const insertMatch = sqlClean.match(/INSERT\s+INTO\s+(\w+)\s*\(([^)]+)\)/i);
35
+ const insertMatch = sqlClean.match(/INSERT\s+INTO\s+([a-zA-Z0-9_"`[\]]+)\s*\(([^)]+)\)/i);
24
36
  if (insertMatch) {
25
- const table = insertMatch[1];
26
- const columns = insertMatch[2].split(',').map(c => c.trim());
37
+ const table = cleanIdentifier(insertMatch[1]);
38
+ const columns = insertMatch[2].split(',').map(c => cleanIdentifier(c));
27
39
  return { table, columns };
28
40
  }
29
41
  // Match UPDATE table SET col1 = ?, col2 = ? ...
30
- const updateMatch = sqlClean.match(/UPDATE\s+(\w+)\s+SET\s+([\s\S]+?)(?:\s+WHERE|$)/i);
42
+ const updateMatch = sqlClean.match(/UPDATE\s+([a-zA-Z0-9_"`[\]]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE|$)/i);
31
43
  if (updateMatch) {
32
- const table = updateMatch[1];
44
+ const table = cleanIdentifier(updateMatch[1]);
33
45
  const setParts = updateMatch[2].split(',');
34
46
  const columns = [];
35
47
  for (const part of setParts) {
36
- const match = part.match(/(\w+)\s*=/);
48
+ const match = part.match(/([a-zA-Z0-9_"`[\]]+)\s*=/);
37
49
  if (match) {
38
- columns.push(match[1]);
50
+ columns.push(cleanIdentifier(match[1]));
39
51
  }
40
52
  }
41
53
  return { table, columns };
@@ -53,7 +65,7 @@ function decryptRow(row, table, keys, options) {
53
65
  const val = row[i];
54
66
  if (typeof val === 'string' && val.startsWith('VOLLVALT:')) {
55
67
  try {
56
- cloned[i] = (0, security_js_1.decryptWithSecurity)(val, (v) => (0, prisma_js_1.decryptValue)(v, keys), table, `column_${i}`, undefined, options);
68
+ cloned[i] = (0, security_js_1.decryptWithSecurity)(val, (v) => (0, security_js_1.decryptValue)(v, keys), table, `column_${i}`, undefined, options);
57
69
  }
58
70
  catch {
59
71
  // Keep original on failure
@@ -67,7 +79,7 @@ function decryptRow(row, table, keys, options) {
67
79
  for (const [key, val] of Object.entries(row)) {
68
80
  if (typeof val === 'string' && val.startsWith('VOLLVALT:')) {
69
81
  try {
70
- cloned[key] = (0, security_js_1.decryptWithSecurity)(val, (v) => (0, prisma_js_1.decryptValue)(v, keys), table, key, row.id || row._id, options);
82
+ cloned[key] = (0, security_js_1.decryptWithSecurity)(val, (v) => (0, security_js_1.decryptValue)(v, keys), table, key, row.id || row._id, options);
71
83
  }
72
84
  catch {
73
85
  // Keep original on failure
@@ -96,10 +108,34 @@ function wrapSqliteDatabase(db, options) {
96
108
  const fieldsToEncrypt = options.entities[table] || [];
97
109
  if (fieldsToEncrypt.length === 0)
98
110
  return params;
111
+ // Case 1: single array parameter, e.g., stmt.run([val1, val2])
112
+ if (params.length === 1 && Array.isArray(params[0])) {
113
+ const arrayParams = params[0].map((param, index) => {
114
+ const colName = columns[index];
115
+ if (colName && fieldsToEncrypt.includes(colName)) {
116
+ return (0, security_js_1.encryptValue)(param, activeKey, activeVersion);
117
+ }
118
+ return param;
119
+ });
120
+ return [arrayParams];
121
+ }
122
+ // Case 2: single object parameter for named binds, e.g., stmt.run({ col1: val1 })
123
+ if (params.length === 1 && params[0] && typeof params[0] === 'object' && !Buffer.isBuffer(params[0])) {
124
+ const obj = { ...params[0] };
125
+ for (const [key, val] of Object.entries(obj)) {
126
+ // Strip prefix character (@, :, $) if present
127
+ const cleanKey = key.replace(/^[@:$]/, '');
128
+ if (fieldsToEncrypt.includes(cleanKey)) {
129
+ obj[key] = (0, security_js_1.encryptValue)(val, activeKey, activeVersion);
130
+ }
131
+ }
132
+ return [obj];
133
+ }
134
+ // Case 3: multiple positional parameters, e.g., stmt.run(val1, val2)
99
135
  return params.map((param, index) => {
100
136
  const colName = columns[index];
101
137
  if (colName && fieldsToEncrypt.includes(colName)) {
102
- return (0, prisma_js_1.encryptValue)(param, activeKey, activeVersion);
138
+ return (0, security_js_1.encryptValue)(param, activeKey, activeVersion);
103
139
  }
104
140
  return param;
105
141
  });
@@ -155,7 +191,7 @@ function wrapOracleConnection(connection, options) {
155
191
  processedBinds = bindParams.map((param, index) => {
156
192
  const colName = columns[index];
157
193
  if (colName && fieldsToEncrypt.includes(colName)) {
158
- return (0, prisma_js_1.encryptValue)(param, activeKey, activeVersion);
194
+ return (0, security_js_1.encryptValue)(param, activeKey, activeVersion);
159
195
  }
160
196
  return param;
161
197
  });
@@ -164,7 +200,7 @@ function wrapOracleConnection(connection, options) {
164
200
  processedBinds = { ...bindParams };
165
201
  for (const field of fieldsToEncrypt) {
166
202
  if (processedBinds[field] !== undefined && processedBinds[field] !== null) {
167
- processedBinds[field] = (0, prisma_js_1.encryptValue)(processedBinds[field], activeKey, activeVersion);
203
+ processedBinds[field] = (0, security_js_1.encryptValue)(processedBinds[field], activeKey, activeVersion);
168
204
  }
169
205
  }
170
206
  }
package/dist/drizzle.js CHANGED
@@ -1,26 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createDrizzleGuard = void 0;
4
- const pg_core_1 = require("drizzle-orm/pg-core");
5
- const mysql_core_1 = require("drizzle-orm/mysql-core");
6
- const sqlite_core_1 = require("drizzle-orm/sqlite-core");
7
- const prisma_1 = require("./prisma");
8
- const blind_index_1 = require("./blind-index");
9
4
  const security_1 = require("./security");
10
5
  function getKeys(options) {
11
6
  let keys;
12
7
  let activeVersion;
13
8
  if (Buffer.isBuffer(options.key)) {
14
- keys = { '1': options.key };
9
+ keys = { '1': Buffer.from(options.key) };
15
10
  activeVersion = '1';
16
11
  }
17
12
  else {
18
- keys = options.key;
13
+ keys = {};
14
+ for (const [v, k] of Object.entries(options.key)) {
15
+ keys[v] = Buffer.from(k);
16
+ }
19
17
  activeVersion = options.activeKeyVersion || Object.keys(keys)[0];
20
18
  }
21
19
  return { keys, activeVersion };
22
20
  }
23
21
  const createDrizzleGuard = (options) => {
22
+ const pgCustomType = require('drizzle-orm/pg-core').customType;
23
+ const mysqlCustomType = require('drizzle-orm/mysql-core').customType;
24
+ const sqliteCustomType = require('drizzle-orm/sqlite-core').customType;
24
25
  const { keys, activeVersion } = getKeys(options);
25
26
  const activeKey = keys[activeVersion];
26
27
  if (!activeKey) {
@@ -29,49 +30,49 @@ const createDrizzleGuard = (options) => {
29
30
  (0, security_1.registerKeysForZeroization)(keys);
30
31
  const rootSalt = options.blindIndexes?.rootSalt;
31
32
  return {
32
- pgText: (name, columnPath) => (0, pg_core_1.customType)({
33
+ pgText: (name, columnPath) => pgCustomType({
33
34
  dataType() {
34
35
  return 'text';
35
36
  },
36
37
  toDriver(value) {
37
- return (0, prisma_1.encryptValue)(value, activeKey, activeVersion);
38
+ return (0, security_1.encryptValue)(value, activeKey, activeVersion);
38
39
  },
39
40
  fromDriver(value) {
40
41
  const parts = columnPath?.split('.') || [name];
41
42
  const mName = parts[0] || 'Model';
42
43
  const fName = parts[1] || name;
43
- return (0, security_1.decryptWithSecurity)(value, (val) => (0, prisma_1.decryptValue)(val, keys), mName, fName, undefined, options);
44
+ return (0, security_1.decryptWithSecurity)(value, (val) => (0, security_1.decryptValue)(val, keys), mName, fName, undefined, options);
44
45
  }
45
46
  })(name),
46
- mysqlText: (name, columnPath) => (0, mysql_core_1.customType)({
47
+ mysqlText: (name, columnPath) => mysqlCustomType({
47
48
  dataType() {
48
49
  return 'text';
49
50
  },
50
51
  toDriver(value) {
51
- return (0, prisma_1.encryptValue)(value, activeKey, activeVersion);
52
+ return (0, security_1.encryptValue)(value, activeKey, activeVersion);
52
53
  },
53
54
  fromDriver(value) {
54
55
  const parts = columnPath?.split('.') || [name];
55
56
  const mName = parts[0] || 'Model';
56
57
  const fName = parts[1] || name;
57
- return (0, security_1.decryptWithSecurity)(value, (val) => (0, prisma_1.decryptValue)(val, keys), mName, fName, undefined, options);
58
+ return (0, security_1.decryptWithSecurity)(value, (val) => (0, security_1.decryptValue)(val, keys), mName, fName, undefined, options);
58
59
  }
59
60
  })(name),
60
- sqliteText: (name, columnPath) => (0, sqlite_core_1.customType)({
61
+ sqliteText: (name, columnPath) => sqliteCustomType({
61
62
  dataType() {
62
63
  return 'text';
63
64
  },
64
65
  toDriver(value) {
65
- return (0, prisma_1.encryptValue)(value, activeKey, activeVersion);
66
+ return (0, security_1.encryptValue)(value, activeKey, activeVersion);
66
67
  },
67
68
  fromDriver(value) {
68
69
  const parts = columnPath?.split('.') || [name];
69
70
  const mName = parts[0] || 'Model';
70
71
  const fName = parts[1] || name;
71
- return (0, security_1.decryptWithSecurity)(value, (val) => (0, prisma_1.decryptValue)(val, keys), mName, fName, undefined, options);
72
+ return (0, security_1.decryptWithSecurity)(value, (val) => (0, security_1.decryptValue)(val, keys), mName, fName, undefined, options);
72
73
  }
73
74
  })(name),
74
- pgBlindIndex: (name, columnName) => (0, pg_core_1.customType)({
75
+ pgBlindIndex: (name, columnName) => pgCustomType({
75
76
  dataType() {
76
77
  return 'text';
77
78
  },
@@ -79,13 +80,13 @@ const createDrizzleGuard = (options) => {
79
80
  if (!rootSalt) {
80
81
  throw new Error('Blind index root salt is not configured in Drizzle guard options.');
81
82
  }
82
- return (0, blind_index_1.computeBlindIndex)(value, rootSalt, columnName);
83
+ return (0, security_1.computeBlindIndex)(value, rootSalt, columnName);
83
84
  },
84
85
  fromDriver(value) {
85
86
  return value;
86
87
  }
87
88
  })(name),
88
- mysqlBlindIndex: (name, columnName) => (0, mysql_core_1.customType)({
89
+ mysqlBlindIndex: (name, columnName) => mysqlCustomType({
89
90
  dataType() {
90
91
  return 'text';
91
92
  },
@@ -93,13 +94,13 @@ const createDrizzleGuard = (options) => {
93
94
  if (!rootSalt) {
94
95
  throw new Error('Blind index root salt is not configured in Drizzle guard options.');
95
96
  }
96
- return (0, blind_index_1.computeBlindIndex)(value, rootSalt, columnName);
97
+ return (0, security_1.computeBlindIndex)(value, rootSalt, columnName);
97
98
  },
98
99
  fromDriver(value) {
99
100
  return value;
100
101
  }
101
102
  })(name),
102
- sqliteBlindIndex: (name, columnName) => (0, sqlite_core_1.customType)({
103
+ sqliteBlindIndex: (name, columnName) => sqliteCustomType({
103
104
  dataType() {
104
105
  return 'text';
105
106
  },
@@ -107,7 +108,7 @@ const createDrizzleGuard = (options) => {
107
108
  if (!rootSalt) {
108
109
  throw new Error('Blind index root salt is not configured in Drizzle guard options.');
109
110
  }
110
- return (0, blind_index_1.computeBlindIndex)(value, rootSalt, columnName);
111
+ return (0, security_1.computeBlindIndex)(value, rootSalt, columnName);
111
112
  },
112
113
  fromDriver(value) {
113
114
  return value;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,5 @@
1
- export { prismaDbGuard, PrismaDbGuardOptions, encryptValue, decryptValue, resolveKeys } from './prisma';
2
- export { mongooseDbGuard, MongooseDbGuardOptions } from './mongoose';
3
- export { createDrizzleGuard } from './drizzle';
4
- export { createTypeOrmSubscriber } from './typeorm';
5
1
  export { wrapSqliteDatabase, wrapOracleConnection, DbGuardDriverOptions } from './drivers';
6
- export { KmsProvider, AwsKmsProvider, GcpKmsProvider, VaultKmsProvider, unwrapDekLocal, Pkcs11KmsProvider } from './kms';
2
+ export { KmsProvider, AwsKmsProvider, GcpKmsProvider, VaultKmsProvider, unwrapDekLocal, Pkcs11KmsProvider, resolveKeys, DbGuardKeysOptions } from './kms';
7
3
  export { computeBlindIndex } from './blind-index';
8
- export { dbGuardContextStore, configureAuditLogger, decryptWithSecurity, checkRateLimit, checkPageSize, resetFailClosedStatusForTesting, resetAuditLoggerForTesting, getCachedKey, setCachedKey, resetSecureKeyCacheForTesting, configureBreakGlass, deactivateBreakGlass, isBreakGlassActive, getBreakGlassKey, activateBreakGlass, parseCiphertext, CRYPTO_ALGORITHMS, VERSION_ALGORITHMS, maskValue } from './security';
4
+ export { dbGuardContextStore, configureAuditLogger, decryptWithSecurity, checkRateLimit, checkPageSize, resetFailClosedStatusForTesting, resetAuditLoggerForTesting, getCachedKey, setCachedKey, resetSecureKeyCacheForTesting, configureBreakGlass, deactivateBreakGlass, isBreakGlassActive, getBreakGlassKey, activateBreakGlass, parseCiphertext, CRYPTO_ALGORITHMS, VERSION_ALGORITHMS, maskValue, encryptValue, decryptValue } from './security';
9
5
  export { auditConfiguration, generateComplianceHtmlReport, ComplianceAuditInput, ComplianceScorecard } from './compliance';
package/dist/index.js CHANGED
@@ -1,17 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateComplianceHtmlReport = exports.auditConfiguration = exports.maskValue = exports.VERSION_ALGORITHMS = exports.CRYPTO_ALGORITHMS = exports.parseCiphertext = exports.activateBreakGlass = exports.getBreakGlassKey = exports.isBreakGlassActive = exports.deactivateBreakGlass = exports.configureBreakGlass = exports.resetSecureKeyCacheForTesting = exports.setCachedKey = exports.getCachedKey = exports.resetAuditLoggerForTesting = exports.resetFailClosedStatusForTesting = exports.checkPageSize = exports.checkRateLimit = exports.decryptWithSecurity = exports.configureAuditLogger = exports.dbGuardContextStore = exports.computeBlindIndex = exports.Pkcs11KmsProvider = exports.unwrapDekLocal = exports.VaultKmsProvider = exports.GcpKmsProvider = exports.AwsKmsProvider = exports.wrapOracleConnection = exports.wrapSqliteDatabase = exports.createTypeOrmSubscriber = exports.createDrizzleGuard = exports.mongooseDbGuard = exports.resolveKeys = exports.decryptValue = exports.encryptValue = exports.prismaDbGuard = void 0;
4
- var prisma_1 = require("./prisma");
5
- Object.defineProperty(exports, "prismaDbGuard", { enumerable: true, get: function () { return prisma_1.prismaDbGuard; } });
6
- Object.defineProperty(exports, "encryptValue", { enumerable: true, get: function () { return prisma_1.encryptValue; } });
7
- Object.defineProperty(exports, "decryptValue", { enumerable: true, get: function () { return prisma_1.decryptValue; } });
8
- Object.defineProperty(exports, "resolveKeys", { enumerable: true, get: function () { return prisma_1.resolveKeys; } });
9
- var mongoose_1 = require("./mongoose");
10
- Object.defineProperty(exports, "mongooseDbGuard", { enumerable: true, get: function () { return mongoose_1.mongooseDbGuard; } });
11
- var drizzle_1 = require("./drizzle");
12
- Object.defineProperty(exports, "createDrizzleGuard", { enumerable: true, get: function () { return drizzle_1.createDrizzleGuard; } });
13
- var typeorm_1 = require("./typeorm");
14
- Object.defineProperty(exports, "createTypeOrmSubscriber", { enumerable: true, get: function () { return typeorm_1.createTypeOrmSubscriber; } });
3
+ exports.generateComplianceHtmlReport = exports.auditConfiguration = exports.decryptValue = exports.encryptValue = exports.maskValue = exports.VERSION_ALGORITHMS = exports.CRYPTO_ALGORITHMS = exports.parseCiphertext = exports.activateBreakGlass = exports.getBreakGlassKey = exports.isBreakGlassActive = exports.deactivateBreakGlass = exports.configureBreakGlass = exports.resetSecureKeyCacheForTesting = exports.setCachedKey = exports.getCachedKey = exports.resetAuditLoggerForTesting = exports.resetFailClosedStatusForTesting = exports.checkPageSize = exports.checkRateLimit = exports.decryptWithSecurity = exports.configureAuditLogger = exports.dbGuardContextStore = exports.computeBlindIndex = exports.resolveKeys = exports.Pkcs11KmsProvider = exports.unwrapDekLocal = exports.VaultKmsProvider = exports.GcpKmsProvider = exports.AwsKmsProvider = exports.wrapOracleConnection = exports.wrapSqliteDatabase = void 0;
15
4
  var drivers_1 = require("./drivers");
16
5
  Object.defineProperty(exports, "wrapSqliteDatabase", { enumerable: true, get: function () { return drivers_1.wrapSqliteDatabase; } });
17
6
  Object.defineProperty(exports, "wrapOracleConnection", { enumerable: true, get: function () { return drivers_1.wrapOracleConnection; } });
@@ -21,6 +10,7 @@ Object.defineProperty(exports, "GcpKmsProvider", { enumerable: true, get: functi
21
10
  Object.defineProperty(exports, "VaultKmsProvider", { enumerable: true, get: function () { return kms_1.VaultKmsProvider; } });
22
11
  Object.defineProperty(exports, "unwrapDekLocal", { enumerable: true, get: function () { return kms_1.unwrapDekLocal; } });
23
12
  Object.defineProperty(exports, "Pkcs11KmsProvider", { enumerable: true, get: function () { return kms_1.Pkcs11KmsProvider; } });
13
+ Object.defineProperty(exports, "resolveKeys", { enumerable: true, get: function () { return kms_1.resolveKeys; } });
24
14
  var blind_index_1 = require("./blind-index");
25
15
  Object.defineProperty(exports, "computeBlindIndex", { enumerable: true, get: function () { return blind_index_1.computeBlindIndex; } });
26
16
  var security_1 = require("./security");
@@ -43,6 +33,8 @@ Object.defineProperty(exports, "parseCiphertext", { enumerable: true, get: funct
43
33
  Object.defineProperty(exports, "CRYPTO_ALGORITHMS", { enumerable: true, get: function () { return security_1.CRYPTO_ALGORITHMS; } });
44
34
  Object.defineProperty(exports, "VERSION_ALGORITHMS", { enumerable: true, get: function () { return security_1.VERSION_ALGORITHMS; } });
45
35
  Object.defineProperty(exports, "maskValue", { enumerable: true, get: function () { return security_1.maskValue; } });
36
+ Object.defineProperty(exports, "encryptValue", { enumerable: true, get: function () { return security_1.encryptValue; } });
37
+ Object.defineProperty(exports, "decryptValue", { enumerable: true, get: function () { return security_1.decryptValue; } });
46
38
  var compliance_1 = require("./compliance");
47
39
  Object.defineProperty(exports, "auditConfiguration", { enumerable: true, get: function () { return compliance_1.auditConfiguration; } });
48
40
  Object.defineProperty(exports, "generateComplianceHtmlReport", { enumerable: true, get: function () { return compliance_1.generateComplianceHtmlReport; } });
package/dist/kms.d.ts CHANGED
@@ -44,3 +44,13 @@ export declare class Pkcs11KmsProvider implements KmsProvider {
44
44
  });
45
45
  decrypt(ciphertext: Buffer): Promise<Buffer>;
46
46
  }
47
+ export interface DbGuardKeysOptions {
48
+ key?: Buffer | Record<string, Buffer>;
49
+ kms?: {
50
+ provider: KmsProvider;
51
+ wrappedKey: Buffer | Record<string, Buffer>;
52
+ wrappedKek?: Buffer | Record<string, Buffer>;
53
+ activeKeyVersion?: string;
54
+ };
55
+ }
56
+ export declare function resolveKeys(options: DbGuardKeysOptions): Promise<Record<string, Buffer>>;
package/dist/kms.js CHANGED
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Pkcs11KmsProvider = exports.VaultKmsProvider = exports.GcpKmsProvider = exports.AwsKmsProvider = void 0;
4
4
  exports.unwrapDekLocal = unwrapDekLocal;
5
+ exports.resolveKeys = resolveKeys;
5
6
  const security_1 = require("./security");
6
7
  class AwsKmsProvider {
7
8
  config;
@@ -106,7 +107,14 @@ class Pkcs11KmsProvider {
106
107
  const pkcs11js = require('pkcs11js');
107
108
  const pkcs11 = new pkcs11js.PKCS11();
108
109
  pkcs11.load(this.config.libraryPath);
109
- pkcs11.C_Initialize();
110
+ try {
111
+ pkcs11.C_Initialize();
112
+ }
113
+ catch (e) {
114
+ if (!e.message?.includes('CRYPTOKI_ALREADY_INITIALIZED') && e.code !== 0x00000191 && e.code !== 401) {
115
+ throw e;
116
+ }
117
+ }
110
118
  const slots = pkcs11.C_GetSlotList(true);
111
119
  const slotIndex = this.config.slotId !== undefined ? this.config.slotId : 0;
112
120
  if (!slots || slots.length <= slotIndex) {
@@ -143,7 +151,6 @@ class Pkcs11KmsProvider {
143
151
  finally {
144
152
  pkcs11.C_Logout(session);
145
153
  pkcs11.C_CloseSession(session);
146
- pkcs11.C_Finalize();
147
154
  }
148
155
  }
149
156
  catch (err) {
@@ -152,3 +159,52 @@ class Pkcs11KmsProvider {
152
159
  }
153
160
  }
154
161
  exports.Pkcs11KmsProvider = Pkcs11KmsProvider;
162
+ async function resolveKeys(options) {
163
+ let rawKeys = {};
164
+ if (options.key) {
165
+ if (Buffer.isBuffer(options.key)) {
166
+ rawKeys = { '1': options.key };
167
+ }
168
+ else {
169
+ rawKeys = { ...options.key };
170
+ }
171
+ }
172
+ else if (options.kms) {
173
+ const { provider, wrappedKey, wrappedKek } = options.kms;
174
+ if (Buffer.isBuffer(wrappedKey)) {
175
+ if (wrappedKek && Buffer.isBuffer(wrappedKek)) {
176
+ const unwrappedKek = await provider.decrypt(wrappedKek);
177
+ const dek = unwrapDekLocal(wrappedKey, unwrappedKek);
178
+ unwrappedKek.fill(0); // RAM Security: zeroize KEK immediately
179
+ rawKeys = { '1': dek };
180
+ }
181
+ else {
182
+ const key = await provider.decrypt(wrappedKey);
183
+ rawKeys = { '1': key };
184
+ }
185
+ }
186
+ else {
187
+ for (const [ver, wrapped] of Object.entries(wrappedKey)) {
188
+ if (wrappedKek) {
189
+ const wKek = Buffer.isBuffer(wrappedKek) ? wrappedKek : wrappedKek[ver];
190
+ if (wKek) {
191
+ const unwrappedKek = await provider.decrypt(wKek);
192
+ const dek = unwrapDekLocal(wrapped, unwrappedKek);
193
+ unwrappedKek.fill(0); // RAM Security: zeroize KEK immediately
194
+ rawKeys[ver] = dek;
195
+ }
196
+ else {
197
+ rawKeys[ver] = await provider.decrypt(wrapped);
198
+ }
199
+ }
200
+ else {
201
+ rawKeys[ver] = await provider.decrypt(wrapped);
202
+ }
203
+ }
204
+ }
205
+ }
206
+ else {
207
+ throw new Error("Either 'key' or 'kms' configuration must be provided.");
208
+ }
209
+ return rawKeys;
210
+ }
@@ -1,4 +1,4 @@
1
- import { Schema } from 'mongoose';
1
+ import type { Schema } from 'mongoose';
2
2
  import { RateLimiterOptions } from './security';
3
3
  export interface MongooseDbGuardOptions {
4
4
  key: Buffer | Record<string, Buffer>;
package/dist/mongoose.js CHANGED
@@ -1,19 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.mongooseDbGuard = mongooseDbGuard;
4
- const prisma_1 = require("./prisma");
5
- const blind_index_1 = require("./blind-index");
4
+ const kms_1 = require("./kms");
6
5
  const security_1 = require("./security");
7
6
  function mongooseDbGuard(schema, options) {
8
7
  const { fields } = options;
9
- let keys;
8
+ let keys = {};
10
9
  let activeVersion;
11
10
  if (Buffer.isBuffer(options.key)) {
12
- keys = { '1': options.key };
11
+ keys = { '1': Buffer.from(options.key) };
13
12
  activeVersion = '1';
14
13
  }
15
14
  else {
16
- keys = options.key;
15
+ for (const [v, k] of Object.entries(options.key)) {
16
+ keys[v] = Buffer.from(k);
17
+ }
17
18
  activeVersion = options.activeKeyVersion || Object.keys(keys)[0];
18
19
  }
19
20
  (0, security_1.registerKeysForZeroization)(keys);
@@ -28,11 +29,15 @@ function mongooseDbGuard(schema, options) {
28
29
  return { keys: { '1': bgKey }, activeKey: bgKey, activeVersion: '1' };
29
30
  }
30
31
  }
31
- if (!tenantId || !options.multiTenant) {
32
+ if (options.multiTenant && !tenantId) {
33
+ throw new Error("Vollcrypt Security: tenantId must be provided in multi-tenant mode.");
34
+ }
35
+ if (!options.multiTenant) {
32
36
  return { keys, activeKey, activeVersion };
33
37
  }
38
+ const tId = tenantId;
34
39
  // Check Secure TTL Cache
35
- const cachedActiveKey = (0, security_1.getCachedKey)(tenantId, activeVersion);
40
+ const cachedActiveKey = (0, security_1.getCachedKey)(tId, activeVersion);
36
41
  if (cachedActiveKey) {
37
42
  return { keys: { [activeVersion]: cachedActiveKey }, activeKey: cachedActiveKey, activeVersion };
38
43
  }
@@ -44,27 +49,31 @@ function mongooseDbGuard(schema, options) {
44
49
  }
45
50
  let tenantConfig;
46
51
  if (multiTenant.tenants) {
47
- tenantConfig = multiTenant.tenants[tenantId];
52
+ tenantConfig = multiTenant.tenants[tId];
48
53
  }
49
54
  else if (multiTenant.getTenantConfig) {
50
- tenantConfig = await multiTenant.getTenantConfig(tenantId);
55
+ tenantConfig = await multiTenant.getTenantConfig(tId);
51
56
  }
52
57
  if (!tenantConfig) {
53
- throw new Error(`Vollcrypt Security: Configuration not found for tenantId "${tenantId}".`);
58
+ throw new Error(`Vollcrypt Security: Configuration not found for tenantId "${tId}".`);
54
59
  }
55
- const resolvedTenantKeys = await (0, prisma_1.resolveKeys)({
60
+ const resolvedTenantKeysRaw = await (0, kms_1.resolveKeys)({
56
61
  ...options,
57
62
  key: tenantConfig.key,
58
63
  kms: tenantConfig.kms
59
64
  });
60
- (0, security_1.registerKeysForZeroization)(resolvedTenantKeys);
65
+ const resolvedTenantKeys = {};
66
+ for (const [v, k] of Object.entries(resolvedTenantKeysRaw)) {
67
+ resolvedTenantKeys[v] = Buffer.from(k);
68
+ }
69
+ (0, security_1.registerKeysForZeroization)(resolvedTenantKeys, tId);
61
70
  const tActiveVersion = tenantConfig.kms?.activeKeyVersion || '1';
62
71
  const tActiveKey = resolvedTenantKeys[tActiveVersion];
63
72
  if (!tActiveKey) {
64
- throw new Error(`Vollcrypt Security: Active key version "${tActiveVersion}" not found for tenantId "${tenantId}".`);
73
+ throw new Error(`Vollcrypt Security: Active key version "${tActiveVersion}" not found for tenantId "${tId}".`);
65
74
  }
66
75
  for (const [ver, keyBuf] of Object.entries(resolvedTenantKeys)) {
67
- (0, security_1.setCachedKey)(tenantId, ver, keyBuf);
76
+ (0, security_1.setCachedKey)(tId, ver, keyBuf);
68
77
  }
69
78
  return { keys: resolvedTenantKeys, activeKey: tActiveKey, activeVersion: tActiveVersion };
70
79
  };
@@ -79,7 +88,7 @@ function mongooseDbGuard(schema, options) {
79
88
  // 1. Encrypt fields
80
89
  for (const field of fields) {
81
90
  if (doc.isModified(field) && doc[field] !== undefined && doc[field] !== null) {
82
- doc[field] = (0, prisma_1.encryptValue)(doc[field], resolved.activeKey, resolved.activeVersion);
91
+ doc[field] = (0, security_1.encryptValue)(doc[field], resolved.activeKey, resolved.activeVersion);
83
92
  }
84
93
  }
85
94
  // 2. Compute blind indexes
@@ -89,9 +98,9 @@ function mongooseDbGuard(schema, options) {
89
98
  const bidxField = `${field}_bidx`;
90
99
  // Decrypt temporary value if it was already encrypted in the previous step
91
100
  const rawVal = doc.isModified(field) && doc[field].startsWith('VOLLVALT:')
92
- ? (0, prisma_1.decryptValue)(doc[field], keys)
101
+ ? (0, security_1.decryptValue)(doc[field], keys)
93
102
  : doc[field];
94
- doc[bidxField] = (0, blind_index_1.computeBlindIndex)(rawVal, options.blindIndexes.rootSalt, `${modelName}.${field}`);
103
+ doc[bidxField] = (0, security_1.computeBlindIndex)(rawVal, options.blindIndexes.rootSalt, `${modelName}.${field}`);
95
104
  }
96
105
  }
97
106
  }
@@ -128,9 +137,9 @@ function mongooseDbGuard(schema, options) {
128
137
  if (obj[currentPart] !== undefined && obj[currentPart] !== null) {
129
138
  if (options.blindIndexes && options.blindIndexes.fields.includes(fullPath) && options.blindIndexes.rootSalt) {
130
139
  const bidxField = `${currentPart}_bidx`;
131
- obj[bidxField] = (0, blind_index_1.computeBlindIndex)(obj[currentPart], options.blindIndexes.rootSalt, `${modelName}.${fullPath}`);
140
+ obj[bidxField] = (0, security_1.computeBlindIndex)(obj[currentPart], options.blindIndexes.rootSalt, `${modelName}.${fullPath}`);
132
141
  }
133
- obj[currentPart] = (0, prisma_1.encryptValue)(obj[currentPart], encKey, encVer);
142
+ obj[currentPart] = (0, security_1.encryptValue)(obj[currentPart], encKey, encVer);
134
143
  }
135
144
  }
136
145
  else {
@@ -141,9 +150,9 @@ function mongooseDbGuard(schema, options) {
141
150
  if (obj[dotNotatedPath] !== undefined && obj[dotNotatedPath] !== null) {
142
151
  if (options.blindIndexes && options.blindIndexes.fields.includes(fullPath) && options.blindIndexes.rootSalt) {
143
152
  const bidxField = `${dotNotatedPath}_bidx`;
144
- obj[bidxField] = (0, blind_index_1.computeBlindIndex)(obj[dotNotatedPath], options.blindIndexes.rootSalt, `${modelName}.${fullPath}`);
153
+ obj[bidxField] = (0, security_1.computeBlindIndex)(obj[dotNotatedPath], options.blindIndexes.rootSalt, `${modelName}.${fullPath}`);
145
154
  }
146
- obj[dotNotatedPath] = (0, prisma_1.encryptValue)(obj[dotNotatedPath], encKey, encVer);
155
+ obj[dotNotatedPath] = (0, security_1.encryptValue)(obj[dotNotatedPath], encKey, encVer);
147
156
  }
148
157
  }
149
158
  };
@@ -178,7 +187,7 @@ function mongooseDbGuard(schema, options) {
178
187
  // 2. Process query criteria (rewrite exact match search queries on conditions)
179
188
  const conditions = typeof query.getQuery === 'function' ? query.getQuery() : null;
180
189
  if (conditions && options.blindIndexes && options.blindIndexes.rootSalt) {
181
- (0, prisma_1.rewriteQueryWhere)(conditions, options.blindIndexes.fields, options.blindIndexes.rootSalt, modelName);
190
+ (0, security_1.rewriteQueryWhere)(conditions, options.blindIndexes.fields, options.blindIndexes.rootSalt, modelName);
182
191
  }
183
192
  if (typeof next === 'function') {
184
193
  next();
@@ -210,7 +219,7 @@ function mongooseDbGuard(schema, options) {
210
219
  const modelName = options.blindIndexes?.modelName || query.model?.modelName || 'Model';
211
220
  const conditions = typeof query.getQuery === 'function' ? query.getQuery() : null;
212
221
  if (conditions && options.blindIndexes && options.blindIndexes.rootSalt) {
213
- (0, prisma_1.rewriteQueryWhere)(conditions, options.blindIndexes.fields, options.blindIndexes.rootSalt, modelName);
222
+ (0, security_1.rewriteQueryWhere)(conditions, options.blindIndexes.fields, options.blindIndexes.rootSalt, modelName);
214
223
  }
215
224
  next();
216
225
  });
@@ -222,7 +231,7 @@ function mongooseDbGuard(schema, options) {
222
231
  for (const field of fields) {
223
232
  if (doc[field] !== undefined && doc[field] !== null) {
224
233
  try {
225
- doc[field] = (0, security_1.decryptWithSecurity)(doc[field], (val) => (0, prisma_1.decryptValue)(val, decKeys), modelName, field, doc.id || doc._id, options);
234
+ doc[field] = (0, security_1.decryptWithSecurity)(doc[field], (val) => (0, security_1.decryptValue)(val, decKeys), modelName, field, doc.id || doc._id, options);
226
235
  }
227
236
  catch (err) {
228
237
  throw new Error(`Mongoose db-guard failed to decrypt field "${field}": ${err.message}`);