@proteinjs/db 1.35.1 → 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.
- package/CHANGELOG.md +11 -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/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/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,343 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __assign = (this && this.__assign) || function () {
|
|
3
|
+
__assign = Object.assign || function(t) {
|
|
4
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
5
|
+
s = arguments[i];
|
|
6
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
7
|
+
t[p] = s[p];
|
|
8
|
+
}
|
|
9
|
+
return t;
|
|
10
|
+
};
|
|
11
|
+
return __assign.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
37
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
38
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
39
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
40
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
41
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
42
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
46
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
47
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
48
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
49
|
+
function step(op) {
|
|
50
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
51
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
52
|
+
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;
|
|
53
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
54
|
+
switch (op[0]) {
|
|
55
|
+
case 0: case 1: t = op; break;
|
|
56
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
57
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
58
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
59
|
+
default:
|
|
60
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
61
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
62
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
63
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
64
|
+
if (t[2]) _.ops.pop();
|
|
65
|
+
_.trys.pop(); continue;
|
|
66
|
+
}
|
|
67
|
+
op = body.call(thisArg, _);
|
|
68
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
69
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
73
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
74
|
+
if (ar || !(i in from)) {
|
|
75
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
76
|
+
ar[i] = from[i];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
80
|
+
};
|
|
81
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
82
|
+
exports.EncryptionLifecycleWalker = void 0;
|
|
83
|
+
var db_query_1 = require("@proteinjs/db-query");
|
|
84
|
+
var logger_1 = require("@proteinjs/logger");
|
|
85
|
+
var EncryptedColumns_1 = require("./EncryptedColumns");
|
|
86
|
+
var EncryptionEnvelope_1 = require("./EncryptionEnvelope");
|
|
87
|
+
var DataKeyStore_1 = require("./DataKeyStore");
|
|
88
|
+
/**
|
|
89
|
+
* The reusable ONLINE backfill behind every encrypted-column config transition (and key
|
|
90
|
+
* rotation) — the migration-runner pattern: a server-side, id-ordered, windowed table walk
|
|
91
|
+
* that rewrites pending rows THROUGH the normal write seam (so encryption, companions, and
|
|
92
|
+
* search tokens all derive exactly as a live write would).
|
|
93
|
+
*
|
|
94
|
+
* Idempotent and resumable by construction: pending-ness is detected from the stored value
|
|
95
|
+
* itself (envelope or not, version current or not), so a re-run — after a crash, or just to
|
|
96
|
+
* be sure — skips completed rows and continues. Rows written by live traffic mid-walk are
|
|
97
|
+
* already in the new shape and skip too. Run it from a `Migration.run()` for deploy-coupled
|
|
98
|
+
* transitions.
|
|
99
|
+
*/
|
|
100
|
+
var EncryptionLifecycleWalker = /** @class */ (function () {
|
|
101
|
+
function EncryptionLifecycleWalker() {
|
|
102
|
+
this.logger = new logger_1.Logger({ name: this.constructor.name });
|
|
103
|
+
this.encryptedColumns = new EncryptedColumns_1.EncryptedColumns();
|
|
104
|
+
this.envelope = new EncryptionEnvelope_1.EncryptionEnvelope();
|
|
105
|
+
}
|
|
106
|
+
EncryptionLifecycleWalker.prototype.walkTable = function (table, mode, options) {
|
|
107
|
+
var _a, _b, _c;
|
|
108
|
+
if (options === void 0) { options = {}; }
|
|
109
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
110
|
+
var props, _d, Db, getDbAsSystem, dbDriver, db, windowSize, columnNames, activeVersionByOwner, summary, cursor, rawRows, _i, rawRows_1, rawRow, pendingProps, _e, columnNames_1, _f, prop, columnName;
|
|
111
|
+
return __generator(this, function (_g) {
|
|
112
|
+
switch (_g.label) {
|
|
113
|
+
case 0:
|
|
114
|
+
this.encryptedColumns.ensureSchema(table);
|
|
115
|
+
props = this.resolveProps(table, mode, options);
|
|
116
|
+
return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require('../Db')); })];
|
|
117
|
+
case 1:
|
|
118
|
+
_d = _g.sent(), Db = _d.Db, getDbAsSystem = _d.getDbAsSystem;
|
|
119
|
+
dbDriver = (_a = options.dbDriver) !== null && _a !== void 0 ? _a : Db.getDefaultDbDriver();
|
|
120
|
+
db = (_b = options.db) !== null && _b !== void 0 ? _b : getDbAsSystem();
|
|
121
|
+
windowSize = (_c = options.windowSize) !== null && _c !== void 0 ? _c : EncryptionLifecycleWalker.DEFAULT_WINDOW_SIZE;
|
|
122
|
+
columnNames = props.map(function (prop) { return ({
|
|
123
|
+
prop: prop,
|
|
124
|
+
columnName: table.columns[prop].name,
|
|
125
|
+
}); });
|
|
126
|
+
activeVersionByOwner = new Map();
|
|
127
|
+
summary = { scanned: 0, rewritten: 0 };
|
|
128
|
+
cursor = options.startAfterId;
|
|
129
|
+
_g.label = 2;
|
|
130
|
+
case 2:
|
|
131
|
+
if (!true) return [3 /*break*/, 12];
|
|
132
|
+
return [4 /*yield*/, this.rawWindow(table, dbDriver, columnNames, cursor, windowSize)];
|
|
133
|
+
case 3:
|
|
134
|
+
rawRows = _g.sent();
|
|
135
|
+
if (rawRows.length === 0) {
|
|
136
|
+
return [3 /*break*/, 12];
|
|
137
|
+
}
|
|
138
|
+
_i = 0, rawRows_1 = rawRows;
|
|
139
|
+
_g.label = 4;
|
|
140
|
+
case 4:
|
|
141
|
+
if (!(_i < rawRows_1.length)) return [3 /*break*/, 11];
|
|
142
|
+
rawRow = rawRows_1[_i];
|
|
143
|
+
summary.scanned++;
|
|
144
|
+
pendingProps = [];
|
|
145
|
+
_e = 0, columnNames_1 = columnNames;
|
|
146
|
+
_g.label = 5;
|
|
147
|
+
case 5:
|
|
148
|
+
if (!(_e < columnNames_1.length)) return [3 /*break*/, 8];
|
|
149
|
+
_f = columnNames_1[_e], prop = _f.prop, columnName = _f.columnName;
|
|
150
|
+
return [4 /*yield*/, this.isPending(mode, rawRow[columnName], activeVersionByOwner)];
|
|
151
|
+
case 6:
|
|
152
|
+
if (_g.sent()) {
|
|
153
|
+
pendingProps.push(prop);
|
|
154
|
+
}
|
|
155
|
+
_g.label = 7;
|
|
156
|
+
case 7:
|
|
157
|
+
_e++;
|
|
158
|
+
return [3 /*break*/, 5];
|
|
159
|
+
case 8:
|
|
160
|
+
if (pendingProps.length === 0) {
|
|
161
|
+
return [3 /*break*/, 10];
|
|
162
|
+
}
|
|
163
|
+
return [4 /*yield*/, this.rewriteRow(table, db, rawRow['id'], pendingProps)];
|
|
164
|
+
case 9:
|
|
165
|
+
_g.sent();
|
|
166
|
+
summary.rewritten++;
|
|
167
|
+
_g.label = 10;
|
|
168
|
+
case 10:
|
|
169
|
+
_i++;
|
|
170
|
+
return [3 /*break*/, 4];
|
|
171
|
+
case 11:
|
|
172
|
+
cursor = rawRows[rawRows.length - 1]['id'];
|
|
173
|
+
if (rawRows.length < windowSize) {
|
|
174
|
+
return [3 /*break*/, 12];
|
|
175
|
+
}
|
|
176
|
+
return [3 /*break*/, 2];
|
|
177
|
+
case 12:
|
|
178
|
+
if (!(mode === 'decrypt')) return [3 /*break*/, 14];
|
|
179
|
+
return [4 /*yield*/, this.sweepTokenRows(table, db, columnNames.map(function (_a) {
|
|
180
|
+
var columnName = _a.columnName;
|
|
181
|
+
return columnName;
|
|
182
|
+
}))];
|
|
183
|
+
case 13:
|
|
184
|
+
_g.sent();
|
|
185
|
+
_g.label = 14;
|
|
186
|
+
case 14:
|
|
187
|
+
this.logger.info({
|
|
188
|
+
message: "Encryption lifecycle walk finished",
|
|
189
|
+
obj: __assign({ table: table.name, mode: mode }, summary),
|
|
190
|
+
});
|
|
191
|
+
return [2 /*return*/, summary];
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
EncryptionLifecycleWalker.prototype.isPending = function (mode, rawValue, activeVersionByOwner) {
|
|
197
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
198
|
+
var parsed, _a, activeVersion;
|
|
199
|
+
return __generator(this, function (_b) {
|
|
200
|
+
switch (_b.label) {
|
|
201
|
+
case 0:
|
|
202
|
+
if (rawValue === null || typeof rawValue === 'undefined') {
|
|
203
|
+
return [2 /*return*/, false];
|
|
204
|
+
}
|
|
205
|
+
parsed = this.envelope.parse(rawValue);
|
|
206
|
+
_a = mode;
|
|
207
|
+
switch (_a) {
|
|
208
|
+
case 'encrypt': return [3 /*break*/, 1];
|
|
209
|
+
case 'retokenize': return [3 /*break*/, 2];
|
|
210
|
+
case 'decrypt': return [3 /*break*/, 3];
|
|
211
|
+
case 'rotate-keys': return [3 /*break*/, 4];
|
|
212
|
+
}
|
|
213
|
+
return [3 /*break*/, 7];
|
|
214
|
+
case 1: return [2 /*return*/, !parsed];
|
|
215
|
+
case 2: return [2 /*return*/, true];
|
|
216
|
+
case 3: return [2 /*return*/, !!parsed];
|
|
217
|
+
case 4:
|
|
218
|
+
if (!parsed) {
|
|
219
|
+
return [2 /*return*/, true]; // plaintext straggler — encrypt under the current key
|
|
220
|
+
}
|
|
221
|
+
activeVersion = activeVersionByOwner.get(parsed.owner);
|
|
222
|
+
if (!(typeof activeVersion === 'undefined')) return [3 /*break*/, 6];
|
|
223
|
+
return [4 /*yield*/, new DataKeyStore_1.DataKeyStore().getWriteKey(parsed.owner)];
|
|
224
|
+
case 5:
|
|
225
|
+
activeVersion = (_b.sent()).version;
|
|
226
|
+
activeVersionByOwner.set(parsed.owner, activeVersion);
|
|
227
|
+
_b.label = 6;
|
|
228
|
+
case 6: return [2 /*return*/, parsed.version < activeVersion];
|
|
229
|
+
case 7: return [2 /*return*/];
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* Rewrite one row through the normal seam: read it (the deserialize hook decrypts — or
|
|
236
|
+
* passes plaintext through, the adoption path), write the pending columns back (the
|
|
237
|
+
* serialize hook re-derives ciphertext, companions, and tokens under the current config).
|
|
238
|
+
*/
|
|
239
|
+
EncryptionLifecycleWalker.prototype.rewriteRow = function (table, db, id, pendingProps) {
|
|
240
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
241
|
+
var row, payload, _i, pendingProps_1, prop;
|
|
242
|
+
return __generator(this, function (_a) {
|
|
243
|
+
switch (_a.label) {
|
|
244
|
+
case 0: return [4 /*yield*/, db.get(table, { id: id })];
|
|
245
|
+
case 1:
|
|
246
|
+
row = _a.sent();
|
|
247
|
+
if (!row) {
|
|
248
|
+
return [2 /*return*/]; // deleted mid-walk
|
|
249
|
+
}
|
|
250
|
+
payload = { id: id };
|
|
251
|
+
for (_i = 0, pendingProps_1 = pendingProps; _i < pendingProps_1.length; _i++) {
|
|
252
|
+
prop = pendingProps_1[_i];
|
|
253
|
+
if (typeof row[prop] !== 'undefined') {
|
|
254
|
+
payload[prop] = row[prop];
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (Object.keys(payload).length === 1) {
|
|
258
|
+
return [2 /*return*/];
|
|
259
|
+
}
|
|
260
|
+
return [4 /*yield*/, db.update(table, payload)];
|
|
261
|
+
case 2:
|
|
262
|
+
_a.sent();
|
|
263
|
+
return [2 /*return*/];
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
/** Raw (un-deserialized) id-ordered window — pending-ness must see stored bytes, not decrypted values. */
|
|
269
|
+
EncryptionLifecycleWalker.prototype.rawWindow = function (table, dbDriver, columnNames, cursor, windowSize) {
|
|
270
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
271
|
+
var StatementConfigFactory, statementConfigFactory, qb;
|
|
272
|
+
return __generator(this, function (_a) {
|
|
273
|
+
switch (_a.label) {
|
|
274
|
+
case 0: return [4 /*yield*/, Promise.resolve().then(function () { return __importStar(require('../StatementConfigFactory')); })];
|
|
275
|
+
case 1:
|
|
276
|
+
StatementConfigFactory = (_a.sent()).StatementConfigFactory;
|
|
277
|
+
statementConfigFactory = new StatementConfigFactory(dbDriver.getDbName());
|
|
278
|
+
qb = new db_query_1.QueryBuilder(table.name).select({ fields: __spreadArray(['id'], columnNames.map(function (_a) {
|
|
279
|
+
var prop = _a.prop;
|
|
280
|
+
return prop;
|
|
281
|
+
}), true) });
|
|
282
|
+
if (cursor) {
|
|
283
|
+
qb.condition({ field: 'id', operator: '>', value: cursor });
|
|
284
|
+
}
|
|
285
|
+
qb.sort([{ field: 'id' }]).paginate({ start: 0, end: windowSize });
|
|
286
|
+
return [4 /*yield*/, dbDriver.runQuery(function (config) { return qb.toSql(statementConfigFactory.getStatementConfig(config)); })];
|
|
287
|
+
case 2: return [2 /*return*/, _a.sent()];
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
};
|
|
292
|
+
/** After decrypt-out, the decrypted columns' token rows are stale — sweep them. */
|
|
293
|
+
EncryptionLifecycleWalker.prototype.sweepTokenRows = function (table, db, columnNames) {
|
|
294
|
+
var _a;
|
|
295
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
296
|
+
var tokenTable, deleteQb;
|
|
297
|
+
return __generator(this, function (_b) {
|
|
298
|
+
switch (_b.label) {
|
|
299
|
+
case 0:
|
|
300
|
+
tokenTable = (_a = this.encryptedColumns.tokenTableFor(table)) !== null && _a !== void 0 ? _a : this.encryptedColumns.tokenTableShape(table);
|
|
301
|
+
return [4 /*yield*/, db.tableExists(tokenTable)];
|
|
302
|
+
case 1:
|
|
303
|
+
if (!(_b.sent())) {
|
|
304
|
+
return [2 /*return*/];
|
|
305
|
+
}
|
|
306
|
+
deleteQb = new db_query_1.QueryBuilder(tokenTable.name).condition({
|
|
307
|
+
field: 'columnName',
|
|
308
|
+
operator: 'IN',
|
|
309
|
+
value: columnNames,
|
|
310
|
+
});
|
|
311
|
+
return [4 /*yield*/, db.delete(tokenTable, deleteQb)];
|
|
312
|
+
case 2:
|
|
313
|
+
_b.sent();
|
|
314
|
+
return [2 /*return*/];
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
};
|
|
319
|
+
EncryptionLifecycleWalker.prototype.resolveProps = function (table, mode, options) {
|
|
320
|
+
if (options.columns && options.columns.length > 0) {
|
|
321
|
+
for (var _i = 0, _a = options.columns; _i < _a.length; _i++) {
|
|
322
|
+
var prop = _a[_i];
|
|
323
|
+
if (!table.columns[prop]) {
|
|
324
|
+
throw new Error("(".concat(table.name, ") Unknown column property to walk: ").concat(prop));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return options.columns;
|
|
328
|
+
}
|
|
329
|
+
if (mode === 'decrypt') {
|
|
330
|
+
throw new Error("Mode 'decrypt' requires options.columns: after the config flips to encrypted: false, the " +
|
|
331
|
+
"declaration no longer names the columns to decrypt.");
|
|
332
|
+
}
|
|
333
|
+
var props = this.encryptedColumns.encryptedProps(table);
|
|
334
|
+
if (props.length === 0) {
|
|
335
|
+
throw new Error("(".concat(table.name, ") No encrypted columns declared \u2014 nothing to walk."));
|
|
336
|
+
}
|
|
337
|
+
return props;
|
|
338
|
+
};
|
|
339
|
+
EncryptionLifecycleWalker.DEFAULT_WINDOW_SIZE = 200;
|
|
340
|
+
return EncryptionLifecycleWalker;
|
|
341
|
+
}());
|
|
342
|
+
exports.EncryptionLifecycleWalker = EncryptionLifecycleWalker;
|
|
343
|
+
//# sourceMappingURL=EncryptionLifecycleWalker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EncryptionLifecycleWalker.js","sourceRoot":"","sources":["../../../src/encryption/EncryptionLifecycleWalker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Table } from '../Table';
|
|
2
|
+
import type { SerializedRecord } from '../Record';
|
|
3
|
+
/** Who a row being written belongs to — the data key its values encrypt under. */
|
|
4
|
+
export type EncryptionWriteContext = {
|
|
5
|
+
keyOwner: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* The transparent encrypt/decrypt seam, invoked by `RecordSerializer` on every write's
|
|
9
|
+
* serialize and every read's deserialize — the same per-column hook layer every caller
|
|
10
|
+
* already passes through, so services, watchers, migrations, and queued client
|
|
11
|
+
* transactions get encryption without knowing it exists.
|
|
12
|
+
*
|
|
13
|
+
* - Serialize: after the columns' own `serialize` steps, values of encrypted columns are
|
|
14
|
+
* replaced with self-describing envelopes (`EncryptionEnvelope`), and the searchable /
|
|
15
|
+
* sort companions are written beside them in the same statement.
|
|
16
|
+
* - Deserialize: before the columns' own `deserialize` steps, envelope values are decrypted
|
|
17
|
+
* (the envelope names its key — owner + version — so no context is needed) and
|
|
18
|
+
* framework-derived companion columns are dropped. A non-envelope value in an encrypted
|
|
19
|
+
* column passes through unchanged — the online-adoption transition: rows written before
|
|
20
|
+
* the encrypt backfill stay readable while the walker converges them.
|
|
21
|
+
*
|
|
22
|
+
* Server-only: this seam executes where the database driver runs. Browser code proxies
|
|
23
|
+
* through `DbService` and receives decrypted values over the authenticated service.
|
|
24
|
+
*/
|
|
25
|
+
export declare class EncryptionRecordHooks {
|
|
26
|
+
private encryptedColumns;
|
|
27
|
+
private envelope;
|
|
28
|
+
private tokenizer;
|
|
29
|
+
/** Encrypt encrypted-column values in `serialized` (column-name-keyed) and add companions. */
|
|
30
|
+
onSerialize(table: Table<any>, serialized: SerializedRecord, context?: EncryptionWriteContext): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* A copy of `serializedRecord` with framework companion columns dropped and every
|
|
33
|
+
* envelope value decrypted (any column — self-describing ciphertext also covers the
|
|
34
|
+
* decrypt-out transition, where the config no longer marks the column).
|
|
35
|
+
*/
|
|
36
|
+
onDeserialize(table: Table<any>, serializedRecord: SerializedRecord): Promise<SerializedRecord>;
|
|
37
|
+
/**
|
|
38
|
+
* The key owner for a row being written — its permission-source scope owner:
|
|
39
|
+
* `DbEncryptionConfig.resolveKeyOwner` when the deployment supplies one (richer sharing
|
|
40
|
+
* models map scope→owner there), else the row's `scope` column value (the framework's
|
|
41
|
+
* scope columns hold the owning user's id).
|
|
42
|
+
*/
|
|
43
|
+
resolveKeyOwnerForWrite(table: Table<any>, record: any): Promise<string>;
|
|
44
|
+
private internalColumnNames;
|
|
45
|
+
private assertServerSide;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=EncryptionRecordHooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EncryptionRecordHooks.d.ts","sourceRoot":"","sources":["../../../src/encryption/EncryptionRecordHooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAOlD,kFAAkF;AAClF,MAAM,MAAM,sBAAsB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAE1D;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,gBAAgB,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,SAAS,CAAyB;IAE1C,8FAA8F;IACxF,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDnH;;;;OAIG;IACG,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,gBAAgB,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA0BrG;;;;;OAKG;IACG,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAoB9E,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,gBAAgB;CAQzB"}
|
|
@@ -0,0 +1,229 @@
|
|
|
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.EncryptionRecordHooks = void 0;
|
|
40
|
+
var DbEncryptionConfig_1 = require("./DbEncryptionConfig");
|
|
41
|
+
var EncryptedColumns_1 = require("./EncryptedColumns");
|
|
42
|
+
var EncryptionEnvelope_1 = require("./EncryptionEnvelope");
|
|
43
|
+
var DataKeyStore_1 = require("./DataKeyStore");
|
|
44
|
+
var SearchTokenizer_1 = require("./SearchTokenizer");
|
|
45
|
+
/**
|
|
46
|
+
* The transparent encrypt/decrypt seam, invoked by `RecordSerializer` on every write's
|
|
47
|
+
* serialize and every read's deserialize — the same per-column hook layer every caller
|
|
48
|
+
* already passes through, so services, watchers, migrations, and queued client
|
|
49
|
+
* transactions get encryption without knowing it exists.
|
|
50
|
+
*
|
|
51
|
+
* - Serialize: after the columns' own `serialize` steps, values of encrypted columns are
|
|
52
|
+
* replaced with self-describing envelopes (`EncryptionEnvelope`), and the searchable /
|
|
53
|
+
* sort companions are written beside them in the same statement.
|
|
54
|
+
* - Deserialize: before the columns' own `deserialize` steps, envelope values are decrypted
|
|
55
|
+
* (the envelope names its key — owner + version — so no context is needed) and
|
|
56
|
+
* framework-derived companion columns are dropped. A non-envelope value in an encrypted
|
|
57
|
+
* column passes through unchanged — the online-adoption transition: rows written before
|
|
58
|
+
* the encrypt backfill stay readable while the walker converges them.
|
|
59
|
+
*
|
|
60
|
+
* Server-only: this seam executes where the database driver runs. Browser code proxies
|
|
61
|
+
* through `DbService` and receives decrypted values over the authenticated service.
|
|
62
|
+
*/
|
|
63
|
+
var EncryptionRecordHooks = /** @class */ (function () {
|
|
64
|
+
function EncryptionRecordHooks() {
|
|
65
|
+
this.encryptedColumns = new EncryptedColumns_1.EncryptedColumns();
|
|
66
|
+
this.envelope = new EncryptionEnvelope_1.EncryptionEnvelope();
|
|
67
|
+
this.tokenizer = new SearchTokenizer_1.SearchTokenizer();
|
|
68
|
+
}
|
|
69
|
+
/** Encrypt encrypted-column values in `serialized` (column-name-keyed) and add companions. */
|
|
70
|
+
EncryptionRecordHooks.prototype.onSerialize = function (table, serialized, context) {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
72
|
+
var touchedProps, writeKey, _i, touchedProps_1, prop, column, config, value;
|
|
73
|
+
return __generator(this, function (_a) {
|
|
74
|
+
switch (_a.label) {
|
|
75
|
+
case 0:
|
|
76
|
+
this.encryptedColumns.ensureSchema(table);
|
|
77
|
+
touchedProps = this.encryptedColumns
|
|
78
|
+
.encryptedProps(table)
|
|
79
|
+
.filter(function (prop) { return table.columns[prop].name in serialized; });
|
|
80
|
+
if (touchedProps.length === 0) {
|
|
81
|
+
return [2 /*return*/];
|
|
82
|
+
}
|
|
83
|
+
this.assertServerSide();
|
|
84
|
+
_i = 0, touchedProps_1 = touchedProps;
|
|
85
|
+
_a.label = 1;
|
|
86
|
+
case 1:
|
|
87
|
+
if (!(_i < touchedProps_1.length)) return [3 /*break*/, 5];
|
|
88
|
+
prop = touchedProps_1[_i];
|
|
89
|
+
column = table.columns[prop];
|
|
90
|
+
config = this.encryptedColumns.configFor(table, prop);
|
|
91
|
+
value = serialized[column.name];
|
|
92
|
+
if (value === null) {
|
|
93
|
+
// Null stays null (IS NULL queries keep working); companions null out with it.
|
|
94
|
+
if (config.searchable === 'equality') {
|
|
95
|
+
serialized["".concat(column.name, "_enc_eq")] = null;
|
|
96
|
+
}
|
|
97
|
+
if (config.sortKey) {
|
|
98
|
+
serialized["".concat(column.name, "_enc_srt")] = null;
|
|
99
|
+
}
|
|
100
|
+
return [3 /*break*/, 4];
|
|
101
|
+
}
|
|
102
|
+
if (typeof value !== 'string') {
|
|
103
|
+
throw new DbEncryptionConfig_1.EncryptedColumnConfigError("(".concat(table.name, ".").concat(prop, ") encrypted columns must serialize to a string; ") +
|
|
104
|
+
"got ".concat(typeof value, ". Declare 'encrypted' on a StringColumn-family column."));
|
|
105
|
+
}
|
|
106
|
+
if (!!writeKey) return [3 /*break*/, 3];
|
|
107
|
+
if (!(context === null || context === void 0 ? void 0 : context.keyOwner)) {
|
|
108
|
+
throw new DbEncryptionConfig_1.EncryptedColumnConfigError("(".concat(table.name, ") A write touches encrypted column '").concat(prop, "' but no key owner was ") +
|
|
109
|
+
"resolved. Writes to encrypted columns must resolve the row's scope owner " +
|
|
110
|
+
"(the row's 'scope' value, or DbEncryptionConfig.resolveKeyOwner).");
|
|
111
|
+
}
|
|
112
|
+
return [4 /*yield*/, new DataKeyStore_1.DataKeyStore().getWriteKey(context.keyOwner)];
|
|
113
|
+
case 2:
|
|
114
|
+
writeKey = _a.sent();
|
|
115
|
+
_a.label = 3;
|
|
116
|
+
case 3:
|
|
117
|
+
serialized[column.name] = this.envelope.encrypt(value, writeKey);
|
|
118
|
+
if (config.searchable === 'equality') {
|
|
119
|
+
serialized["".concat(column.name, "_enc_eq")] = this.tokenizer.equalityFingerprint(value, writeKey.indexKey);
|
|
120
|
+
}
|
|
121
|
+
if (config.sortKey) {
|
|
122
|
+
serialized["".concat(column.name, "_enc_srt")] = this.tokenizer.sortPrefix(value, config.sortKey.revealPrefix);
|
|
123
|
+
}
|
|
124
|
+
_a.label = 4;
|
|
125
|
+
case 4:
|
|
126
|
+
_i++;
|
|
127
|
+
return [3 /*break*/, 1];
|
|
128
|
+
case 5: return [2 /*return*/];
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
/**
|
|
134
|
+
* A copy of `serializedRecord` with framework companion columns dropped and every
|
|
135
|
+
* envelope value decrypted (any column — self-describing ciphertext also covers the
|
|
136
|
+
* decrypt-out transition, where the config no longer marks the column).
|
|
137
|
+
*/
|
|
138
|
+
EncryptionRecordHooks.prototype.onDeserialize = function (table, serializedRecord) {
|
|
139
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
140
|
+
var prepared, internalColumnNames, decrypted, _i, _a, columnName, value, parsed, key;
|
|
141
|
+
return __generator(this, function (_b) {
|
|
142
|
+
switch (_b.label) {
|
|
143
|
+
case 0:
|
|
144
|
+
this.encryptedColumns.ensureSchema(table);
|
|
145
|
+
prepared = {};
|
|
146
|
+
internalColumnNames = this.internalColumnNames(table);
|
|
147
|
+
decrypted = false;
|
|
148
|
+
_i = 0, _a = Object.keys(serializedRecord);
|
|
149
|
+
_b.label = 1;
|
|
150
|
+
case 1:
|
|
151
|
+
if (!(_i < _a.length)) return [3 /*break*/, 4];
|
|
152
|
+
columnName = _a[_i];
|
|
153
|
+
if (internalColumnNames.has(columnName)) {
|
|
154
|
+
return [3 /*break*/, 3];
|
|
155
|
+
}
|
|
156
|
+
value = serializedRecord[columnName];
|
|
157
|
+
parsed = this.envelope.parse(value);
|
|
158
|
+
if (!parsed) {
|
|
159
|
+
prepared[columnName] = value;
|
|
160
|
+
return [3 /*break*/, 3];
|
|
161
|
+
}
|
|
162
|
+
this.assertServerSide();
|
|
163
|
+
return [4 /*yield*/, new DataKeyStore_1.DataKeyStore().getKeyByVersion(parsed.owner, parsed.version)];
|
|
164
|
+
case 2:
|
|
165
|
+
key = _b.sent();
|
|
166
|
+
prepared[columnName] = this.envelope.decrypt(value, key);
|
|
167
|
+
decrypted = true;
|
|
168
|
+
_b.label = 3;
|
|
169
|
+
case 3:
|
|
170
|
+
_i++;
|
|
171
|
+
return [3 /*break*/, 1];
|
|
172
|
+
case 4: return [2 /*return*/, decrypted || internalColumnNames.size > 0 ? prepared : serializedRecord];
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* The key owner for a row being written — its permission-source scope owner:
|
|
179
|
+
* `DbEncryptionConfig.resolveKeyOwner` when the deployment supplies one (richer sharing
|
|
180
|
+
* models map scope→owner there), else the row's `scope` column value (the framework's
|
|
181
|
+
* scope columns hold the owning user's id).
|
|
182
|
+
*/
|
|
183
|
+
EncryptionRecordHooks.prototype.resolveKeyOwnerForWrite = function (table, record) {
|
|
184
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
185
|
+
var config, owner;
|
|
186
|
+
return __generator(this, function (_a) {
|
|
187
|
+
switch (_a.label) {
|
|
188
|
+
case 0:
|
|
189
|
+
config = (0, DbEncryptionConfig_1.getDbEncryptionConfig)();
|
|
190
|
+
if (!config.resolveKeyOwner) return [3 /*break*/, 2];
|
|
191
|
+
return [4 /*yield*/, config.resolveKeyOwner({ table: table, record: record })];
|
|
192
|
+
case 1:
|
|
193
|
+
owner = _a.sent();
|
|
194
|
+
if (owner) {
|
|
195
|
+
return [2 /*return*/, owner];
|
|
196
|
+
}
|
|
197
|
+
_a.label = 2;
|
|
198
|
+
case 2:
|
|
199
|
+
if (typeof record.scope === 'string' && record.scope.length > 0) {
|
|
200
|
+
return [2 /*return*/, record.scope];
|
|
201
|
+
}
|
|
202
|
+
throw new DbEncryptionConfig_1.EncryptedColumnConfigError("(".concat(table.name, ") Cannot resolve the key owner for a write to an encrypted column: the row ") +
|
|
203
|
+
"carries no 'scope' value and DbEncryptionConfig.resolveKeyOwner resolved nothing. " +
|
|
204
|
+
"Scoped tables get this automatically; other tables must supply resolveKeyOwner.");
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
EncryptionRecordHooks.prototype.internalColumnNames = function (table) {
|
|
210
|
+
var names = new Set();
|
|
211
|
+
for (var _i = 0, _a = Object.keys(table.columns); _i < _a.length; _i++) {
|
|
212
|
+
var prop = _a[_i];
|
|
213
|
+
var column = table.columns[prop];
|
|
214
|
+
if (this.encryptedColumns.isInternalColumn(column)) {
|
|
215
|
+
names.add(column.name);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return names;
|
|
219
|
+
};
|
|
220
|
+
EncryptionRecordHooks.prototype.assertServerSide = function () {
|
|
221
|
+
if (typeof self !== 'undefined') {
|
|
222
|
+
throw new Error("Column encryption executes where the database driver runs (the server); the browser " +
|
|
223
|
+
"must reach encrypted tables through DbService.");
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
return EncryptionRecordHooks;
|
|
227
|
+
}());
|
|
228
|
+
exports.EncryptionRecordHooks = EncryptionRecordHooks;
|
|
229
|
+
//# sourceMappingURL=EncryptionRecordHooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EncryptionRecordHooks.js","sourceRoot":"","sources":["../../../src/encryption/EncryptionRecordHooks.ts"],"names":[],"mappings":"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"}
|