@vollcrypt/db-guard 0.1.1 → 0.1.2
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/dist/drivers.d.ts +15 -0
- package/dist/drivers.js +181 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -1
- package/dist/provenance.json +18 -6
- package/dist/provenance.json.sig +1 -2
- package/dist/sbom.json +14 -6
- package/dist/sbom.json.sig +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RateLimiterOptions } from './security.js';
|
|
2
|
+
export interface DbGuardDriverOptions {
|
|
3
|
+
key: Buffer | Record<string, Buffer>;
|
|
4
|
+
activeKeyVersion?: string;
|
|
5
|
+
entities: Record<string, string[]>;
|
|
6
|
+
cryptoRbac?: {
|
|
7
|
+
roles: Record<string, {
|
|
8
|
+
decrypt: string[];
|
|
9
|
+
mask?: Record<string, 'credit_card' | 'email' | 'tc_no' | ((v: any) => any) | string>;
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
rateLimiter?: RateLimiterOptions;
|
|
13
|
+
}
|
|
14
|
+
export declare function wrapSqliteDatabase(db: any, options: DbGuardDriverOptions): any;
|
|
15
|
+
export declare function wrapOracleConnection(connection: any, options: DbGuardDriverOptions): any;
|
package/dist/drivers.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapSqliteDatabase = wrapSqliteDatabase;
|
|
4
|
+
exports.wrapOracleConnection = wrapOracleConnection;
|
|
5
|
+
const prisma_js_1 = require("./prisma.js");
|
|
6
|
+
const security_js_1 = require("./security.js");
|
|
7
|
+
function getKeys(options) {
|
|
8
|
+
let keys;
|
|
9
|
+
let activeVersion;
|
|
10
|
+
if (Buffer.isBuffer(options.key)) {
|
|
11
|
+
keys = { '1': options.key };
|
|
12
|
+
activeVersion = '1';
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
keys = options.key;
|
|
16
|
+
activeVersion = options.activeKeyVersion || Object.keys(keys)[0];
|
|
17
|
+
}
|
|
18
|
+
return { keys, activeVersion };
|
|
19
|
+
}
|
|
20
|
+
function getParamColumns(sql) {
|
|
21
|
+
const sqlClean = sql.replace(/\s+/g, ' ').trim();
|
|
22
|
+
// Match INSERT INTO table (col1, col2) ...
|
|
23
|
+
const insertMatch = sqlClean.match(/INSERT\s+INTO\s+(\w+)\s*\(([^)]+)\)/i);
|
|
24
|
+
if (insertMatch) {
|
|
25
|
+
const table = insertMatch[1];
|
|
26
|
+
const columns = insertMatch[2].split(',').map(c => c.trim());
|
|
27
|
+
return { table, columns };
|
|
28
|
+
}
|
|
29
|
+
// Match UPDATE table SET col1 = ?, col2 = ? ...
|
|
30
|
+
const updateMatch = sqlClean.match(/UPDATE\s+(\w+)\s+SET\s+([\s\S]+?)(?:\s+WHERE|$)/i);
|
|
31
|
+
if (updateMatch) {
|
|
32
|
+
const table = updateMatch[1];
|
|
33
|
+
const setParts = updateMatch[2].split(',');
|
|
34
|
+
const columns = [];
|
|
35
|
+
for (const part of setParts) {
|
|
36
|
+
const match = part.match(/(\w+)\s*=/);
|
|
37
|
+
if (match) {
|
|
38
|
+
columns.push(match[1]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return { table, columns };
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
function decryptRow(row, table, keys, options) {
|
|
46
|
+
if (!row)
|
|
47
|
+
return row;
|
|
48
|
+
if (typeof row === 'object') {
|
|
49
|
+
const cloned = Array.isArray(row) ? [...row] : { ...row };
|
|
50
|
+
if (Array.isArray(row)) {
|
|
51
|
+
// Array format (index-based)
|
|
52
|
+
for (let i = 0; i < row.length; i++) {
|
|
53
|
+
const val = row[i];
|
|
54
|
+
if (typeof val === 'string' && val.startsWith('VOLLVALT:')) {
|
|
55
|
+
try {
|
|
56
|
+
cloned[i] = (0, security_js_1.decryptWithSecurity)(val, (v) => (0, prisma_js_1.decryptValue)(v, keys), table, `column_${i}`, undefined, options);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Keep original on failure
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// Object format (key-value)
|
|
66
|
+
const fields = options.entities[table] || [];
|
|
67
|
+
for (const [key, val] of Object.entries(row)) {
|
|
68
|
+
if (typeof val === 'string' && val.startsWith('VOLLVALT:')) {
|
|
69
|
+
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);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Keep original on failure
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return cloned;
|
|
79
|
+
}
|
|
80
|
+
return row;
|
|
81
|
+
}
|
|
82
|
+
function wrapSqliteDatabase(db, options) {
|
|
83
|
+
const { keys, activeVersion } = getKeys(options);
|
|
84
|
+
const activeKey = keys[activeVersion];
|
|
85
|
+
(0, security_js_1.registerKeysForZeroization)(keys);
|
|
86
|
+
const originalPrepare = db.prepare;
|
|
87
|
+
db.prepare = function (sql, ...args) {
|
|
88
|
+
const statement = originalPrepare.call(this, sql, ...args);
|
|
89
|
+
const parsed = getParamColumns(sql);
|
|
90
|
+
// Helper to encrypt query input parameters
|
|
91
|
+
const encryptParams = (params) => {
|
|
92
|
+
if (!parsed)
|
|
93
|
+
return params;
|
|
94
|
+
const table = parsed.table;
|
|
95
|
+
const columns = parsed.columns;
|
|
96
|
+
const fieldsToEncrypt = options.entities[table] || [];
|
|
97
|
+
if (fieldsToEncrypt.length === 0)
|
|
98
|
+
return params;
|
|
99
|
+
return params.map((param, index) => {
|
|
100
|
+
const colName = columns[index];
|
|
101
|
+
if (colName && fieldsToEncrypt.includes(colName)) {
|
|
102
|
+
return (0, prisma_js_1.encryptValue)(param, activeKey, activeVersion);
|
|
103
|
+
}
|
|
104
|
+
return param;
|
|
105
|
+
});
|
|
106
|
+
};
|
|
107
|
+
const wrapStatementMethod = (originalMethod) => {
|
|
108
|
+
return function (...params) {
|
|
109
|
+
const processedParams = encryptParams(params);
|
|
110
|
+
const result = originalMethod.apply(statement, processedParams);
|
|
111
|
+
if (parsed) {
|
|
112
|
+
const table = parsed.table;
|
|
113
|
+
if (Array.isArray(result)) {
|
|
114
|
+
return result.map(row => decryptRow(row, table, keys, options));
|
|
115
|
+
}
|
|
116
|
+
else if (result) {
|
|
117
|
+
return decryptRow(result, table, keys, options);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
// If query SQL parsing was skipped (e.g. SELECT *), decrypt rows generically
|
|
122
|
+
// using first table configured in options as fallback
|
|
123
|
+
const defaultTable = Object.keys(options.entities)[0] || 'Model';
|
|
124
|
+
if (Array.isArray(result)) {
|
|
125
|
+
return result.map(row => decryptRow(row, defaultTable, keys, options));
|
|
126
|
+
}
|
|
127
|
+
else if (result) {
|
|
128
|
+
return decryptRow(result, defaultTable, keys, options);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
statement.run = wrapStatementMethod(statement.run);
|
|
135
|
+
statement.get = wrapStatementMethod(statement.get);
|
|
136
|
+
statement.all = wrapStatementMethod(statement.all);
|
|
137
|
+
return statement;
|
|
138
|
+
};
|
|
139
|
+
return db;
|
|
140
|
+
}
|
|
141
|
+
function wrapOracleConnection(connection, options) {
|
|
142
|
+
const { keys, activeVersion } = getKeys(options);
|
|
143
|
+
const activeKey = keys[activeVersion];
|
|
144
|
+
(0, security_js_1.registerKeysForZeroization)(keys);
|
|
145
|
+
const originalExecute = connection.execute;
|
|
146
|
+
connection.execute = async function (sql, bindParams = {}, execOptions = {}, ...args) {
|
|
147
|
+
const parsed = getParamColumns(sql);
|
|
148
|
+
let processedBinds = bindParams;
|
|
149
|
+
if (parsed) {
|
|
150
|
+
const table = parsed.table;
|
|
151
|
+
const columns = parsed.columns;
|
|
152
|
+
const fieldsToEncrypt = options.entities[table] || [];
|
|
153
|
+
if (fieldsToEncrypt.length > 0) {
|
|
154
|
+
if (Array.isArray(bindParams)) {
|
|
155
|
+
processedBinds = bindParams.map((param, index) => {
|
|
156
|
+
const colName = columns[index];
|
|
157
|
+
if (colName && fieldsToEncrypt.includes(colName)) {
|
|
158
|
+
return (0, prisma_js_1.encryptValue)(param, activeKey, activeVersion);
|
|
159
|
+
}
|
|
160
|
+
return param;
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
else if (bindParams && typeof bindParams === 'object') {
|
|
164
|
+
processedBinds = { ...bindParams };
|
|
165
|
+
for (const field of fieldsToEncrypt) {
|
|
166
|
+
if (processedBinds[field] !== undefined && processedBinds[field] !== null) {
|
|
167
|
+
processedBinds[field] = (0, prisma_js_1.encryptValue)(processedBinds[field], activeKey, activeVersion);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const result = await originalExecute.call(this, sql, processedBinds, execOptions, ...args);
|
|
174
|
+
if (result && result.rows) {
|
|
175
|
+
const targetTable = parsed ? parsed.table : (Object.keys(options.entities)[0] || 'Model');
|
|
176
|
+
result.rows = result.rows.map((row) => decryptRow(row, targetTable, keys, options));
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
};
|
|
180
|
+
return connection;
|
|
181
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { prismaDbGuard, PrismaDbGuardOptions, encryptValue, decryptValue, resolv
|
|
|
2
2
|
export { mongooseDbGuard, MongooseDbGuardOptions } from './mongoose';
|
|
3
3
|
export { createDrizzleGuard } from './drizzle';
|
|
4
4
|
export { createTypeOrmSubscriber } from './typeorm';
|
|
5
|
+
export { wrapSqliteDatabase, wrapOracleConnection, DbGuardDriverOptions } from './drivers';
|
|
5
6
|
export { KmsProvider, AwsKmsProvider, GcpKmsProvider, VaultKmsProvider, unwrapDekLocal, Pkcs11KmsProvider } from './kms';
|
|
6
7
|
export { computeBlindIndex } from './blind-index';
|
|
7
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';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +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.createTypeOrmSubscriber = exports.createDrizzleGuard = exports.mongooseDbGuard = exports.resolveKeys = exports.decryptValue = exports.encryptValue = exports.prismaDbGuard = void 0;
|
|
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
4
|
var prisma_1 = require("./prisma");
|
|
5
5
|
Object.defineProperty(exports, "prismaDbGuard", { enumerable: true, get: function () { return prisma_1.prismaDbGuard; } });
|
|
6
6
|
Object.defineProperty(exports, "encryptValue", { enumerable: true, get: function () { return prisma_1.encryptValue; } });
|
|
@@ -12,6 +12,9 @@ var drizzle_1 = require("./drizzle");
|
|
|
12
12
|
Object.defineProperty(exports, "createDrizzleGuard", { enumerable: true, get: function () { return drizzle_1.createDrizzleGuard; } });
|
|
13
13
|
var typeorm_1 = require("./typeorm");
|
|
14
14
|
Object.defineProperty(exports, "createTypeOrmSubscriber", { enumerable: true, get: function () { return typeorm_1.createTypeOrmSubscriber; } });
|
|
15
|
+
var drivers_1 = require("./drivers");
|
|
16
|
+
Object.defineProperty(exports, "wrapSqliteDatabase", { enumerable: true, get: function () { return drivers_1.wrapSqliteDatabase; } });
|
|
17
|
+
Object.defineProperty(exports, "wrapOracleConnection", { enumerable: true, get: function () { return drivers_1.wrapOracleConnection; } });
|
|
15
18
|
var kms_1 = require("./kms");
|
|
16
19
|
Object.defineProperty(exports, "AwsKmsProvider", { enumerable: true, get: function () { return kms_1.AwsKmsProvider; } });
|
|
17
20
|
Object.defineProperty(exports, "GcpKmsProvider", { enumerable: true, get: function () { return kms_1.GcpKmsProvider; } });
|
package/dist/provenance.json
CHANGED
|
@@ -37,6 +37,18 @@
|
|
|
37
37
|
"sha256": "0b660e3eafcc27a78d5c97c7d34837a25c68295660a3d1c7da0ae8e0a676bfb6"
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
+
{
|
|
41
|
+
"name": "dist/drivers.d.ts",
|
|
42
|
+
"digest": {
|
|
43
|
+
"sha256": "1363416c7c4ce5549331a13c43f89c8cba2865b26cac8e699b4504c48c29b049"
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "dist/drivers.js",
|
|
48
|
+
"digest": {
|
|
49
|
+
"sha256": "44623a5cf632c22a41b8196b809a3c00d50276bde28c2fbde13d6f4bef3177ce"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
40
52
|
{
|
|
41
53
|
"name": "dist/drizzle.d.ts",
|
|
42
54
|
"digest": {
|
|
@@ -52,13 +64,13 @@
|
|
|
52
64
|
{
|
|
53
65
|
"name": "dist/index.d.ts",
|
|
54
66
|
"digest": {
|
|
55
|
-
"sha256": "
|
|
67
|
+
"sha256": "a4864c4ea0bb9e9cc9bc1f58cdbc31863e5543a572e6049ee900b53b9fecb003"
|
|
56
68
|
}
|
|
57
69
|
},
|
|
58
70
|
{
|
|
59
71
|
"name": "dist/index.js",
|
|
60
72
|
"digest": {
|
|
61
|
-
"sha256": "
|
|
73
|
+
"sha256": "496292f1edd16bd779f6e8712291c4b90e5b3f404d71b54f5c369c6736c26814"
|
|
62
74
|
}
|
|
63
75
|
},
|
|
64
76
|
{
|
|
@@ -129,7 +141,7 @@
|
|
|
129
141
|
"externalParameters": {
|
|
130
142
|
"packageJson": {
|
|
131
143
|
"name": "@vollcrypt/db-guard",
|
|
132
|
-
"version": "0.1.
|
|
144
|
+
"version": "0.1.2",
|
|
133
145
|
"scripts": {
|
|
134
146
|
"build": "tsc && node scripts/generate-sbom.js",
|
|
135
147
|
"test": "node --import tsx --test tests/*.test.ts"
|
|
@@ -213,9 +225,9 @@
|
|
|
213
225
|
"id": "https://vollcrypt.dev/builders/local-hermetic-env"
|
|
214
226
|
},
|
|
215
227
|
"metadata": {
|
|
216
|
-
"invocationId": "
|
|
217
|
-
"startedOn": "2026-06-
|
|
218
|
-
"finishedOn": "2026-06-
|
|
228
|
+
"invocationId": "19095e456ee2a685d43df5cc56999080",
|
|
229
|
+
"startedOn": "2026-06-11T16:17:36.609Z",
|
|
230
|
+
"finishedOn": "2026-06-11T16:17:36.610Z"
|
|
219
231
|
}
|
|
220
232
|
}
|
|
221
233
|
}
|
package/dist/provenance.json.sig
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
�����������bܤ�/W����>6
|
|
1
|
+
?NENc0�HӰ�@�S�t��J�ɽ<(:3�8O �7X�q-du�Y�^~՚�8�z� Dž�
|
package/dist/sbom.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.5",
|
|
4
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"serialNumber": "urn:uuid:45a7c8f7-12f3-4e25-ab52-81be917b4646",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
|
-
"timestamp": "2026-06-
|
|
7
|
+
"timestamp": "2026-06-11T16:17:36.609Z",
|
|
8
8
|
"tools": [
|
|
9
9
|
{
|
|
10
10
|
"vendor": "Vollcrypt",
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"component": {
|
|
16
|
-
"bomRef": "pkg:npm/@vollcrypt/db-guard@0.1.
|
|
16
|
+
"bomRef": "pkg:npm/@vollcrypt/db-guard@0.1.2",
|
|
17
17
|
"type": "library",
|
|
18
18
|
"name": "@vollcrypt/db-guard",
|
|
19
|
-
"version": "0.1.
|
|
19
|
+
"version": "0.1.2",
|
|
20
20
|
"description": "Database field-level encryption integrations for Vollcrypt (Prisma, Mongoose, Drizzle, TypeORM)",
|
|
21
21
|
"hashes": [
|
|
22
22
|
{
|
|
@@ -43,6 +43,14 @@
|
|
|
43
43
|
"alg": "SHA-256",
|
|
44
44
|
"content": "0b660e3eafcc27a78d5c97c7d34837a25c68295660a3d1c7da0ae8e0a676bfb6"
|
|
45
45
|
},
|
|
46
|
+
{
|
|
47
|
+
"alg": "SHA-256",
|
|
48
|
+
"content": "1363416c7c4ce5549331a13c43f89c8cba2865b26cac8e699b4504c48c29b049"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"alg": "SHA-256",
|
|
52
|
+
"content": "44623a5cf632c22a41b8196b809a3c00d50276bde28c2fbde13d6f4bef3177ce"
|
|
53
|
+
},
|
|
46
54
|
{
|
|
47
55
|
"alg": "SHA-256",
|
|
48
56
|
"content": "cb43fec66c7da1e84b96a97e8a18b0d08606535c64236f66ff950250d0f23292"
|
|
@@ -53,11 +61,11 @@
|
|
|
53
61
|
},
|
|
54
62
|
{
|
|
55
63
|
"alg": "SHA-256",
|
|
56
|
-
"content": "
|
|
64
|
+
"content": "a4864c4ea0bb9e9cc9bc1f58cdbc31863e5543a572e6049ee900b53b9fecb003"
|
|
57
65
|
},
|
|
58
66
|
{
|
|
59
67
|
"alg": "SHA-256",
|
|
60
|
-
"content": "
|
|
68
|
+
"content": "496292f1edd16bd779f6e8712291c4b90e5b3f404d71b54f5c369c6736c26814"
|
|
61
69
|
},
|
|
62
70
|
{
|
|
63
71
|
"alg": "SHA-256",
|
package/dist/sbom.json.sig
CHANGED
|
Binary file
|
package/package.json
CHANGED