@proteinjs/db 1.35.1 → 1.37.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/CHANGELOG.md +22 -0
- package/dist/generated/index.d.ts.map +1 -1
- package/dist/generated/index.js +7 -1
- package/dist/generated/index.js.map +1 -1
- package/dist/generated/test/index.d.ts.map +1 -1
- package/dist/generated/test/index.js +7 -1
- package/dist/generated/test/index.js.map +1 -1
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -1
- package/dist/src/Columns.d.ts +5 -1
- package/dist/src/Columns.d.ts.map +1 -1
- package/dist/src/Columns.js +2 -1
- package/dist/src/Columns.js.map +1 -1
- package/dist/src/Db.d.ts +25 -0
- package/dist/src/Db.d.ts.map +1 -1
- package/dist/src/Db.js +219 -22
- package/dist/src/Db.js.map +1 -1
- package/dist/src/Record.d.ts +7 -1
- package/dist/src/Record.d.ts.map +1 -1
- package/dist/src/Record.js +56 -21
- package/dist/src/Record.js.map +1 -1
- package/dist/src/Table.d.ts +82 -1
- package/dist/src/Table.d.ts.map +1 -1
- package/dist/src/Table.js +24 -1
- package/dist/src/Table.js.map +1 -1
- package/dist/src/TableQueryTransformProvider.d.ts +17 -0
- package/dist/src/TableQueryTransformProvider.d.ts.map +1 -0
- package/dist/src/TableQueryTransformProvider.js +34 -0
- package/dist/src/TableQueryTransformProvider.js.map +1 -0
- package/dist/src/encryption/Base64Url.d.ts +12 -0
- package/dist/src/encryption/Base64Url.d.ts.map +1 -0
- package/dist/src/encryption/Base64Url.js +21 -0
- package/dist/src/encryption/Base64Url.js.map +1 -0
- package/dist/src/encryption/DataEncryptionKeyTable.d.ts +33 -0
- package/dist/src/encryption/DataEncryptionKeyTable.d.ts.map +1 -0
- package/dist/src/encryption/DataEncryptionKeyTable.js +45 -0
- package/dist/src/encryption/DataEncryptionKeyTable.js.map +1 -0
- package/dist/src/encryption/DataKeyStore.d.ts +84 -0
- package/dist/src/encryption/DataKeyStore.d.ts.map +1 -0
- package/dist/src/encryption/DataKeyStore.js +481 -0
- package/dist/src/encryption/DataKeyStore.js.map +1 -0
- package/dist/src/encryption/DbEncryptionConfig.d.ts +62 -0
- package/dist/src/encryption/DbEncryptionConfig.d.ts.map +1 -0
- package/dist/src/encryption/DbEncryptionConfig.js +67 -0
- package/dist/src/encryption/DbEncryptionConfig.js.map +1 -0
- package/dist/src/encryption/EncryptedColumnQueryError.d.ts +10 -0
- package/dist/src/encryption/EncryptedColumnQueryError.d.ts.map +1 -0
- package/dist/src/encryption/EncryptedColumnQueryError.js +38 -0
- package/dist/src/encryption/EncryptedColumnQueryError.js.map +1 -0
- package/dist/src/encryption/EncryptedColumnQueryTransform.d.ts +52 -0
- package/dist/src/encryption/EncryptedColumnQueryTransform.d.ts.map +1 -0
- package/dist/src/encryption/EncryptedColumnQueryTransform.js +423 -0
- package/dist/src/encryption/EncryptedColumnQueryTransform.js.map +1 -0
- package/dist/src/encryption/EncryptedColumns.d.ts +69 -0
- package/dist/src/encryption/EncryptedColumns.d.ts.map +1 -0
- package/dist/src/encryption/EncryptedColumns.js +286 -0
- package/dist/src/encryption/EncryptedColumns.js.map +1 -0
- package/dist/src/encryption/EncryptionDerivedTableRegistry.d.ts +20 -0
- package/dist/src/encryption/EncryptionDerivedTableRegistry.d.ts.map +1 -0
- package/dist/src/encryption/EncryptionDerivedTableRegistry.js +36 -0
- package/dist/src/encryption/EncryptionDerivedTableRegistry.js.map +1 -0
- package/dist/src/encryption/EncryptionEnvelope.d.ts +25 -0
- package/dist/src/encryption/EncryptionEnvelope.d.ts.map +1 -0
- package/dist/src/encryption/EncryptionEnvelope.js +59 -0
- package/dist/src/encryption/EncryptionEnvelope.js.map +1 -0
- package/dist/src/encryption/EncryptionLifecycleWalker.d.ts +65 -0
- package/dist/src/encryption/EncryptionLifecycleWalker.d.ts.map +1 -0
- package/dist/src/encryption/EncryptionLifecycleWalker.js +343 -0
- package/dist/src/encryption/EncryptionLifecycleWalker.js.map +1 -0
- package/dist/src/encryption/EncryptionRecordHooks.d.ts +47 -0
- package/dist/src/encryption/EncryptionRecordHooks.d.ts.map +1 -0
- package/dist/src/encryption/EncryptionRecordHooks.js +229 -0
- package/dist/src/encryption/EncryptionRecordHooks.js.map +1 -0
- package/dist/src/encryption/EncryptionTokenMaintenance.d.ts +34 -0
- package/dist/src/encryption/EncryptionTokenMaintenance.d.ts.map +1 -0
- package/dist/src/encryption/EncryptionTokenMaintenance.js +211 -0
- package/dist/src/encryption/EncryptionTokenMaintenance.js.map +1 -0
- package/dist/src/encryption/InMemoryMasterKeyProvider.d.ts +20 -0
- package/dist/src/encryption/InMemoryMasterKeyProvider.d.ts.map +1 -0
- package/dist/src/encryption/InMemoryMasterKeyProvider.js +87 -0
- package/dist/src/encryption/InMemoryMasterKeyProvider.js.map +1 -0
- package/dist/src/encryption/MasterKeyProvider.d.ts +27 -0
- package/dist/src/encryption/MasterKeyProvider.d.ts.map +1 -0
- package/dist/src/encryption/MasterKeyProvider.js +3 -0
- package/dist/src/encryption/MasterKeyProvider.js.map +1 -0
- package/dist/src/encryption/SearchTokenizer.d.ts +49 -0
- package/dist/src/encryption/SearchTokenizer.d.ts.map +1 -0
- package/dist/src/encryption/SearchTokenizer.js +106 -0
- package/dist/src/encryption/SearchTokenizer.js.map +1 -0
- package/dist/src/schema/TableManager.d.ts +10 -0
- package/dist/src/schema/TableManager.d.ts.map +1 -1
- package/dist/src/schema/TableManager.js +62 -5
- package/dist/src/schema/TableManager.js.map +1 -1
- package/dist/src/tables/MigrationTable.d.ts +2 -2
- package/dist/test/EncryptedColumnsSchema.test.d.ts +2 -0
- package/dist/test/EncryptedColumnsSchema.test.d.ts.map +1 -0
- package/dist/test/EncryptedColumnsSchema.test.js +151 -0
- package/dist/test/EncryptedColumnsSchema.test.js.map +1 -0
- package/dist/test/EncryptionEnvelope.test.d.ts +2 -0
- package/dist/test/EncryptionEnvelope.test.d.ts.map +1 -0
- package/dist/test/EncryptionEnvelope.test.js +109 -0
- package/dist/test/EncryptionEnvelope.test.js.map +1 -0
- package/dist/test/EncryptionQueryContract.test.d.ts +2 -0
- package/dist/test/EncryptionQueryContract.test.d.ts.map +1 -0
- package/dist/test/EncryptionQueryContract.test.js +399 -0
- package/dist/test/EncryptionQueryContract.test.js.map +1 -0
- package/dist/test/SearchTokenizer.test.d.ts +2 -0
- package/dist/test/SearchTokenizer.test.d.ts.map +1 -0
- package/dist/test/SearchTokenizer.test.js +64 -0
- package/dist/test/SearchTokenizer.test.js.map +1 -0
- package/dist/test/reusable/CascadeDeleteTests.js +2 -2
- package/dist/test/reusable/CascadeDeleteTests.js.map +1 -1
- package/dist/test/reusable/ColumnTypesTests.js +2 -2
- package/dist/test/reusable/ColumnTypesTests.js.map +1 -1
- package/dist/test/reusable/CrudTests.js +2 -2
- package/dist/test/reusable/CrudTests.js.map +1 -1
- package/dist/test/reusable/DynamicReferenceColumnTests.js +2 -2
- package/dist/test/reusable/DynamicReferenceColumnTests.js.map +1 -1
- package/dist/test/reusable/PreloadReferencesTests.js +2 -2
- package/dist/test/reusable/PreloadReferencesTests.js.map +1 -1
- package/dist/test/reusable/RecordIteratorTests.js +2 -2
- package/dist/test/reusable/RecordIteratorTests.js.map +1 -1
- package/dist/test/reusable/TableManagerTests.js +2 -2
- package/dist/test/reusable/TableManagerTests.js.map +1 -1
- package/dist/test/reusable/TransactionTests.js +2 -2
- package/dist/test/reusable/TransactionTests.js.map +1 -1
- package/generated/index.ts +7 -1
- package/generated/test/index.ts +7 -1
- package/index.ts +16 -0
- package/package.json +3 -3
- package/src/Columns.ts +6 -2
- package/src/Db.ts +137 -12
- package/src/Record.ts +21 -4
- package/src/Table.ts +109 -2
- package/src/TableQueryTransformProvider.ts +31 -0
- package/src/encryption/Base64Url.ts +14 -0
- package/src/encryption/DataEncryptionKeyTable.ts +40 -0
- package/src/encryption/DataKeyStore.ts +305 -0
- package/src/encryption/DbEncryptionConfig.ts +92 -0
- package/src/encryption/EncryptedColumnQueryError.ts +15 -0
- package/src/encryption/EncryptedColumnQueryTransform.ts +383 -0
- package/src/encryption/EncryptedColumns.ts +318 -0
- package/src/encryption/EncryptionDerivedTableRegistry.ts +34 -0
- package/src/encryption/EncryptionEnvelope.ts +60 -0
- package/src/encryption/EncryptionLifecycleWalker.ts +243 -0
- package/src/encryption/EncryptionRecordHooks.ts +167 -0
- package/src/encryption/EncryptionTokenMaintenance.ts +123 -0
- package/src/encryption/InMemoryMasterKeyProvider.ts +42 -0
- package/src/encryption/MasterKeyProvider.ts +26 -0
- package/src/encryption/SearchTokenizer.ts +103 -0
- package/src/schema/TableManager.ts +43 -1
- package/test/EncryptedColumnsSchema.test.ts +172 -0
- package/test/EncryptionEnvelope.test.ts +66 -0
- package/test/EncryptionQueryContract.test.ts +195 -0
- package/test/SearchTokenizer.test.ts +67 -0
- package/test/reusable/CascadeDeleteTests.ts +2 -2
- package/test/reusable/ColumnTypesTests.ts +2 -2
- package/test/reusable/CrudTests.ts +2 -2
- package/test/reusable/DynamicReferenceColumnTests.ts +2 -2
- package/test/reusable/PreloadReferencesTests.ts +2 -2
- package/test/reusable/RecordIteratorTests.ts +2 -2
- package/test/reusable/TableManagerTests.ts +2 -2
- package/test/reusable/TransactionTests.ts +2 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { QueryBuilder } from '@proteinjs/db-query';
|
|
2
|
+
import type { Table } from '../Table';
|
|
3
|
+
import type { Record } from '../Record';
|
|
4
|
+
/**
|
|
5
|
+
* Search-token upkeep for `encrypted: { searchable: 'contains' }` columns: the same write
|
|
6
|
+
* that stores a row's ciphertext also derives the value's search tokens (words, trigrams,
|
|
7
|
+
* short prefixes — `SearchTokenizer`), fingerprints each with the row owner's index key,
|
|
8
|
+
* and maintains them as rows of the derived token table (`EncryptedColumns.tokenTableFor`)
|
|
9
|
+
* — the portable inverted index the query translator's candidate step reads.
|
|
10
|
+
*
|
|
11
|
+
* Invoked by `Db` around its DML (insert/update/delete), through a SYSTEM Db riding the
|
|
12
|
+
* same driver and ambient transaction — inside a transaction, token rows commit or roll
|
|
13
|
+
* back with the row; outside one, the token write follows the row write immediately.
|
|
14
|
+
*/
|
|
15
|
+
export declare class EncryptionTokenMaintenance {
|
|
16
|
+
private static readonly ID_CHUNK_SIZE;
|
|
17
|
+
private encryptedColumns;
|
|
18
|
+
private tokenizer;
|
|
19
|
+
/** Write token rows for the contains-searchable columns present in an inserted record. */
|
|
20
|
+
afterInsert(table: Table<any>, record: any, keyOwner: string, systemDb: TokenMaintenanceDb): Promise<void>;
|
|
21
|
+
/** Rewrite token rows of the touched contains-searchable columns for the updated row ids. */
|
|
22
|
+
afterUpdate(table: Table<any>, recordIds: string[], record: any, keyOwner: string, systemDb: TokenMaintenanceDb): Promise<void>;
|
|
23
|
+
/** Remove every token row of deleted records. */
|
|
24
|
+
afterDelete(table: Table<any>, deletedIds: string[], systemDb: TokenMaintenanceDb): Promise<void>;
|
|
25
|
+
private writeTokenRows;
|
|
26
|
+
private touchedContainsProps;
|
|
27
|
+
private chunk;
|
|
28
|
+
}
|
|
29
|
+
/** The Db surface token maintenance needs (a system Db instance — see class doc). */
|
|
30
|
+
export interface TokenMaintenanceDb {
|
|
31
|
+
insert<T extends Record>(table: Table<T>, record: Omit<T, keyof Record>): Promise<T>;
|
|
32
|
+
delete<T extends Record>(table: Table<T>, query: QueryBuilder<T>): Promise<number>;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=EncryptionTokenMaintenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EncryptionTokenMaintenance.d.ts","sourceRoot":"","sources":["../../../src/encryption/EncryptionTokenMaintenance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAKxC;;;;;;;;;;GAUG;AACH,qBAAa,0BAA0B;IACrC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAO;IAC5C,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,SAAS,CAAyB;IAE1C,0FAA0F;IACpF,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IAShH,6FAA6F;IACvF,WAAW,CACf,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EACjB,SAAS,EAAE,MAAM,EAAE,EACnB,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,IAAI,CAAC;IAkBhB,iDAAiD;IAC3C,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;YAgBzF,cAAc;IA6B5B,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,KAAK;CAQd;AAED,qFAAqF;AACrF,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACrF,MAAM,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACpF"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.EncryptionTokenMaintenance = void 0;
|
|
40
|
+
var db_query_1 = require("@proteinjs/db-query");
|
|
41
|
+
var EncryptedColumns_1 = require("./EncryptedColumns");
|
|
42
|
+
var DataKeyStore_1 = require("./DataKeyStore");
|
|
43
|
+
var SearchTokenizer_1 = require("./SearchTokenizer");
|
|
44
|
+
/**
|
|
45
|
+
* Search-token upkeep for `encrypted: { searchable: 'contains' }` columns: the same write
|
|
46
|
+
* that stores a row's ciphertext also derives the value's search tokens (words, trigrams,
|
|
47
|
+
* short prefixes — `SearchTokenizer`), fingerprints each with the row owner's index key,
|
|
48
|
+
* and maintains them as rows of the derived token table (`EncryptedColumns.tokenTableFor`)
|
|
49
|
+
* — the portable inverted index the query translator's candidate step reads.
|
|
50
|
+
*
|
|
51
|
+
* Invoked by `Db` around its DML (insert/update/delete), through a SYSTEM Db riding the
|
|
52
|
+
* same driver and ambient transaction — inside a transaction, token rows commit or roll
|
|
53
|
+
* back with the row; outside one, the token write follows the row write immediately.
|
|
54
|
+
*/
|
|
55
|
+
var EncryptionTokenMaintenance = /** @class */ (function () {
|
|
56
|
+
function EncryptionTokenMaintenance() {
|
|
57
|
+
this.encryptedColumns = new EncryptedColumns_1.EncryptedColumns();
|
|
58
|
+
this.tokenizer = new SearchTokenizer_1.SearchTokenizer();
|
|
59
|
+
}
|
|
60
|
+
/** Write token rows for the contains-searchable columns present in an inserted record. */
|
|
61
|
+
EncryptionTokenMaintenance.prototype.afterInsert = function (table, record, keyOwner, systemDb) {
|
|
62
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
63
|
+
var touched;
|
|
64
|
+
return __generator(this, function (_a) {
|
|
65
|
+
switch (_a.label) {
|
|
66
|
+
case 0:
|
|
67
|
+
touched = this.touchedContainsProps(table, record);
|
|
68
|
+
if (touched.length === 0) {
|
|
69
|
+
return [2 /*return*/];
|
|
70
|
+
}
|
|
71
|
+
return [4 /*yield*/, this.writeTokenRows(table, [record.id], record, touched, keyOwner, systemDb)];
|
|
72
|
+
case 1:
|
|
73
|
+
_a.sent();
|
|
74
|
+
return [2 /*return*/];
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
/** Rewrite token rows of the touched contains-searchable columns for the updated row ids. */
|
|
80
|
+
EncryptionTokenMaintenance.prototype.afterUpdate = function (table, recordIds, record, keyOwner, systemDb) {
|
|
81
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
82
|
+
var touched, tokenTable, touchedColumnNames, _i, _a, idsChunk, deleteQb;
|
|
83
|
+
return __generator(this, function (_b) {
|
|
84
|
+
switch (_b.label) {
|
|
85
|
+
case 0:
|
|
86
|
+
touched = this.touchedContainsProps(table, record);
|
|
87
|
+
if (touched.length === 0 || recordIds.length === 0) {
|
|
88
|
+
return [2 /*return*/];
|
|
89
|
+
}
|
|
90
|
+
tokenTable = this.encryptedColumns.tokenTableFor(table);
|
|
91
|
+
touchedColumnNames = touched.map(function (prop) { return table.columns[prop].name; });
|
|
92
|
+
_i = 0, _a = this.chunk(recordIds, EncryptionTokenMaintenance.ID_CHUNK_SIZE);
|
|
93
|
+
_b.label = 1;
|
|
94
|
+
case 1:
|
|
95
|
+
if (!(_i < _a.length)) return [3 /*break*/, 4];
|
|
96
|
+
idsChunk = _a[_i];
|
|
97
|
+
deleteQb = new db_query_1.QueryBuilder(tokenTable.name)
|
|
98
|
+
.condition({ field: 'recordId', operator: 'IN', value: idsChunk })
|
|
99
|
+
.condition({ field: 'columnName', operator: 'IN', value: touchedColumnNames });
|
|
100
|
+
return [4 /*yield*/, systemDb.delete(tokenTable, deleteQb)];
|
|
101
|
+
case 2:
|
|
102
|
+
_b.sent();
|
|
103
|
+
_b.label = 3;
|
|
104
|
+
case 3:
|
|
105
|
+
_i++;
|
|
106
|
+
return [3 /*break*/, 1];
|
|
107
|
+
case 4: return [4 /*yield*/, this.writeTokenRows(table, recordIds, record, touched, keyOwner, systemDb)];
|
|
108
|
+
case 5:
|
|
109
|
+
_b.sent();
|
|
110
|
+
return [2 /*return*/];
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
/** Remove every token row of deleted records. */
|
|
116
|
+
EncryptionTokenMaintenance.prototype.afterDelete = function (table, deletedIds, systemDb) {
|
|
117
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
118
|
+
var tokenTable, _i, _a, idsChunk, deleteQb;
|
|
119
|
+
return __generator(this, function (_b) {
|
|
120
|
+
switch (_b.label) {
|
|
121
|
+
case 0:
|
|
122
|
+
tokenTable = this.encryptedColumns.tokenTableFor(table);
|
|
123
|
+
if (!tokenTable || deletedIds.length === 0) {
|
|
124
|
+
return [2 /*return*/];
|
|
125
|
+
}
|
|
126
|
+
_i = 0, _a = this.chunk(deletedIds, EncryptionTokenMaintenance.ID_CHUNK_SIZE);
|
|
127
|
+
_b.label = 1;
|
|
128
|
+
case 1:
|
|
129
|
+
if (!(_i < _a.length)) return [3 /*break*/, 4];
|
|
130
|
+
idsChunk = _a[_i];
|
|
131
|
+
deleteQb = new db_query_1.QueryBuilder(tokenTable.name).condition({
|
|
132
|
+
field: 'recordId',
|
|
133
|
+
operator: 'IN',
|
|
134
|
+
value: idsChunk,
|
|
135
|
+
});
|
|
136
|
+
return [4 /*yield*/, systemDb.delete(tokenTable, deleteQb)];
|
|
137
|
+
case 2:
|
|
138
|
+
_b.sent();
|
|
139
|
+
_b.label = 3;
|
|
140
|
+
case 3:
|
|
141
|
+
_i++;
|
|
142
|
+
return [3 /*break*/, 1];
|
|
143
|
+
case 4: return [2 /*return*/];
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
EncryptionTokenMaintenance.prototype.writeTokenRows = function (table, recordIds, record, touchedProps, keyOwner, systemDb) {
|
|
149
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
150
|
+
var tokenTable, writeKey, _i, touchedProps_1, prop, value, columnName, fingerprints, _a, recordIds_1, recordId, _b, fingerprints_1, token;
|
|
151
|
+
return __generator(this, function (_c) {
|
|
152
|
+
switch (_c.label) {
|
|
153
|
+
case 0:
|
|
154
|
+
tokenTable = this.encryptedColumns.tokenTableFor(table);
|
|
155
|
+
return [4 /*yield*/, new DataKeyStore_1.DataKeyStore().getWriteKey(keyOwner)];
|
|
156
|
+
case 1:
|
|
157
|
+
writeKey = _c.sent();
|
|
158
|
+
_i = 0, touchedProps_1 = touchedProps;
|
|
159
|
+
_c.label = 2;
|
|
160
|
+
case 2:
|
|
161
|
+
if (!(_i < touchedProps_1.length)) return [3 /*break*/, 9];
|
|
162
|
+
prop = touchedProps_1[_i];
|
|
163
|
+
value = record[prop];
|
|
164
|
+
if (value === null) {
|
|
165
|
+
return [3 /*break*/, 8]; // null values carry no tokens
|
|
166
|
+
}
|
|
167
|
+
columnName = table.columns[prop].name;
|
|
168
|
+
fingerprints = this.tokenizer.fingerprints(this.tokenizer.tokensForValue(String(value)), writeKey.indexKey);
|
|
169
|
+
_a = 0, recordIds_1 = recordIds;
|
|
170
|
+
_c.label = 3;
|
|
171
|
+
case 3:
|
|
172
|
+
if (!(_a < recordIds_1.length)) return [3 /*break*/, 8];
|
|
173
|
+
recordId = recordIds_1[_a];
|
|
174
|
+
_b = 0, fingerprints_1 = fingerprints;
|
|
175
|
+
_c.label = 4;
|
|
176
|
+
case 4:
|
|
177
|
+
if (!(_b < fingerprints_1.length)) return [3 /*break*/, 7];
|
|
178
|
+
token = fingerprints_1[_b];
|
|
179
|
+
return [4 /*yield*/, systemDb.insert(tokenTable, { recordId: recordId, columnName: columnName, token: token })];
|
|
180
|
+
case 5:
|
|
181
|
+
_c.sent();
|
|
182
|
+
_c.label = 6;
|
|
183
|
+
case 6:
|
|
184
|
+
_b++;
|
|
185
|
+
return [3 /*break*/, 4];
|
|
186
|
+
case 7:
|
|
187
|
+
_a++;
|
|
188
|
+
return [3 /*break*/, 3];
|
|
189
|
+
case 8:
|
|
190
|
+
_i++;
|
|
191
|
+
return [3 /*break*/, 2];
|
|
192
|
+
case 9: return [2 /*return*/];
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
EncryptionTokenMaintenance.prototype.touchedContainsProps = function (table, record) {
|
|
198
|
+
return this.encryptedColumns.containsProps(table).filter(function (prop) { return typeof record[prop] !== 'undefined'; });
|
|
199
|
+
};
|
|
200
|
+
EncryptionTokenMaintenance.prototype.chunk = function (items, size) {
|
|
201
|
+
var chunks = [];
|
|
202
|
+
for (var i = 0; i < items.length; i += size) {
|
|
203
|
+
chunks.push(items.slice(i, i + size));
|
|
204
|
+
}
|
|
205
|
+
return chunks;
|
|
206
|
+
};
|
|
207
|
+
EncryptionTokenMaintenance.ID_CHUNK_SIZE = 500;
|
|
208
|
+
return EncryptionTokenMaintenance;
|
|
209
|
+
}());
|
|
210
|
+
exports.EncryptionTokenMaintenance = EncryptionTokenMaintenance;
|
|
211
|
+
//# sourceMappingURL=EncryptionTokenMaintenance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EncryptionTokenMaintenance.js","sourceRoot":"","sources":["../../../src/encryption/EncryptionTokenMaintenance.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gDAAmD;AAGnD,uDAA6E;AAC7E,+CAA8C;AAC9C,qDAAoD;AAEpD;;;;;;;;;;GAUG;AACH;IAAA;QAEU,qBAAgB,GAAG,IAAI,mCAAgB,EAAE,CAAC;QAC1C,cAAS,GAAG,IAAI,iCAAe,EAAE,CAAC;IA+F5C,CAAC;IA7FC,0FAA0F;IACpF,gDAAW,GAAjB,UAAkB,KAAiB,EAAE,MAAW,EAAE,QAAgB,EAAE,QAA4B;;;;;;wBACxF,OAAO,GAAG,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;wBACzD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE;4BACxB,sBAAO;yBACR;wBAED,qBAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAA;;wBAAlF,SAAkF,CAAC;;;;;KACpF;IAED,6FAA6F;IACvF,gDAAW,GAAjB,UACE,KAAiB,EACjB,SAAmB,EACnB,MAAW,EACX,QAAgB,EAChB,QAA4B;;;;;;wBAEtB,OAAO,GAAG,IAAI,CAAC,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;wBACzD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;4BAClD,sBAAO;yBACR;wBAEK,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,KAAK,CAAE,CAAC;wBACzD,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,UAAC,IAAI,IAAK,OAAE,KAAK,CAAC,OAAe,CAAC,IAAI,CAAsB,CAAC,IAAI,EAAvD,CAAuD,CAAC,CAAC;8BACpB,EAA/D,KAAA,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,0BAA0B,CAAC,aAAa,CAAC;;;6BAA/D,CAAA,cAA+D,CAAA;wBAA3E,QAAQ;wBACX,QAAQ,GAAG,IAAI,uBAAY,CAAwB,UAAU,CAAC,IAAI,CAAC;6BACtE,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;6BACjE,SAAS,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;wBACjF,qBAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAA;;wBAA3C,SAA2C,CAAC;;;wBAJvB,IAA+D,CAAA;;4BAOtF,qBAAM,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAA;;wBAAhF,SAAgF,CAAC;;;;;KAClF;IAED,iDAAiD;IAC3C,gDAAW,GAAjB,UAAkB,KAAiB,EAAE,UAAoB,EAAE,QAA4B;;;;;;wBAC/E,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;wBAC9D,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE;4BAC1C,sBAAO;yBACR;8BAEsF,EAAhE,KAAA,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,0BAA0B,CAAC,aAAa,CAAC;;;6BAAhE,CAAA,cAAgE,CAAA;wBAA5E,QAAQ;wBACX,QAAQ,GAAG,IAAI,uBAAY,CAAwB,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;4BAClF,KAAK,EAAE,UAAU;4BACjB,QAAQ,EAAE,IAAI;4BACd,KAAK,EAAE,QAAQ;yBAChB,CAAC,CAAC;wBACH,qBAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAA;;wBAA3C,SAA2C,CAAC;;;wBANvB,IAAgE,CAAA;;;;;;KAQxF;IAEa,mDAAc,GAA5B,UACE,KAAiB,EACjB,SAAmB,EACnB,MAAW,EACX,YAAsB,EACtB,QAAgB,EAChB,QAA4B;;;;;;wBAEtB,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,KAAK,CAAE,CAAC;wBAC9C,qBAAM,IAAI,2BAAY,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAA;;wBAAzD,QAAQ,GAAG,SAA8C;8BAChC,EAAZ,6BAAY;;;6BAAZ,CAAA,0BAAY,CAAA;wBAApB,IAAI;wBACP,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;wBAC3B,IAAI,KAAK,KAAK,IAAI,EAAE;4BAClB,wBAAS,CAAC,8BAA8B;yBACzC;wBAEK,UAAU,GAAK,KAAK,CAAC,OAAe,CAAC,IAAI,CAAsB,CAAC,IAAI,CAAC;wBACrE,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;8BAClF,EAAT,uBAAS;;;6BAAT,CAAA,uBAAS,CAAA;wBAArB,QAAQ;8BACe,EAAZ,6BAAY;;;6BAAZ,CAAA,0BAAY,CAAA;wBAArB,KAAK;wBACd,qBAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,QAAQ,UAAA,EAAE,UAAU,YAAA,EAAE,KAAK,OAAA,EAG9D,CAAC,EAAA;;wBAHF,SAGE,CAAC;;;wBAJe,IAAY,CAAA;;;wBADX,IAAS,CAAA;;;wBARf,IAAY,CAAA;;;;;;KAiBhC;IAEO,yDAAoB,GAA5B,UAA6B,KAAiB,EAAE,MAAW;QACzD,OAAO,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAC,IAAI,IAAK,OAAA,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,WAAW,EAAnC,CAAmC,CAAC,CAAC;IAC1G,CAAC;IAEO,0CAAK,GAAb,UAAiB,KAAU,EAAE,IAAY;QACvC,IAAM,MAAM,GAAU,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE;YAC3C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;SACvC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAhGuB,wCAAa,GAAG,GAAG,AAAN,CAAO;IAiG9C,iCAAC;CAAA,AAlGD,IAkGC;AAlGY,gEAA0B"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { MasterKeyProvider } from './MasterKeyProvider';
|
|
4
|
+
/**
|
|
5
|
+
* A `MasterKeyProvider` holding the master key in process memory. For tests and local
|
|
6
|
+
* development only — a production deployment keeps its master key in a vault
|
|
7
|
+
* (`GcpKmsMasterKeyProvider`), where the key material never enters the app process.
|
|
8
|
+
*
|
|
9
|
+
* Wraps with AES-256-GCM. Constructing with the same `secret` yields a provider that can
|
|
10
|
+
* unwrap keys wrapped by a previous instance (test fixtures across processes); constructing
|
|
11
|
+
* with no secret generates a random master key for the life of the process.
|
|
12
|
+
*/
|
|
13
|
+
export declare class InMemoryMasterKeyProvider implements MasterKeyProvider {
|
|
14
|
+
private masterKey;
|
|
15
|
+
constructor(secret?: string);
|
|
16
|
+
wrapDataKey(plaintextKeyMaterial: Buffer): Promise<string>;
|
|
17
|
+
unwrapDataKey(wrappedKeyMaterial: string): Promise<Buffer>;
|
|
18
|
+
getMasterKeyId(): string;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=InMemoryMasterKeyProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemoryMasterKeyProvider.d.ts","sourceRoot":"","sources":["../../../src/encryption/InMemoryMasterKeyProvider.ts"],"names":[],"mappings":";;AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD;;;;;;;;GAQG;AACH,qBAAa,yBAA0B,YAAW,iBAAiB;IACjE,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,CAAC,EAAE,MAAM;IAIrB,WAAW,CAAC,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQ1D,aAAa,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUhE,cAAc,IAAI,MAAM;CAGzB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
+
function step(op) {
|
|
16
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
+
switch (op[0]) {
|
|
21
|
+
case 0: case 1: t = op; break;
|
|
22
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
+
default:
|
|
26
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
+
if (t[2]) _.ops.pop();
|
|
31
|
+
_.trys.pop(); continue;
|
|
32
|
+
}
|
|
33
|
+
op = body.call(thisArg, _);
|
|
34
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.InMemoryMasterKeyProvider = void 0;
|
|
40
|
+
var crypto_1 = require("crypto");
|
|
41
|
+
var Base64Url_1 = require("./Base64Url");
|
|
42
|
+
/**
|
|
43
|
+
* A `MasterKeyProvider` holding the master key in process memory. For tests and local
|
|
44
|
+
* development only — a production deployment keeps its master key in a vault
|
|
45
|
+
* (`GcpKmsMasterKeyProvider`), where the key material never enters the app process.
|
|
46
|
+
*
|
|
47
|
+
* Wraps with AES-256-GCM. Constructing with the same `secret` yields a provider that can
|
|
48
|
+
* unwrap keys wrapped by a previous instance (test fixtures across processes); constructing
|
|
49
|
+
* with no secret generates a random master key for the life of the process.
|
|
50
|
+
*/
|
|
51
|
+
var InMemoryMasterKeyProvider = /** @class */ (function () {
|
|
52
|
+
function InMemoryMasterKeyProvider(secret) {
|
|
53
|
+
this.masterKey = secret ? (0, crypto_1.createHash)('sha256').update(secret).digest() : (0, crypto_1.randomBytes)(32);
|
|
54
|
+
}
|
|
55
|
+
InMemoryMasterKeyProvider.prototype.wrapDataKey = function (plaintextKeyMaterial) {
|
|
56
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
57
|
+
var iv, cipher, ciphertext, authTag;
|
|
58
|
+
return __generator(this, function (_a) {
|
|
59
|
+
iv = (0, crypto_1.randomBytes)(12);
|
|
60
|
+
cipher = (0, crypto_1.createCipheriv)('aes-256-gcm', this.masterKey, iv);
|
|
61
|
+
ciphertext = Buffer.concat([cipher.update(plaintextKeyMaterial), cipher.final()]);
|
|
62
|
+
authTag = cipher.getAuthTag();
|
|
63
|
+
return [2 /*return*/, Base64Url_1.Base64Url.encode(Buffer.concat([iv, authTag, ciphertext]))];
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
InMemoryMasterKeyProvider.prototype.unwrapDataKey = function (wrappedKeyMaterial) {
|
|
68
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
69
|
+
var bytes, iv, authTag, ciphertext, decipher;
|
|
70
|
+
return __generator(this, function (_a) {
|
|
71
|
+
bytes = Base64Url_1.Base64Url.decode(wrappedKeyMaterial);
|
|
72
|
+
iv = bytes.subarray(0, 12);
|
|
73
|
+
authTag = bytes.subarray(12, 28);
|
|
74
|
+
ciphertext = bytes.subarray(28);
|
|
75
|
+
decipher = (0, crypto_1.createDecipheriv)('aes-256-gcm', this.masterKey, iv);
|
|
76
|
+
decipher.setAuthTag(authTag);
|
|
77
|
+
return [2 /*return*/, Buffer.concat([decipher.update(ciphertext), decipher.final()])];
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
InMemoryMasterKeyProvider.prototype.getMasterKeyId = function () {
|
|
82
|
+
return 'in-memory';
|
|
83
|
+
};
|
|
84
|
+
return InMemoryMasterKeyProvider;
|
|
85
|
+
}());
|
|
86
|
+
exports.InMemoryMasterKeyProvider = InMemoryMasterKeyProvider;
|
|
87
|
+
//# sourceMappingURL=InMemoryMasterKeyProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InMemoryMasterKeyProvider.js","sourceRoot":"","sources":["../../../src/encryption/InMemoryMasterKeyProvider.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iCAAmF;AACnF,yCAAwC;AAGxC;;;;;;;;GAQG;AACH;IAGE,mCAAY,MAAe;QACzB,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC;IAC3F,CAAC;IAEK,+CAAW,GAAjB,UAAkB,oBAA4B;;;;gBACtC,EAAE,GAAG,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC;gBACrB,MAAM,GAAG,IAAA,uBAAc,EAAC,aAAa,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBAC3D,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAClF,OAAO,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;gBACpC,sBAAO,qBAAS,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,EAAC;;;KACnE;IAEK,iDAAa,GAAnB,UAAoB,kBAA0B;;;;gBACtC,KAAK,GAAG,qBAAS,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC;gBAC7C,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC3B,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBACjC,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;gBAChC,QAAQ,GAAG,IAAA,yBAAgB,EAAC,aAAa,EAAE,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;gBACrE,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBAC7B,sBAAO,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAC;;;KACvE;IAED,kDAAc,GAAd;QACE,OAAO,WAAW,CAAC;IACrB,CAAC;IACH,gCAAC;AAAD,CAAC,AA5BD,IA4BC;AA5BY,8DAAyB"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/**
|
|
4
|
+
* The master-key seam of column encryption (see `EncryptedColumnConfig`).
|
|
5
|
+
*
|
|
6
|
+
* One master key exists per deployment, held in a key vault (Cloud KMS in production, an
|
|
7
|
+
* in-memory key in tests). The master key never encrypts row data directly — it wraps
|
|
8
|
+
* (encrypts) each user's randomly generated data key, and those per-user data keys encrypt
|
|
9
|
+
* the rows in that user's scope. The vault is therefore called once per data key
|
|
10
|
+
* (unwrap-once-per-key caching lives in `DataKeyStore`), never per row.
|
|
11
|
+
*
|
|
12
|
+
* Implementations:
|
|
13
|
+
* - `InMemoryMasterKeyProvider` (this package) — tests and local development.
|
|
14
|
+
* - `GcpKmsMasterKeyProvider` (`@proteinjs/db-encryption-driver-gcp-kms`) — Cloud KMS.
|
|
15
|
+
*/
|
|
16
|
+
export interface MasterKeyProvider {
|
|
17
|
+
/**
|
|
18
|
+
* Encrypt (wrap) raw data-key material under the master key.
|
|
19
|
+
* @returns an opaque string safe to store in the data-key table
|
|
20
|
+
*/
|
|
21
|
+
wrapDataKey(plaintextKeyMaterial: Buffer): Promise<string>;
|
|
22
|
+
/** Decrypt (unwrap) previously wrapped data-key material. */
|
|
23
|
+
unwrapDataKey(wrappedKeyMaterial: string): Promise<Buffer>;
|
|
24
|
+
/** Stable identifier of the master key (a KMS resource name, or 'in-memory') — observability only. */
|
|
25
|
+
getMasterKeyId(): string;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=MasterKeyProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MasterKeyProvider.d.ts","sourceRoot":"","sources":["../../../src/encryption/MasterKeyProvider.ts"],"names":[],"mappings":";;AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,WAAW,CAAC,oBAAoB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE3D,6DAA6D;IAC7D,aAAa,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE3D,sGAAsG;IACtG,cAAc,IAAI,MAAM,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MasterKeyProvider.js","sourceRoot":"","sources":["../../../src/encryption/MasterKeyProvider.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
/**
|
|
4
|
+
* Search tokens and keyed fingerprints for encrypted columns
|
|
5
|
+
* (`encrypted: { searchable: 'contains' | 'equality' }`).
|
|
6
|
+
*
|
|
7
|
+
* Definitions:
|
|
8
|
+
* - **Search token** — a normalized fragment of a text value: its lowercased words, each
|
|
9
|
+
* word's trigrams (three-letter fragments), and each word's 1- and 2-letter prefixes
|
|
10
|
+
* (so 1–2 character queries behave as word-prefix search).
|
|
11
|
+
* - **Keyed fingerprint (HMAC-SHA256)** — computable only with the owner's index key
|
|
12
|
+
* (`DataKeyMaterial.indexKey`); without it, stored fingerprints can be neither created
|
|
13
|
+
* nor reversed, so raw database access cannot probe ("does any title contain X?").
|
|
14
|
+
*
|
|
15
|
+
* Query-side cover: a candidate row must hold ALL of the query's fragment fingerprints.
|
|
16
|
+
* The cover can over-match (fragments present but not contiguous) and — for query words of
|
|
17
|
+
* ≥3 characters — can never under-match; the query layer verifies every candidate against
|
|
18
|
+
* the decrypted value before returning it (the pg_trgm recheck semantics), so results are
|
|
19
|
+
* exact. Documented narrowing: a 1–2 character query WORD matches word beginnings only
|
|
20
|
+
* (a 1–2 character mid-word substring is unsupported and behaves as prefix search).
|
|
21
|
+
*
|
|
22
|
+
* Equality fingerprints cover the EXACT serialized value (no normalization): `=` keeps its
|
|
23
|
+
* native case-sensitive semantics with no recheck, and a unique index on the fingerprint
|
|
24
|
+
* column enforces per-owner value uniqueness.
|
|
25
|
+
*/
|
|
26
|
+
export declare class SearchTokenizer {
|
|
27
|
+
/** All write-side tokens of `value` (deduplicated, un-fingerprinted). */
|
|
28
|
+
tokensForValue(value: string): string[];
|
|
29
|
+
/**
|
|
30
|
+
* The query-side fragment cover of `query`: for each query word, its trigrams (≥3 chars)
|
|
31
|
+
* or its prefix token (1–2 chars). Every fragment must match for a row to be a candidate.
|
|
32
|
+
*/
|
|
33
|
+
fragmentsForQuery(query: string): string[];
|
|
34
|
+
/** Keyed fingerprint of one token. */
|
|
35
|
+
fingerprint(token: string, indexKey: Buffer): string;
|
|
36
|
+
fingerprints(tokens: string[], indexKey: Buffer): string[];
|
|
37
|
+
/** Whole-value equality fingerprint — over the exact serialized value (see class doc). */
|
|
38
|
+
equalityFingerprint(value: string, indexKey: Buffer): string;
|
|
39
|
+
/**
|
|
40
|
+
* The declared bounded reveal for `encrypted: { sortKey: { revealPrefix: N } }`: the
|
|
41
|
+
* normalized (lowercased) first N characters, stored beside the ciphertext for native
|
|
42
|
+
* ORDER BY. Raw database access can read those N characters — the declared, documented
|
|
43
|
+
* leak, chosen at the schema, never the default.
|
|
44
|
+
*/
|
|
45
|
+
sortPrefix(value: string, revealPrefix: number): string;
|
|
46
|
+
private words;
|
|
47
|
+
private trigrams;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=SearchTokenizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchTokenizer.d.ts","sourceRoot":"","sources":["../../../src/encryption/SearchTokenizer.ts"],"names":[],"mappings":";;AAGA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,eAAe;IAC1B,yEAAyE;IACzE,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAgBvC;;;OAGG;IACH,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAe1C,sCAAsC;IACtC,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIpD,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IAI1D,0FAA0F;IAC1F,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI5D;;;;;OAKG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAIvD,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,QAAQ;CAQjB"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SearchTokenizer = void 0;
|
|
4
|
+
var crypto_1 = require("crypto");
|
|
5
|
+
var Base64Url_1 = require("./Base64Url");
|
|
6
|
+
/**
|
|
7
|
+
* Search tokens and keyed fingerprints for encrypted columns
|
|
8
|
+
* (`encrypted: { searchable: 'contains' | 'equality' }`).
|
|
9
|
+
*
|
|
10
|
+
* Definitions:
|
|
11
|
+
* - **Search token** — a normalized fragment of a text value: its lowercased words, each
|
|
12
|
+
* word's trigrams (three-letter fragments), and each word's 1- and 2-letter prefixes
|
|
13
|
+
* (so 1–2 character queries behave as word-prefix search).
|
|
14
|
+
* - **Keyed fingerprint (HMAC-SHA256)** — computable only with the owner's index key
|
|
15
|
+
* (`DataKeyMaterial.indexKey`); without it, stored fingerprints can be neither created
|
|
16
|
+
* nor reversed, so raw database access cannot probe ("does any title contain X?").
|
|
17
|
+
*
|
|
18
|
+
* Query-side cover: a candidate row must hold ALL of the query's fragment fingerprints.
|
|
19
|
+
* The cover can over-match (fragments present but not contiguous) and — for query words of
|
|
20
|
+
* ≥3 characters — can never under-match; the query layer verifies every candidate against
|
|
21
|
+
* the decrypted value before returning it (the pg_trgm recheck semantics), so results are
|
|
22
|
+
* exact. Documented narrowing: a 1–2 character query WORD matches word beginnings only
|
|
23
|
+
* (a 1–2 character mid-word substring is unsupported and behaves as prefix search).
|
|
24
|
+
*
|
|
25
|
+
* Equality fingerprints cover the EXACT serialized value (no normalization): `=` keeps its
|
|
26
|
+
* native case-sensitive semantics with no recheck, and a unique index on the fingerprint
|
|
27
|
+
* column enforces per-owner value uniqueness.
|
|
28
|
+
*/
|
|
29
|
+
var SearchTokenizer = /** @class */ (function () {
|
|
30
|
+
function SearchTokenizer() {
|
|
31
|
+
}
|
|
32
|
+
/** All write-side tokens of `value` (deduplicated, un-fingerprinted). */
|
|
33
|
+
SearchTokenizer.prototype.tokensForValue = function (value) {
|
|
34
|
+
var tokens = new Set();
|
|
35
|
+
for (var _i = 0, _a = this.words(value); _i < _a.length; _i++) {
|
|
36
|
+
var word = _a[_i];
|
|
37
|
+
tokens.add("w:".concat(word));
|
|
38
|
+
tokens.add("p:".concat(word.slice(0, 1)));
|
|
39
|
+
if (word.length >= 2) {
|
|
40
|
+
tokens.add("p:".concat(word.slice(0, 2)));
|
|
41
|
+
}
|
|
42
|
+
for (var _b = 0, _c = this.trigrams(word); _b < _c.length; _b++) {
|
|
43
|
+
var trigram = _c[_b];
|
|
44
|
+
tokens.add("t:".concat(trigram));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return Array.from(tokens);
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* The query-side fragment cover of `query`: for each query word, its trigrams (≥3 chars)
|
|
51
|
+
* or its prefix token (1–2 chars). Every fragment must match for a row to be a candidate.
|
|
52
|
+
*/
|
|
53
|
+
SearchTokenizer.prototype.fragmentsForQuery = function (query) {
|
|
54
|
+
var fragments = new Set();
|
|
55
|
+
for (var _i = 0, _a = this.words(query); _i < _a.length; _i++) {
|
|
56
|
+
var word = _a[_i];
|
|
57
|
+
if (word.length >= 3) {
|
|
58
|
+
for (var _b = 0, _c = this.trigrams(word); _b < _c.length; _b++) {
|
|
59
|
+
var trigram = _c[_b];
|
|
60
|
+
fragments.add("t:".concat(trigram));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
fragments.add("p:".concat(word));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return Array.from(fragments);
|
|
68
|
+
};
|
|
69
|
+
/** Keyed fingerprint of one token. */
|
|
70
|
+
SearchTokenizer.prototype.fingerprint = function (token, indexKey) {
|
|
71
|
+
return Base64Url_1.Base64Url.encode((0, crypto_1.createHmac)('sha256', indexKey).update(token, 'utf8').digest());
|
|
72
|
+
};
|
|
73
|
+
SearchTokenizer.prototype.fingerprints = function (tokens, indexKey) {
|
|
74
|
+
var _this = this;
|
|
75
|
+
return tokens.map(function (token) { return _this.fingerprint(token, indexKey); });
|
|
76
|
+
};
|
|
77
|
+
/** Whole-value equality fingerprint — over the exact serialized value (see class doc). */
|
|
78
|
+
SearchTokenizer.prototype.equalityFingerprint = function (value, indexKey) {
|
|
79
|
+
return Base64Url_1.Base64Url.encode((0, crypto_1.createHmac)('sha256', indexKey).update("eq:".concat(value), 'utf8').digest());
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* The declared bounded reveal for `encrypted: { sortKey: { revealPrefix: N } }`: the
|
|
83
|
+
* normalized (lowercased) first N characters, stored beside the ciphertext for native
|
|
84
|
+
* ORDER BY. Raw database access can read those N characters — the declared, documented
|
|
85
|
+
* leak, chosen at the schema, never the default.
|
|
86
|
+
*/
|
|
87
|
+
SearchTokenizer.prototype.sortPrefix = function (value, revealPrefix) {
|
|
88
|
+
return value.toLowerCase().slice(0, revealPrefix);
|
|
89
|
+
};
|
|
90
|
+
SearchTokenizer.prototype.words = function (text) {
|
|
91
|
+
return text
|
|
92
|
+
.toLowerCase()
|
|
93
|
+
.split(/[^\p{L}\p{N}]+/u)
|
|
94
|
+
.filter(function (word) { return word.length > 0; });
|
|
95
|
+
};
|
|
96
|
+
SearchTokenizer.prototype.trigrams = function (word) {
|
|
97
|
+
var trigrams = [];
|
|
98
|
+
for (var i = 0; i + 3 <= word.length; i++) {
|
|
99
|
+
trigrams.push(word.slice(i, i + 3));
|
|
100
|
+
}
|
|
101
|
+
return trigrams;
|
|
102
|
+
};
|
|
103
|
+
return SearchTokenizer;
|
|
104
|
+
}());
|
|
105
|
+
exports.SearchTokenizer = SearchTokenizer;
|
|
106
|
+
//# sourceMappingURL=SearchTokenizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SearchTokenizer.js","sourceRoot":"","sources":["../../../src/encryption/SearchTokenizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,6 +40,16 @@ export declare class TableManager {
|
|
|
40
40
|
*/
|
|
41
41
|
loadTables(): Promise<void>;
|
|
42
42
|
loadTable(table: Table<any>): Promise<void>;
|
|
43
|
+
private loadSingleTable;
|
|
44
|
+
/**
|
|
45
|
+
* Column-encryption schema pass (`ColumnOptions.encrypted`): validate declarations,
|
|
46
|
+
* inject the derived companion columns, and append each table's derived search-token
|
|
47
|
+
* table so it is created/altered alongside its base table. When the deployment turns on
|
|
48
|
+
* `requireEncryptedDeclarations` (or `DB_REQUIRE_ENCRYPTED_DECLARATIONS=true`), every
|
|
49
|
+
* text-holding column must declare `encrypted` — registration fails loudly here otherwise.
|
|
50
|
+
*/
|
|
51
|
+
private prepareTablesForLoad;
|
|
52
|
+
private requireEncryptedDeclarations;
|
|
43
53
|
private alterTableIfChanged;
|
|
44
54
|
/**
|
|
45
55
|
* Reconcile a create/alter DDL failure against a concurrent schema change, closing the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableManager.d.ts","sourceRoot":"","sources":["../../../src/schema/TableManager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAoC,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAgB,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"TableManager.d.ts","sourceRoot":"","sources":["../../../src/schema/TableManager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAoC,MAAM,UAAU,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAgB,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAMjC;;;;;GAKG;AACH,qBAAa,kCAAmC,SAAQ,KAAK;gBAC/C,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,eAAe,EAAE,OAAO,EAAE;IAYhF,MAAM,CAAC,QAAQ,CAAC,mBAAmB,MAAM;CAC1C;AAKD,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC;CAC3C;AAED,qBAAa,YAAY;IACvB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAK;IACtD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,+BAA+B,CAAO;IAC9D,OAAO,CAAC,MAAM,CAA2F;IACzG,OAAO,CAAC,QAAQ,CAAW;IACpB,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,cAAc,EAAE,cAAc,CAAC;gBAGpC,QAAQ,EAAE,QAAQ,EAClB,iBAAiB,EAAE,iBAAiB,EACpC,gBAAgB,EAAE,gBAAgB,EAClC,cAAc,CAAC,EAAE,cAAc;IAQ3B,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC;IAInC;;;;;;OAMG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA4B3B,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAMnC,eAAe;IAgB7B;;;;;;OAMG;IACH,OAAO,CAAC,oBAAoB;IAmB5B,OAAO,CAAC,4BAA4B;YAQtB,mBAAmB;IAcjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;YACW,+BAA+B;IAiB7C;;;;;;;;;;;OAWG;YACW,wBAAwB;IAyCtC;sEACkE;IAClE,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,+BAA+B;IAwDvC,OAAO,CAAC,gBAAgB;YAgBV,eAAe;YA6Ff,kBAAkB;IA+ChC;;;;;;;OAOG;YACW,6BAA6B;IAe3C;;;;OAIG;YACW,uBAAuB;CAyCtC"}
|