@vollcrypt/db-guard 0.9.0 → 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.
- package/LICENSE +16 -0
- package/LICENSE-COMMERCIAL.md +71 -0
- package/LICENSE-GPL +674 -0
- package/dist/blind-index.d.ts +1 -7
- package/dist/blind-index.js +3 -26
- package/dist/cli.js +3 -3
- package/dist/drivers.js +7 -8
- package/dist/drizzle.js +18 -20
- package/dist/index.d.ts +2 -6
- package/dist/index.js +4 -12
- package/dist/kms.d.ts +10 -0
- package/dist/kms.js +50 -0
- package/dist/mongoose.d.ts +1 -1
- package/dist/mongoose.js +12 -13
- package/dist/prisma.d.ts +4 -24
- package/dist/prisma.js +18 -174
- package/dist/provenance.json +21 -21
- package/dist/provenance.json.sig +2 -1
- package/dist/sbom.json +21 -21
- package/dist/sbom.json.sig +1 -2
- package/dist/security.d.ts +8 -0
- package/dist/security.js +124 -0
- package/dist/typeorm.d.ts +1 -1
- package/dist/typeorm.js +7 -9
- package/package.json +27 -2
package/dist/blind-index.js
CHANGED
|
@@ -1,28 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.computeBlindIndex =
|
|
4
|
-
|
|
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
|
-
try {
|
|
19
|
-
// 2. Compute the final blind index using the derived column key
|
|
20
|
-
const plaintextBuf = Buffer.from(plaintext, 'utf8');
|
|
21
|
-
const blindIndex = (0, security_1.deriveHkdf)(derivedColumnKey, null, plaintextBuf, 32);
|
|
22
|
-
return blindIndex.toString('hex');
|
|
23
|
-
}
|
|
24
|
-
finally {
|
|
25
|
-
// 3. RAM Security: Zeroize the derived key immediately (Anti-Core Dump)
|
|
26
|
-
derivedColumnKey.fill(0);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
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
|
|
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,
|
|
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,
|
|
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,7 +2,6 @@
|
|
|
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
7
|
let keys = {};
|
|
@@ -66,7 +65,7 @@ function decryptRow(row, table, keys, options) {
|
|
|
66
65
|
const val = row[i];
|
|
67
66
|
if (typeof val === 'string' && val.startsWith('VOLLVALT:')) {
|
|
68
67
|
try {
|
|
69
|
-
cloned[i] = (0, security_js_1.decryptWithSecurity)(val, (v) => (0,
|
|
68
|
+
cloned[i] = (0, security_js_1.decryptWithSecurity)(val, (v) => (0, security_js_1.decryptValue)(v, keys), table, `column_${i}`, undefined, options);
|
|
70
69
|
}
|
|
71
70
|
catch {
|
|
72
71
|
// Keep original on failure
|
|
@@ -80,7 +79,7 @@ function decryptRow(row, table, keys, options) {
|
|
|
80
79
|
for (const [key, val] of Object.entries(row)) {
|
|
81
80
|
if (typeof val === 'string' && val.startsWith('VOLLVALT:')) {
|
|
82
81
|
try {
|
|
83
|
-
cloned[key] = (0, security_js_1.decryptWithSecurity)(val, (v) => (0,
|
|
82
|
+
cloned[key] = (0, security_js_1.decryptWithSecurity)(val, (v) => (0, security_js_1.decryptValue)(v, keys), table, key, row.id || row._id, options);
|
|
84
83
|
}
|
|
85
84
|
catch {
|
|
86
85
|
// Keep original on failure
|
|
@@ -114,7 +113,7 @@ function wrapSqliteDatabase(db, options) {
|
|
|
114
113
|
const arrayParams = params[0].map((param, index) => {
|
|
115
114
|
const colName = columns[index];
|
|
116
115
|
if (colName && fieldsToEncrypt.includes(colName)) {
|
|
117
|
-
return (0,
|
|
116
|
+
return (0, security_js_1.encryptValue)(param, activeKey, activeVersion);
|
|
118
117
|
}
|
|
119
118
|
return param;
|
|
120
119
|
});
|
|
@@ -127,7 +126,7 @@ function wrapSqliteDatabase(db, options) {
|
|
|
127
126
|
// Strip prefix character (@, :, $) if present
|
|
128
127
|
const cleanKey = key.replace(/^[@:$]/, '');
|
|
129
128
|
if (fieldsToEncrypt.includes(cleanKey)) {
|
|
130
|
-
obj[key] = (0,
|
|
129
|
+
obj[key] = (0, security_js_1.encryptValue)(val, activeKey, activeVersion);
|
|
131
130
|
}
|
|
132
131
|
}
|
|
133
132
|
return [obj];
|
|
@@ -136,7 +135,7 @@ function wrapSqliteDatabase(db, options) {
|
|
|
136
135
|
return params.map((param, index) => {
|
|
137
136
|
const colName = columns[index];
|
|
138
137
|
if (colName && fieldsToEncrypt.includes(colName)) {
|
|
139
|
-
return (0,
|
|
138
|
+
return (0, security_js_1.encryptValue)(param, activeKey, activeVersion);
|
|
140
139
|
}
|
|
141
140
|
return param;
|
|
142
141
|
});
|
|
@@ -192,7 +191,7 @@ function wrapOracleConnection(connection, options) {
|
|
|
192
191
|
processedBinds = bindParams.map((param, index) => {
|
|
193
192
|
const colName = columns[index];
|
|
194
193
|
if (colName && fieldsToEncrypt.includes(colName)) {
|
|
195
|
-
return (0,
|
|
194
|
+
return (0, security_js_1.encryptValue)(param, activeKey, activeVersion);
|
|
196
195
|
}
|
|
197
196
|
return param;
|
|
198
197
|
});
|
|
@@ -201,7 +200,7 @@ function wrapOracleConnection(connection, options) {
|
|
|
201
200
|
processedBinds = { ...bindParams };
|
|
202
201
|
for (const field of fieldsToEncrypt) {
|
|
203
202
|
if (processedBinds[field] !== undefined && processedBinds[field] !== null) {
|
|
204
|
-
processedBinds[field] = (0,
|
|
203
|
+
processedBinds[field] = (0, security_js_1.encryptValue)(processedBinds[field], activeKey, activeVersion);
|
|
205
204
|
}
|
|
206
205
|
}
|
|
207
206
|
}
|
package/dist/drizzle.js
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
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;
|
|
@@ -24,6 +19,9 @@ function getKeys(options) {
|
|
|
24
19
|
return { keys, activeVersion };
|
|
25
20
|
}
|
|
26
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;
|
|
27
25
|
const { keys, activeVersion } = getKeys(options);
|
|
28
26
|
const activeKey = keys[activeVersion];
|
|
29
27
|
if (!activeKey) {
|
|
@@ -32,49 +30,49 @@ const createDrizzleGuard = (options) => {
|
|
|
32
30
|
(0, security_1.registerKeysForZeroization)(keys);
|
|
33
31
|
const rootSalt = options.blindIndexes?.rootSalt;
|
|
34
32
|
return {
|
|
35
|
-
pgText: (name, columnPath) => (
|
|
33
|
+
pgText: (name, columnPath) => pgCustomType({
|
|
36
34
|
dataType() {
|
|
37
35
|
return 'text';
|
|
38
36
|
},
|
|
39
37
|
toDriver(value) {
|
|
40
|
-
return (0,
|
|
38
|
+
return (0, security_1.encryptValue)(value, activeKey, activeVersion);
|
|
41
39
|
},
|
|
42
40
|
fromDriver(value) {
|
|
43
41
|
const parts = columnPath?.split('.') || [name];
|
|
44
42
|
const mName = parts[0] || 'Model';
|
|
45
43
|
const fName = parts[1] || name;
|
|
46
|
-
return (0, security_1.decryptWithSecurity)(value, (val) => (0,
|
|
44
|
+
return (0, security_1.decryptWithSecurity)(value, (val) => (0, security_1.decryptValue)(val, keys), mName, fName, undefined, options);
|
|
47
45
|
}
|
|
48
46
|
})(name),
|
|
49
|
-
mysqlText: (name, columnPath) => (
|
|
47
|
+
mysqlText: (name, columnPath) => mysqlCustomType({
|
|
50
48
|
dataType() {
|
|
51
49
|
return 'text';
|
|
52
50
|
},
|
|
53
51
|
toDriver(value) {
|
|
54
|
-
return (0,
|
|
52
|
+
return (0, security_1.encryptValue)(value, activeKey, activeVersion);
|
|
55
53
|
},
|
|
56
54
|
fromDriver(value) {
|
|
57
55
|
const parts = columnPath?.split('.') || [name];
|
|
58
56
|
const mName = parts[0] || 'Model';
|
|
59
57
|
const fName = parts[1] || name;
|
|
60
|
-
return (0, security_1.decryptWithSecurity)(value, (val) => (0,
|
|
58
|
+
return (0, security_1.decryptWithSecurity)(value, (val) => (0, security_1.decryptValue)(val, keys), mName, fName, undefined, options);
|
|
61
59
|
}
|
|
62
60
|
})(name),
|
|
63
|
-
sqliteText: (name, columnPath) => (
|
|
61
|
+
sqliteText: (name, columnPath) => sqliteCustomType({
|
|
64
62
|
dataType() {
|
|
65
63
|
return 'text';
|
|
66
64
|
},
|
|
67
65
|
toDriver(value) {
|
|
68
|
-
return (0,
|
|
66
|
+
return (0, security_1.encryptValue)(value, activeKey, activeVersion);
|
|
69
67
|
},
|
|
70
68
|
fromDriver(value) {
|
|
71
69
|
const parts = columnPath?.split('.') || [name];
|
|
72
70
|
const mName = parts[0] || 'Model';
|
|
73
71
|
const fName = parts[1] || name;
|
|
74
|
-
return (0, security_1.decryptWithSecurity)(value, (val) => (0,
|
|
72
|
+
return (0, security_1.decryptWithSecurity)(value, (val) => (0, security_1.decryptValue)(val, keys), mName, fName, undefined, options);
|
|
75
73
|
}
|
|
76
74
|
})(name),
|
|
77
|
-
pgBlindIndex: (name, columnName) => (
|
|
75
|
+
pgBlindIndex: (name, columnName) => pgCustomType({
|
|
78
76
|
dataType() {
|
|
79
77
|
return 'text';
|
|
80
78
|
},
|
|
@@ -82,13 +80,13 @@ const createDrizzleGuard = (options) => {
|
|
|
82
80
|
if (!rootSalt) {
|
|
83
81
|
throw new Error('Blind index root salt is not configured in Drizzle guard options.');
|
|
84
82
|
}
|
|
85
|
-
return (0,
|
|
83
|
+
return (0, security_1.computeBlindIndex)(value, rootSalt, columnName);
|
|
86
84
|
},
|
|
87
85
|
fromDriver(value) {
|
|
88
86
|
return value;
|
|
89
87
|
}
|
|
90
88
|
})(name),
|
|
91
|
-
mysqlBlindIndex: (name, columnName) => (
|
|
89
|
+
mysqlBlindIndex: (name, columnName) => mysqlCustomType({
|
|
92
90
|
dataType() {
|
|
93
91
|
return 'text';
|
|
94
92
|
},
|
|
@@ -96,13 +94,13 @@ const createDrizzleGuard = (options) => {
|
|
|
96
94
|
if (!rootSalt) {
|
|
97
95
|
throw new Error('Blind index root salt is not configured in Drizzle guard options.');
|
|
98
96
|
}
|
|
99
|
-
return (0,
|
|
97
|
+
return (0, security_1.computeBlindIndex)(value, rootSalt, columnName);
|
|
100
98
|
},
|
|
101
99
|
fromDriver(value) {
|
|
102
100
|
return value;
|
|
103
101
|
}
|
|
104
102
|
})(name),
|
|
105
|
-
sqliteBlindIndex: (name, columnName) => (
|
|
103
|
+
sqliteBlindIndex: (name, columnName) => sqliteCustomType({
|
|
106
104
|
dataType() {
|
|
107
105
|
return 'text';
|
|
108
106
|
},
|
|
@@ -110,7 +108,7 @@ const createDrizzleGuard = (options) => {
|
|
|
110
108
|
if (!rootSalt) {
|
|
111
109
|
throw new Error('Blind index root salt is not configured in Drizzle guard options.');
|
|
112
110
|
}
|
|
113
|
-
return (0,
|
|
111
|
+
return (0, security_1.computeBlindIndex)(value, rootSalt, columnName);
|
|
114
112
|
},
|
|
115
113
|
fromDriver(value) {
|
|
116
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 =
|
|
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;
|
|
@@ -158,3 +159,52 @@ class Pkcs11KmsProvider {
|
|
|
158
159
|
}
|
|
159
160
|
}
|
|
160
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
|
+
}
|
package/dist/mongoose.d.ts
CHANGED
package/dist/mongoose.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.mongooseDbGuard = mongooseDbGuard;
|
|
4
|
-
const
|
|
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;
|
|
@@ -58,7 +57,7 @@ function mongooseDbGuard(schema, options) {
|
|
|
58
57
|
if (!tenantConfig) {
|
|
59
58
|
throw new Error(`Vollcrypt Security: Configuration not found for tenantId "${tId}".`);
|
|
60
59
|
}
|
|
61
|
-
const resolvedTenantKeysRaw = await (0,
|
|
60
|
+
const resolvedTenantKeysRaw = await (0, kms_1.resolveKeys)({
|
|
62
61
|
...options,
|
|
63
62
|
key: tenantConfig.key,
|
|
64
63
|
kms: tenantConfig.kms
|
|
@@ -89,7 +88,7 @@ function mongooseDbGuard(schema, options) {
|
|
|
89
88
|
// 1. Encrypt fields
|
|
90
89
|
for (const field of fields) {
|
|
91
90
|
if (doc.isModified(field) && doc[field] !== undefined && doc[field] !== null) {
|
|
92
|
-
doc[field] = (0,
|
|
91
|
+
doc[field] = (0, security_1.encryptValue)(doc[field], resolved.activeKey, resolved.activeVersion);
|
|
93
92
|
}
|
|
94
93
|
}
|
|
95
94
|
// 2. Compute blind indexes
|
|
@@ -99,9 +98,9 @@ function mongooseDbGuard(schema, options) {
|
|
|
99
98
|
const bidxField = `${field}_bidx`;
|
|
100
99
|
// Decrypt temporary value if it was already encrypted in the previous step
|
|
101
100
|
const rawVal = doc.isModified(field) && doc[field].startsWith('VOLLVALT:')
|
|
102
|
-
? (0,
|
|
101
|
+
? (0, security_1.decryptValue)(doc[field], keys)
|
|
103
102
|
: doc[field];
|
|
104
|
-
doc[bidxField] = (0,
|
|
103
|
+
doc[bidxField] = (0, security_1.computeBlindIndex)(rawVal, options.blindIndexes.rootSalt, `${modelName}.${field}`);
|
|
105
104
|
}
|
|
106
105
|
}
|
|
107
106
|
}
|
|
@@ -138,9 +137,9 @@ function mongooseDbGuard(schema, options) {
|
|
|
138
137
|
if (obj[currentPart] !== undefined && obj[currentPart] !== null) {
|
|
139
138
|
if (options.blindIndexes && options.blindIndexes.fields.includes(fullPath) && options.blindIndexes.rootSalt) {
|
|
140
139
|
const bidxField = `${currentPart}_bidx`;
|
|
141
|
-
obj[bidxField] = (0,
|
|
140
|
+
obj[bidxField] = (0, security_1.computeBlindIndex)(obj[currentPart], options.blindIndexes.rootSalt, `${modelName}.${fullPath}`);
|
|
142
141
|
}
|
|
143
|
-
obj[currentPart] = (0,
|
|
142
|
+
obj[currentPart] = (0, security_1.encryptValue)(obj[currentPart], encKey, encVer);
|
|
144
143
|
}
|
|
145
144
|
}
|
|
146
145
|
else {
|
|
@@ -151,9 +150,9 @@ function mongooseDbGuard(schema, options) {
|
|
|
151
150
|
if (obj[dotNotatedPath] !== undefined && obj[dotNotatedPath] !== null) {
|
|
152
151
|
if (options.blindIndexes && options.blindIndexes.fields.includes(fullPath) && options.blindIndexes.rootSalt) {
|
|
153
152
|
const bidxField = `${dotNotatedPath}_bidx`;
|
|
154
|
-
obj[bidxField] = (0,
|
|
153
|
+
obj[bidxField] = (0, security_1.computeBlindIndex)(obj[dotNotatedPath], options.blindIndexes.rootSalt, `${modelName}.${fullPath}`);
|
|
155
154
|
}
|
|
156
|
-
obj[dotNotatedPath] = (0,
|
|
155
|
+
obj[dotNotatedPath] = (0, security_1.encryptValue)(obj[dotNotatedPath], encKey, encVer);
|
|
157
156
|
}
|
|
158
157
|
}
|
|
159
158
|
};
|
|
@@ -188,7 +187,7 @@ function mongooseDbGuard(schema, options) {
|
|
|
188
187
|
// 2. Process query criteria (rewrite exact match search queries on conditions)
|
|
189
188
|
const conditions = typeof query.getQuery === 'function' ? query.getQuery() : null;
|
|
190
189
|
if (conditions && options.blindIndexes && options.blindIndexes.rootSalt) {
|
|
191
|
-
(0,
|
|
190
|
+
(0, security_1.rewriteQueryWhere)(conditions, options.blindIndexes.fields, options.blindIndexes.rootSalt, modelName);
|
|
192
191
|
}
|
|
193
192
|
if (typeof next === 'function') {
|
|
194
193
|
next();
|
|
@@ -220,7 +219,7 @@ function mongooseDbGuard(schema, options) {
|
|
|
220
219
|
const modelName = options.blindIndexes?.modelName || query.model?.modelName || 'Model';
|
|
221
220
|
const conditions = typeof query.getQuery === 'function' ? query.getQuery() : null;
|
|
222
221
|
if (conditions && options.blindIndexes && options.blindIndexes.rootSalt) {
|
|
223
|
-
(0,
|
|
222
|
+
(0, security_1.rewriteQueryWhere)(conditions, options.blindIndexes.fields, options.blindIndexes.rootSalt, modelName);
|
|
224
223
|
}
|
|
225
224
|
next();
|
|
226
225
|
});
|
|
@@ -232,7 +231,7 @@ function mongooseDbGuard(schema, options) {
|
|
|
232
231
|
for (const field of fields) {
|
|
233
232
|
if (doc[field] !== undefined && doc[field] !== null) {
|
|
234
233
|
try {
|
|
235
|
-
doc[field] = (0, security_1.decryptWithSecurity)(doc[field], (val) => (0,
|
|
234
|
+
doc[field] = (0, security_1.decryptWithSecurity)(doc[field], (val) => (0, security_1.decryptValue)(val, decKeys), modelName, field, doc.id || doc._id, options);
|
|
236
235
|
}
|
|
237
236
|
catch (err) {
|
|
238
237
|
throw new Error(`Mongoose db-guard failed to decrypt field "${field}": ${err.message}`);
|
package/dist/prisma.d.ts
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DbGuardKeysOptions } from './kms';
|
|
2
2
|
import { RateLimiterOptions } from './security';
|
|
3
|
-
export interface PrismaDbGuardOptions {
|
|
4
|
-
key?: Buffer | Record<string, Buffer>;
|
|
5
|
-
kms?: {
|
|
6
|
-
provider: KmsProvider;
|
|
7
|
-
wrappedKey: Buffer | Record<string, Buffer>;
|
|
8
|
-
wrappedKek?: Buffer | Record<string, Buffer>;
|
|
9
|
-
activeKeyVersion?: string;
|
|
10
|
-
};
|
|
3
|
+
export interface PrismaDbGuardOptions extends DbGuardKeysOptions {
|
|
11
4
|
models: Record<string, string[]>;
|
|
12
5
|
blindIndexes?: {
|
|
13
6
|
rootSalt: Buffer;
|
|
@@ -31,24 +24,11 @@ export interface PrismaDbGuardOptions {
|
|
|
31
24
|
} | undefined>;
|
|
32
25
|
};
|
|
33
26
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Resolves the plaintext keys asynchronously from local config or KMS provider.
|
|
36
|
-
*/
|
|
37
|
-
export declare function resolveKeys(options: PrismaDbGuardOptions): Promise<Record<string, Buffer>>;
|
|
38
|
-
export declare function encryptValue(val: any, key: Buffer, version: string): string;
|
|
39
|
-
export declare function decryptValue(stored: any, keys: Record<string, Buffer>): any;
|
|
40
|
-
/**
|
|
41
|
-
* Traverses query `where` arguments to rewrite exact match queries on encrypted fields
|
|
42
|
-
* to target shadow `_bidx` columns using dynamic HKDF-SHA256 blind indexing.
|
|
43
|
-
*/
|
|
44
|
-
export declare function rewriteQueryWhere(where: any, fields: string[], rootSalt: Buffer, modelName: string): void;
|
|
45
|
-
/**
|
|
46
|
-
* Appends calculated blind indexes to the write payload (create/update).
|
|
47
|
-
*/
|
|
48
|
-
export declare function addBlindIndexes(data: any, fields: string[], rootSalt: Buffer, modelName: string): void;
|
|
49
27
|
/**
|
|
50
28
|
* Prisma DbGuard Extension Factory
|
|
51
29
|
*
|
|
52
30
|
* Bootstraps client-level field encryption, query translation, and automatic decryption.
|
|
53
31
|
*/
|
|
54
32
|
export declare const prismaDbGuard: (options: PrismaDbGuardOptions, resolvedKeys?: Record<string, Buffer>) => (client: any) => import("@prisma/client").PrismaClientExtends<import("@prisma/client/runtime/library").InternalArgs<{}, {}, {}, {}> & import("@prisma/client/runtime/library").DefaultArgs>;
|
|
33
|
+
export { encryptValue, decryptValue, rewriteQueryWhere, addBlindIndexes } from './security';
|
|
34
|
+
export { resolveKeys } from './kms';
|