@vollcrypt/db-guard 0.1.0
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/README.md +271 -0
- package/compliance-config.json +39 -0
- package/dist/blind-index.d.ts +7 -0
- package/dist/blind-index.js +24 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +211 -0
- package/dist/compliance-report.html +562 -0
- package/dist/compliance.d.ts +40 -0
- package/dist/compliance.js +659 -0
- package/dist/drizzle.d.ts +65 -0
- package/dist/drizzle.js +118 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +44 -0
- package/dist/kms.d.ts +46 -0
- package/dist/kms.js +154 -0
- package/dist/mongoose.d.ts +30 -0
- package/dist/mongoose.js +317 -0
- package/dist/prisma.d.ts +54 -0
- package/dist/prisma.js +390 -0
- package/dist/provenance.json +222 -0
- package/dist/provenance.json.sig +1 -0
- package/dist/sbom.json +209 -0
- package/dist/sbom.json.sig +1 -0
- package/dist/security.d.ts +88 -0
- package/dist/security.js +547 -0
- package/dist/typeorm.d.ts +26 -0
- package/dist/typeorm.js +149 -0
- package/package.json +50 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { RateLimiterOptions } from './security';
|
|
2
|
+
export interface DrizzleDbGuardOptions {
|
|
3
|
+
key: Buffer | Record<string, Buffer>;
|
|
4
|
+
activeKeyVersion?: string;
|
|
5
|
+
blindIndexes?: {
|
|
6
|
+
rootSalt: Buffer;
|
|
7
|
+
};
|
|
8
|
+
cryptoRbac?: {
|
|
9
|
+
roles: Record<string, {
|
|
10
|
+
decrypt: string[];
|
|
11
|
+
mask?: Record<string, 'credit_card' | 'email' | 'tc_no' | ((v: any) => any) | string>;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
rateLimiter?: RateLimiterOptions;
|
|
15
|
+
}
|
|
16
|
+
export declare const createDrizzleGuard: (options: DrizzleDbGuardOptions) => {
|
|
17
|
+
pgText: (name: string, columnPath?: string) => import("drizzle-orm/pg-core").PgCustomColumnBuilder<{
|
|
18
|
+
name: string;
|
|
19
|
+
dataType: "custom";
|
|
20
|
+
columnType: "PgCustomColumn";
|
|
21
|
+
data: unknown;
|
|
22
|
+
driverParam: unknown;
|
|
23
|
+
enumValues: undefined;
|
|
24
|
+
}>;
|
|
25
|
+
mysqlText: (name: string, columnPath?: string) => import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{
|
|
26
|
+
name: string;
|
|
27
|
+
dataType: "custom";
|
|
28
|
+
columnType: "MySqlCustomColumn";
|
|
29
|
+
data: unknown;
|
|
30
|
+
driverParam: unknown;
|
|
31
|
+
enumValues: undefined;
|
|
32
|
+
}>;
|
|
33
|
+
sqliteText: (name: string, columnPath?: string) => import("drizzle-orm/sqlite-core").SQLiteCustomColumnBuilder<{
|
|
34
|
+
name: string;
|
|
35
|
+
dataType: "custom";
|
|
36
|
+
columnType: "SQLiteCustomColumn";
|
|
37
|
+
data: unknown;
|
|
38
|
+
driverParam: unknown;
|
|
39
|
+
enumValues: undefined;
|
|
40
|
+
}>;
|
|
41
|
+
pgBlindIndex: (name: string, columnName: string) => import("drizzle-orm/pg-core").PgCustomColumnBuilder<{
|
|
42
|
+
name: string;
|
|
43
|
+
dataType: "custom";
|
|
44
|
+
columnType: "PgCustomColumn";
|
|
45
|
+
data: unknown;
|
|
46
|
+
driverParam: unknown;
|
|
47
|
+
enumValues: undefined;
|
|
48
|
+
}>;
|
|
49
|
+
mysqlBlindIndex: (name: string, columnName: string) => import("drizzle-orm/mysql-core").MySqlCustomColumnBuilder<{
|
|
50
|
+
name: string;
|
|
51
|
+
dataType: "custom";
|
|
52
|
+
columnType: "MySqlCustomColumn";
|
|
53
|
+
data: unknown;
|
|
54
|
+
driverParam: unknown;
|
|
55
|
+
enumValues: undefined;
|
|
56
|
+
}>;
|
|
57
|
+
sqliteBlindIndex: (name: string, columnName: string) => import("drizzle-orm/sqlite-core").SQLiteCustomColumnBuilder<{
|
|
58
|
+
name: string;
|
|
59
|
+
dataType: "custom";
|
|
60
|
+
columnType: "SQLiteCustomColumn";
|
|
61
|
+
data: unknown;
|
|
62
|
+
driverParam: unknown;
|
|
63
|
+
enumValues: undefined;
|
|
64
|
+
}>;
|
|
65
|
+
};
|
package/dist/drizzle.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
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
|
+
const security_1 = require("./security");
|
|
10
|
+
function getKeys(options) {
|
|
11
|
+
let keys;
|
|
12
|
+
let activeVersion;
|
|
13
|
+
if (Buffer.isBuffer(options.key)) {
|
|
14
|
+
keys = { '1': options.key };
|
|
15
|
+
activeVersion = '1';
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
keys = options.key;
|
|
19
|
+
activeVersion = options.activeKeyVersion || Object.keys(keys)[0];
|
|
20
|
+
}
|
|
21
|
+
return { keys, activeVersion };
|
|
22
|
+
}
|
|
23
|
+
const createDrizzleGuard = (options) => {
|
|
24
|
+
const { keys, activeVersion } = getKeys(options);
|
|
25
|
+
const activeKey = keys[activeVersion];
|
|
26
|
+
if (!activeKey) {
|
|
27
|
+
throw new Error(`Active encryption key version "${activeVersion}" is not present in the key map.`);
|
|
28
|
+
}
|
|
29
|
+
(0, security_1.registerKeysForZeroization)(keys);
|
|
30
|
+
const rootSalt = options.blindIndexes?.rootSalt;
|
|
31
|
+
return {
|
|
32
|
+
pgText: (name, columnPath) => (0, pg_core_1.customType)({
|
|
33
|
+
dataType() {
|
|
34
|
+
return 'text';
|
|
35
|
+
},
|
|
36
|
+
toDriver(value) {
|
|
37
|
+
return (0, prisma_1.encryptValue)(value, activeKey, activeVersion);
|
|
38
|
+
},
|
|
39
|
+
fromDriver(value) {
|
|
40
|
+
const parts = columnPath?.split('.') || [name];
|
|
41
|
+
const mName = parts[0] || 'Model';
|
|
42
|
+
const fName = parts[1] || name;
|
|
43
|
+
return (0, security_1.decryptWithSecurity)(value, (val) => (0, prisma_1.decryptValue)(val, keys), mName, fName, undefined, options);
|
|
44
|
+
}
|
|
45
|
+
})(name),
|
|
46
|
+
mysqlText: (name, columnPath) => (0, mysql_core_1.customType)({
|
|
47
|
+
dataType() {
|
|
48
|
+
return 'text';
|
|
49
|
+
},
|
|
50
|
+
toDriver(value) {
|
|
51
|
+
return (0, prisma_1.encryptValue)(value, activeKey, activeVersion);
|
|
52
|
+
},
|
|
53
|
+
fromDriver(value) {
|
|
54
|
+
const parts = columnPath?.split('.') || [name];
|
|
55
|
+
const mName = parts[0] || 'Model';
|
|
56
|
+
const fName = parts[1] || name;
|
|
57
|
+
return (0, security_1.decryptWithSecurity)(value, (val) => (0, prisma_1.decryptValue)(val, keys), mName, fName, undefined, options);
|
|
58
|
+
}
|
|
59
|
+
})(name),
|
|
60
|
+
sqliteText: (name, columnPath) => (0, sqlite_core_1.customType)({
|
|
61
|
+
dataType() {
|
|
62
|
+
return 'text';
|
|
63
|
+
},
|
|
64
|
+
toDriver(value) {
|
|
65
|
+
return (0, prisma_1.encryptValue)(value, activeKey, activeVersion);
|
|
66
|
+
},
|
|
67
|
+
fromDriver(value) {
|
|
68
|
+
const parts = columnPath?.split('.') || [name];
|
|
69
|
+
const mName = parts[0] || 'Model';
|
|
70
|
+
const fName = parts[1] || name;
|
|
71
|
+
return (0, security_1.decryptWithSecurity)(value, (val) => (0, prisma_1.decryptValue)(val, keys), mName, fName, undefined, options);
|
|
72
|
+
}
|
|
73
|
+
})(name),
|
|
74
|
+
pgBlindIndex: (name, columnName) => (0, pg_core_1.customType)({
|
|
75
|
+
dataType() {
|
|
76
|
+
return 'text';
|
|
77
|
+
},
|
|
78
|
+
toDriver(value) {
|
|
79
|
+
if (!rootSalt) {
|
|
80
|
+
throw new Error('Blind index root salt is not configured in Drizzle guard options.');
|
|
81
|
+
}
|
|
82
|
+
return (0, blind_index_1.computeBlindIndex)(value, rootSalt, columnName);
|
|
83
|
+
},
|
|
84
|
+
fromDriver(value) {
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
})(name),
|
|
88
|
+
mysqlBlindIndex: (name, columnName) => (0, mysql_core_1.customType)({
|
|
89
|
+
dataType() {
|
|
90
|
+
return 'text';
|
|
91
|
+
},
|
|
92
|
+
toDriver(value) {
|
|
93
|
+
if (!rootSalt) {
|
|
94
|
+
throw new Error('Blind index root salt is not configured in Drizzle guard options.');
|
|
95
|
+
}
|
|
96
|
+
return (0, blind_index_1.computeBlindIndex)(value, rootSalt, columnName);
|
|
97
|
+
},
|
|
98
|
+
fromDriver(value) {
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
})(name),
|
|
102
|
+
sqliteBlindIndex: (name, columnName) => (0, sqlite_core_1.customType)({
|
|
103
|
+
dataType() {
|
|
104
|
+
return 'text';
|
|
105
|
+
},
|
|
106
|
+
toDriver(value) {
|
|
107
|
+
if (!rootSalt) {
|
|
108
|
+
throw new Error('Blind index root salt is not configured in Drizzle guard options.');
|
|
109
|
+
}
|
|
110
|
+
return (0, blind_index_1.computeBlindIndex)(value, rootSalt, columnName);
|
|
111
|
+
},
|
|
112
|
+
fromDriver(value) {
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
})(name)
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
exports.createDrizzleGuard = createDrizzleGuard;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
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
|
+
export { KmsProvider, AwsKmsProvider, GcpKmsProvider, VaultKmsProvider, unwrapDekLocal, Pkcs11KmsProvider } from './kms';
|
|
6
|
+
export { computeBlindIndex } from './blind-index';
|
|
7
|
+
export { dbGuardContextStore, configureAuditLogger, decryptWithSecurity, checkRateLimit, checkPageSize, resetFailClosedStatusForTesting, resetAuditLoggerForTesting, getCachedKey, setCachedKey, resetSecureKeyCacheForTesting, configureBreakGlass, deactivateBreakGlass, isBreakGlassActive, getBreakGlassKey, activateBreakGlass, parseCiphertext, CRYPTO_ALGORITHMS, VERSION_ALGORITHMS } from './security';
|
|
8
|
+
export { auditConfiguration, generateComplianceHtmlReport, ComplianceAuditInput, ComplianceScorecard } from './compliance';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateComplianceHtmlReport = exports.auditConfiguration = 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;
|
|
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; } });
|
|
15
|
+
var kms_1 = require("./kms");
|
|
16
|
+
Object.defineProperty(exports, "AwsKmsProvider", { enumerable: true, get: function () { return kms_1.AwsKmsProvider; } });
|
|
17
|
+
Object.defineProperty(exports, "GcpKmsProvider", { enumerable: true, get: function () { return kms_1.GcpKmsProvider; } });
|
|
18
|
+
Object.defineProperty(exports, "VaultKmsProvider", { enumerable: true, get: function () { return kms_1.VaultKmsProvider; } });
|
|
19
|
+
Object.defineProperty(exports, "unwrapDekLocal", { enumerable: true, get: function () { return kms_1.unwrapDekLocal; } });
|
|
20
|
+
Object.defineProperty(exports, "Pkcs11KmsProvider", { enumerable: true, get: function () { return kms_1.Pkcs11KmsProvider; } });
|
|
21
|
+
var blind_index_1 = require("./blind-index");
|
|
22
|
+
Object.defineProperty(exports, "computeBlindIndex", { enumerable: true, get: function () { return blind_index_1.computeBlindIndex; } });
|
|
23
|
+
var security_1 = require("./security");
|
|
24
|
+
Object.defineProperty(exports, "dbGuardContextStore", { enumerable: true, get: function () { return security_1.dbGuardContextStore; } });
|
|
25
|
+
Object.defineProperty(exports, "configureAuditLogger", { enumerable: true, get: function () { return security_1.configureAuditLogger; } });
|
|
26
|
+
Object.defineProperty(exports, "decryptWithSecurity", { enumerable: true, get: function () { return security_1.decryptWithSecurity; } });
|
|
27
|
+
Object.defineProperty(exports, "checkRateLimit", { enumerable: true, get: function () { return security_1.checkRateLimit; } });
|
|
28
|
+
Object.defineProperty(exports, "checkPageSize", { enumerable: true, get: function () { return security_1.checkPageSize; } });
|
|
29
|
+
Object.defineProperty(exports, "resetFailClosedStatusForTesting", { enumerable: true, get: function () { return security_1.resetFailClosedStatusForTesting; } });
|
|
30
|
+
Object.defineProperty(exports, "resetAuditLoggerForTesting", { enumerable: true, get: function () { return security_1.resetAuditLoggerForTesting; } });
|
|
31
|
+
Object.defineProperty(exports, "getCachedKey", { enumerable: true, get: function () { return security_1.getCachedKey; } });
|
|
32
|
+
Object.defineProperty(exports, "setCachedKey", { enumerable: true, get: function () { return security_1.setCachedKey; } });
|
|
33
|
+
Object.defineProperty(exports, "resetSecureKeyCacheForTesting", { enumerable: true, get: function () { return security_1.resetSecureKeyCacheForTesting; } });
|
|
34
|
+
Object.defineProperty(exports, "configureBreakGlass", { enumerable: true, get: function () { return security_1.configureBreakGlass; } });
|
|
35
|
+
Object.defineProperty(exports, "deactivateBreakGlass", { enumerable: true, get: function () { return security_1.deactivateBreakGlass; } });
|
|
36
|
+
Object.defineProperty(exports, "isBreakGlassActive", { enumerable: true, get: function () { return security_1.isBreakGlassActive; } });
|
|
37
|
+
Object.defineProperty(exports, "getBreakGlassKey", { enumerable: true, get: function () { return security_1.getBreakGlassKey; } });
|
|
38
|
+
Object.defineProperty(exports, "activateBreakGlass", { enumerable: true, get: function () { return security_1.activateBreakGlass; } });
|
|
39
|
+
Object.defineProperty(exports, "parseCiphertext", { enumerable: true, get: function () { return security_1.parseCiphertext; } });
|
|
40
|
+
Object.defineProperty(exports, "CRYPTO_ALGORITHMS", { enumerable: true, get: function () { return security_1.CRYPTO_ALGORITHMS; } });
|
|
41
|
+
Object.defineProperty(exports, "VERSION_ALGORITHMS", { enumerable: true, get: function () { return security_1.VERSION_ALGORITHMS; } });
|
|
42
|
+
var compliance_1 = require("./compliance");
|
|
43
|
+
Object.defineProperty(exports, "auditConfiguration", { enumerable: true, get: function () { return compliance_1.auditConfiguration; } });
|
|
44
|
+
Object.defineProperty(exports, "generateComplianceHtmlReport", { enumerable: true, get: function () { return compliance_1.generateComplianceHtmlReport; } });
|
package/dist/kms.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export interface KmsProvider {
|
|
2
|
+
decrypt(ciphertext: Buffer): Promise<Buffer>;
|
|
3
|
+
}
|
|
4
|
+
export declare class AwsKmsProvider implements KmsProvider {
|
|
5
|
+
private config;
|
|
6
|
+
constructor(config: {
|
|
7
|
+
region: string;
|
|
8
|
+
keyId?: string;
|
|
9
|
+
credentials?: any;
|
|
10
|
+
});
|
|
11
|
+
decrypt(ciphertext: Buffer): Promise<Buffer>;
|
|
12
|
+
}
|
|
13
|
+
export declare class GcpKmsProvider implements KmsProvider {
|
|
14
|
+
private config;
|
|
15
|
+
constructor(config: {
|
|
16
|
+
keyName: string;
|
|
17
|
+
clientOptions?: any;
|
|
18
|
+
});
|
|
19
|
+
decrypt(ciphertext: Buffer): Promise<Buffer>;
|
|
20
|
+
}
|
|
21
|
+
export declare class VaultKmsProvider implements KmsProvider {
|
|
22
|
+
private config;
|
|
23
|
+
constructor(config: {
|
|
24
|
+
url: string;
|
|
25
|
+
token: string;
|
|
26
|
+
keyName: string;
|
|
27
|
+
});
|
|
28
|
+
decrypt(ciphertext: Buffer): Promise<Buffer>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Local Envelope Decryption wrapper using AES-256-Key-Wrap (AES-KW)
|
|
32
|
+
*/
|
|
33
|
+
export declare function unwrapDekLocal(wrappedDek: Buffer, unwrappedKek: Buffer): Buffer;
|
|
34
|
+
/**
|
|
35
|
+
* On-Premises HSM Provider using the standard PKCS#11 protocol
|
|
36
|
+
*/
|
|
37
|
+
export declare class Pkcs11KmsProvider implements KmsProvider {
|
|
38
|
+
private config;
|
|
39
|
+
constructor(config: {
|
|
40
|
+
libraryPath: string;
|
|
41
|
+
pin: string;
|
|
42
|
+
slotId?: number;
|
|
43
|
+
keyId: string;
|
|
44
|
+
});
|
|
45
|
+
decrypt(ciphertext: Buffer): Promise<Buffer>;
|
|
46
|
+
}
|
package/dist/kms.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Pkcs11KmsProvider = exports.VaultKmsProvider = exports.GcpKmsProvider = exports.AwsKmsProvider = void 0;
|
|
4
|
+
exports.unwrapDekLocal = unwrapDekLocal;
|
|
5
|
+
const security_1 = require("./security");
|
|
6
|
+
class AwsKmsProvider {
|
|
7
|
+
config;
|
|
8
|
+
constructor(config) {
|
|
9
|
+
this.config = config;
|
|
10
|
+
}
|
|
11
|
+
async decrypt(ciphertext) {
|
|
12
|
+
try {
|
|
13
|
+
const { KMSClient, DecryptCommand } = require('@aws-sdk/client-kms');
|
|
14
|
+
const client = new KMSClient(this.config);
|
|
15
|
+
const command = new DecryptCommand({
|
|
16
|
+
CiphertextBlob: ciphertext,
|
|
17
|
+
KeyId: this.config.keyId,
|
|
18
|
+
});
|
|
19
|
+
const res = await client.send(command);
|
|
20
|
+
if (!res.Plaintext) {
|
|
21
|
+
throw new Error('AWS KMS returned empty plaintext');
|
|
22
|
+
}
|
|
23
|
+
return Buffer.from(res.Plaintext);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
throw new Error(`AWS KMS decryption failed: ${err.message}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.AwsKmsProvider = AwsKmsProvider;
|
|
31
|
+
class GcpKmsProvider {
|
|
32
|
+
config;
|
|
33
|
+
constructor(config) {
|
|
34
|
+
this.config = config;
|
|
35
|
+
}
|
|
36
|
+
async decrypt(ciphertext) {
|
|
37
|
+
try {
|
|
38
|
+
const { KeyManagementServiceClient } = require('@google-cloud/kms');
|
|
39
|
+
const client = new KeyManagementServiceClient(this.config.clientOptions);
|
|
40
|
+
const [res] = await client.decrypt({
|
|
41
|
+
name: this.config.keyName,
|
|
42
|
+
ciphertext: ciphertext,
|
|
43
|
+
});
|
|
44
|
+
if (!res.plaintext) {
|
|
45
|
+
throw new Error('GCP KMS returned empty plaintext');
|
|
46
|
+
}
|
|
47
|
+
return Buffer.from(res.plaintext);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
throw new Error(`GCP KMS decryption failed: ${err.message}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.GcpKmsProvider = GcpKmsProvider;
|
|
55
|
+
class VaultKmsProvider {
|
|
56
|
+
config;
|
|
57
|
+
constructor(config) {
|
|
58
|
+
this.config = config;
|
|
59
|
+
}
|
|
60
|
+
async decrypt(ciphertext) {
|
|
61
|
+
try {
|
|
62
|
+
const vault = require('node-vault')({
|
|
63
|
+
endpoint: this.config.url,
|
|
64
|
+
token: this.config.token,
|
|
65
|
+
});
|
|
66
|
+
// Decrypt using Transit engine api
|
|
67
|
+
const payload = ciphertext.toString('utf8');
|
|
68
|
+
const res = await vault.customOp({
|
|
69
|
+
method: 'POST',
|
|
70
|
+
path: `/v1/transit/decrypt/${this.config.keyName}`,
|
|
71
|
+
data: { ciphertext: payload },
|
|
72
|
+
});
|
|
73
|
+
if (!res.data || !res.data.plaintext) {
|
|
74
|
+
throw new Error('HashiCorp Vault returned empty plaintext');
|
|
75
|
+
}
|
|
76
|
+
return Buffer.from(res.data.plaintext, 'base64');
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
throw new Error(`HashiCorp Vault decryption failed: ${err.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.VaultKmsProvider = VaultKmsProvider;
|
|
84
|
+
/**
|
|
85
|
+
* Local Envelope Decryption wrapper using AES-256-Key-Wrap (AES-KW)
|
|
86
|
+
*/
|
|
87
|
+
function unwrapDekLocal(wrappedDek, unwrappedKek) {
|
|
88
|
+
try {
|
|
89
|
+
return (0, security_1.unwrapKey)(unwrappedKek, wrappedDek);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
throw new Error(`Local AES-KW DEK unwrap failed: ${err.message}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* On-Premises HSM Provider using the standard PKCS#11 protocol
|
|
97
|
+
*/
|
|
98
|
+
class Pkcs11KmsProvider {
|
|
99
|
+
config;
|
|
100
|
+
constructor(config) {
|
|
101
|
+
this.config = config;
|
|
102
|
+
}
|
|
103
|
+
async decrypt(ciphertext) {
|
|
104
|
+
try {
|
|
105
|
+
// Lazy load pkcs11js
|
|
106
|
+
const pkcs11js = require('pkcs11js');
|
|
107
|
+
const pkcs11 = new pkcs11js.PKCS11();
|
|
108
|
+
pkcs11.load(this.config.libraryPath);
|
|
109
|
+
pkcs11.C_Initialize();
|
|
110
|
+
const slots = pkcs11.C_GetSlotList(true);
|
|
111
|
+
const slotIndex = this.config.slotId !== undefined ? this.config.slotId : 0;
|
|
112
|
+
if (!slots || slots.length <= slotIndex) {
|
|
113
|
+
throw new Error(`PKCS#11 slot index ${slotIndex} not found or slot list is empty.`);
|
|
114
|
+
}
|
|
115
|
+
const session = pkcs11.C_OpenSession(slots[slotIndex], pkcs11js.CKF_SERIAL_SESSION | pkcs11js.CKF_RW_SESSION);
|
|
116
|
+
pkcs11.C_Login(session, pkcs11js.CKU_USER, this.config.pin);
|
|
117
|
+
try {
|
|
118
|
+
const keyIdBuf = Buffer.from(this.config.keyId, 'hex');
|
|
119
|
+
pkcs11.C_FindObjectsInit(session, [
|
|
120
|
+
{ type: pkcs11js.CKA_CLASS, value: pkcs11js.CKO_SECRET_KEY },
|
|
121
|
+
{ type: pkcs11js.CKA_ID, value: keyIdBuf }
|
|
122
|
+
]);
|
|
123
|
+
const objects = pkcs11.C_FindObjects(session, 1);
|
|
124
|
+
pkcs11.C_FindObjectsFinal(session);
|
|
125
|
+
if (!objects || objects.length === 0) {
|
|
126
|
+
throw new Error(`Secret key with ID ${this.config.keyId} not found in HSM.`);
|
|
127
|
+
}
|
|
128
|
+
const keyHandle = objects[0];
|
|
129
|
+
// Extract 16-byte IV for CKM_AES_CBC_PAD, otherwise fallback to zeros
|
|
130
|
+
let iv = Buffer.alloc(16, 0);
|
|
131
|
+
let actualCiphertext = ciphertext;
|
|
132
|
+
if (ciphertext.length > 16) {
|
|
133
|
+
iv = ciphertext.subarray(0, 16);
|
|
134
|
+
actualCiphertext = ciphertext.subarray(16);
|
|
135
|
+
}
|
|
136
|
+
pkcs11.C_DecryptInit(session, {
|
|
137
|
+
mechanism: pkcs11js.CKM_AES_CBC_PAD,
|
|
138
|
+
parameter: iv
|
|
139
|
+
}, keyHandle);
|
|
140
|
+
const decrypted = pkcs11.C_Decrypt(session, actualCiphertext, Buffer.alloc(actualCiphertext.length + 16));
|
|
141
|
+
return Buffer.from(decrypted);
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
pkcs11.C_Logout(session);
|
|
145
|
+
pkcs11.C_CloseSession(session);
|
|
146
|
+
pkcs11.C_Finalize();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
throw new Error(`PKCS#11 HSM decryption failed: ${err.message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
exports.Pkcs11KmsProvider = Pkcs11KmsProvider;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Schema } from 'mongoose';
|
|
2
|
+
import { RateLimiterOptions } from './security';
|
|
3
|
+
export interface MongooseDbGuardOptions {
|
|
4
|
+
key: Buffer | Record<string, Buffer>;
|
|
5
|
+
activeKeyVersion?: string;
|
|
6
|
+
fields: string[];
|
|
7
|
+
blindIndexes?: {
|
|
8
|
+
rootSalt: Buffer;
|
|
9
|
+
fields: string[];
|
|
10
|
+
modelName?: string;
|
|
11
|
+
};
|
|
12
|
+
cryptoRbac?: {
|
|
13
|
+
roles: Record<string, {
|
|
14
|
+
decrypt: string[];
|
|
15
|
+
mask?: Record<string, 'credit_card' | 'email' | 'tc_no' | ((v: any) => any) | string>;
|
|
16
|
+
}>;
|
|
17
|
+
};
|
|
18
|
+
rateLimiter?: RateLimiterOptions;
|
|
19
|
+
multiTenant?: {
|
|
20
|
+
tenants?: Record<string, {
|
|
21
|
+
key?: Buffer | Record<string, Buffer>;
|
|
22
|
+
kms?: any;
|
|
23
|
+
}>;
|
|
24
|
+
getTenantConfig?: (tenantId: string) => Promise<{
|
|
25
|
+
key?: Buffer | Record<string, Buffer>;
|
|
26
|
+
kms?: any;
|
|
27
|
+
} | undefined>;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare function mongooseDbGuard(schema: Schema, options: MongooseDbGuardOptions): void;
|