@proteinjs/db 1.35.0 → 1.36.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.
Files changed (161) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/generated/index.d.ts.map +1 -1
  3. package/dist/generated/index.js +7 -1
  4. package/dist/generated/index.js.map +1 -1
  5. package/dist/generated/test/index.d.ts.map +1 -1
  6. package/dist/generated/test/index.js +7 -1
  7. package/dist/generated/test/index.js.map +1 -1
  8. package/dist/index.d.ts +15 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +15 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/src/Db.d.ts +25 -0
  13. package/dist/src/Db.d.ts.map +1 -1
  14. package/dist/src/Db.js +219 -22
  15. package/dist/src/Db.js.map +1 -1
  16. package/dist/src/Record.d.ts +7 -1
  17. package/dist/src/Record.d.ts.map +1 -1
  18. package/dist/src/Record.js +56 -21
  19. package/dist/src/Record.js.map +1 -1
  20. package/dist/src/Table.d.ts +82 -1
  21. package/dist/src/Table.d.ts.map +1 -1
  22. package/dist/src/Table.js +24 -1
  23. package/dist/src/Table.js.map +1 -1
  24. package/dist/src/TableQueryTransformProvider.d.ts +17 -0
  25. package/dist/src/TableQueryTransformProvider.d.ts.map +1 -0
  26. package/dist/src/TableQueryTransformProvider.js +34 -0
  27. package/dist/src/TableQueryTransformProvider.js.map +1 -0
  28. package/dist/src/encryption/Base64Url.d.ts +12 -0
  29. package/dist/src/encryption/Base64Url.d.ts.map +1 -0
  30. package/dist/src/encryption/Base64Url.js +21 -0
  31. package/dist/src/encryption/Base64Url.js.map +1 -0
  32. package/dist/src/encryption/DataEncryptionKeyTable.d.ts +33 -0
  33. package/dist/src/encryption/DataEncryptionKeyTable.d.ts.map +1 -0
  34. package/dist/src/encryption/DataEncryptionKeyTable.js +45 -0
  35. package/dist/src/encryption/DataEncryptionKeyTable.js.map +1 -0
  36. package/dist/src/encryption/DataKeyStore.d.ts +84 -0
  37. package/dist/src/encryption/DataKeyStore.d.ts.map +1 -0
  38. package/dist/src/encryption/DataKeyStore.js +481 -0
  39. package/dist/src/encryption/DataKeyStore.js.map +1 -0
  40. package/dist/src/encryption/DbEncryptionConfig.d.ts +62 -0
  41. package/dist/src/encryption/DbEncryptionConfig.d.ts.map +1 -0
  42. package/dist/src/encryption/DbEncryptionConfig.js +67 -0
  43. package/dist/src/encryption/DbEncryptionConfig.js.map +1 -0
  44. package/dist/src/encryption/EncryptedColumnQueryError.d.ts +10 -0
  45. package/dist/src/encryption/EncryptedColumnQueryError.d.ts.map +1 -0
  46. package/dist/src/encryption/EncryptedColumnQueryError.js +38 -0
  47. package/dist/src/encryption/EncryptedColumnQueryError.js.map +1 -0
  48. package/dist/src/encryption/EncryptedColumnQueryTransform.d.ts +52 -0
  49. package/dist/src/encryption/EncryptedColumnQueryTransform.d.ts.map +1 -0
  50. package/dist/src/encryption/EncryptedColumnQueryTransform.js +423 -0
  51. package/dist/src/encryption/EncryptedColumnQueryTransform.js.map +1 -0
  52. package/dist/src/encryption/EncryptedColumns.d.ts +69 -0
  53. package/dist/src/encryption/EncryptedColumns.d.ts.map +1 -0
  54. package/dist/src/encryption/EncryptedColumns.js +286 -0
  55. package/dist/src/encryption/EncryptedColumns.js.map +1 -0
  56. package/dist/src/encryption/EncryptionDerivedTableRegistry.d.ts +20 -0
  57. package/dist/src/encryption/EncryptionDerivedTableRegistry.d.ts.map +1 -0
  58. package/dist/src/encryption/EncryptionDerivedTableRegistry.js +36 -0
  59. package/dist/src/encryption/EncryptionDerivedTableRegistry.js.map +1 -0
  60. package/dist/src/encryption/EncryptionEnvelope.d.ts +25 -0
  61. package/dist/src/encryption/EncryptionEnvelope.d.ts.map +1 -0
  62. package/dist/src/encryption/EncryptionEnvelope.js +59 -0
  63. package/dist/src/encryption/EncryptionEnvelope.js.map +1 -0
  64. package/dist/src/encryption/EncryptionLifecycleWalker.d.ts +65 -0
  65. package/dist/src/encryption/EncryptionLifecycleWalker.d.ts.map +1 -0
  66. package/dist/src/encryption/EncryptionLifecycleWalker.js +343 -0
  67. package/dist/src/encryption/EncryptionLifecycleWalker.js.map +1 -0
  68. package/dist/src/encryption/EncryptionRecordHooks.d.ts +47 -0
  69. package/dist/src/encryption/EncryptionRecordHooks.d.ts.map +1 -0
  70. package/dist/src/encryption/EncryptionRecordHooks.js +229 -0
  71. package/dist/src/encryption/EncryptionRecordHooks.js.map +1 -0
  72. package/dist/src/encryption/EncryptionTokenMaintenance.d.ts +34 -0
  73. package/dist/src/encryption/EncryptionTokenMaintenance.d.ts.map +1 -0
  74. package/dist/src/encryption/EncryptionTokenMaintenance.js +211 -0
  75. package/dist/src/encryption/EncryptionTokenMaintenance.js.map +1 -0
  76. package/dist/src/encryption/InMemoryMasterKeyProvider.d.ts +20 -0
  77. package/dist/src/encryption/InMemoryMasterKeyProvider.d.ts.map +1 -0
  78. package/dist/src/encryption/InMemoryMasterKeyProvider.js +87 -0
  79. package/dist/src/encryption/InMemoryMasterKeyProvider.js.map +1 -0
  80. package/dist/src/encryption/MasterKeyProvider.d.ts +27 -0
  81. package/dist/src/encryption/MasterKeyProvider.d.ts.map +1 -0
  82. package/dist/src/encryption/MasterKeyProvider.js +3 -0
  83. package/dist/src/encryption/MasterKeyProvider.js.map +1 -0
  84. package/dist/src/encryption/SearchTokenizer.d.ts +49 -0
  85. package/dist/src/encryption/SearchTokenizer.d.ts.map +1 -0
  86. package/dist/src/encryption/SearchTokenizer.js +106 -0
  87. package/dist/src/encryption/SearchTokenizer.js.map +1 -0
  88. package/dist/src/schema/TableManager.d.ts +10 -0
  89. package/dist/src/schema/TableManager.d.ts.map +1 -1
  90. package/dist/src/schema/TableManager.js +62 -5
  91. package/dist/src/schema/TableManager.js.map +1 -1
  92. package/dist/src/tables/MigrationTable.d.ts +2 -2
  93. package/dist/test/EncryptedColumnsSchema.test.d.ts +2 -0
  94. package/dist/test/EncryptedColumnsSchema.test.d.ts.map +1 -0
  95. package/dist/test/EncryptedColumnsSchema.test.js +151 -0
  96. package/dist/test/EncryptedColumnsSchema.test.js.map +1 -0
  97. package/dist/test/EncryptionEnvelope.test.d.ts +2 -0
  98. package/dist/test/EncryptionEnvelope.test.d.ts.map +1 -0
  99. package/dist/test/EncryptionEnvelope.test.js +109 -0
  100. package/dist/test/EncryptionEnvelope.test.js.map +1 -0
  101. package/dist/test/EncryptionQueryContract.test.d.ts +2 -0
  102. package/dist/test/EncryptionQueryContract.test.d.ts.map +1 -0
  103. package/dist/test/EncryptionQueryContract.test.js +399 -0
  104. package/dist/test/EncryptionQueryContract.test.js.map +1 -0
  105. package/dist/test/SearchTokenizer.test.d.ts +2 -0
  106. package/dist/test/SearchTokenizer.test.d.ts.map +1 -0
  107. package/dist/test/SearchTokenizer.test.js +64 -0
  108. package/dist/test/SearchTokenizer.test.js.map +1 -0
  109. package/dist/test/reusable/CascadeDeleteTests.js +2 -2
  110. package/dist/test/reusable/CascadeDeleteTests.js.map +1 -1
  111. package/dist/test/reusable/ColumnTypesTests.js +2 -2
  112. package/dist/test/reusable/ColumnTypesTests.js.map +1 -1
  113. package/dist/test/reusable/CrudTests.js +2 -2
  114. package/dist/test/reusable/CrudTests.js.map +1 -1
  115. package/dist/test/reusable/DynamicReferenceColumnTests.js +2 -2
  116. package/dist/test/reusable/DynamicReferenceColumnTests.js.map +1 -1
  117. package/dist/test/reusable/PreloadReferencesTests.js +2 -2
  118. package/dist/test/reusable/PreloadReferencesTests.js.map +1 -1
  119. package/dist/test/reusable/RecordIteratorTests.js +2 -2
  120. package/dist/test/reusable/RecordIteratorTests.js.map +1 -1
  121. package/dist/test/reusable/TableManagerTests.js +2 -2
  122. package/dist/test/reusable/TableManagerTests.js.map +1 -1
  123. package/dist/test/reusable/TransactionTests.js +2 -2
  124. package/dist/test/reusable/TransactionTests.js.map +1 -1
  125. package/generated/index.ts +7 -1
  126. package/generated/test/index.ts +7 -1
  127. package/index.ts +16 -0
  128. package/package.json +3 -3
  129. package/src/Db.ts +137 -12
  130. package/src/Record.ts +21 -4
  131. package/src/Table.ts +109 -2
  132. package/src/TableQueryTransformProvider.ts +31 -0
  133. package/src/encryption/Base64Url.ts +14 -0
  134. package/src/encryption/DataEncryptionKeyTable.ts +40 -0
  135. package/src/encryption/DataKeyStore.ts +305 -0
  136. package/src/encryption/DbEncryptionConfig.ts +92 -0
  137. package/src/encryption/EncryptedColumnQueryError.ts +15 -0
  138. package/src/encryption/EncryptedColumnQueryTransform.ts +383 -0
  139. package/src/encryption/EncryptedColumns.ts +318 -0
  140. package/src/encryption/EncryptionDerivedTableRegistry.ts +34 -0
  141. package/src/encryption/EncryptionEnvelope.ts +60 -0
  142. package/src/encryption/EncryptionLifecycleWalker.ts +243 -0
  143. package/src/encryption/EncryptionRecordHooks.ts +167 -0
  144. package/src/encryption/EncryptionTokenMaintenance.ts +123 -0
  145. package/src/encryption/InMemoryMasterKeyProvider.ts +42 -0
  146. package/src/encryption/MasterKeyProvider.ts +26 -0
  147. package/src/encryption/SearchTokenizer.ts +103 -0
  148. package/src/schema/TableManager.ts +43 -1
  149. package/test/EncryptedColumnsSchema.test.ts +172 -0
  150. package/test/EncryptionEnvelope.test.ts +66 -0
  151. package/test/EncryptionQueryContract.test.ts +195 -0
  152. package/test/SearchTokenizer.test.ts +67 -0
  153. package/test/reusable/CascadeDeleteTests.ts +2 -2
  154. package/test/reusable/ColumnTypesTests.ts +2 -2
  155. package/test/reusable/CrudTests.ts +2 -2
  156. package/test/reusable/DynamicReferenceColumnTests.ts +2 -2
  157. package/test/reusable/PreloadReferencesTests.ts +2 -2
  158. package/test/reusable/RecordIteratorTests.ts +2 -2
  159. package/test/reusable/TableManagerTests.ts +2 -2
  160. package/test/reusable/TransactionTests.ts +2 -2
  161. package/tsconfig.json +1 -1
@@ -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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=MasterKeyProvider.js.map
@@ -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;AAIjC;;;;;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;YAgBnC,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"}
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"}