@cipherstash/stack 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/LICENSE.md +21 -0
- package/README.md +670 -0
- package/dist/bin/stash.js +5049 -0
- package/dist/bin/stash.js.map +1 -0
- package/dist/chunk-2GZMIJFO.js +2400 -0
- package/dist/chunk-2GZMIJFO.js.map +1 -0
- package/dist/chunk-5DCT6YU2.js +138 -0
- package/dist/chunk-5DCT6YU2.js.map +1 -0
- package/dist/chunk-7XRPN2KX.js +336 -0
- package/dist/chunk-7XRPN2KX.js.map +1 -0
- package/dist/chunk-SJ7JO4ME.js +28 -0
- package/dist/chunk-SJ7JO4ME.js.map +1 -0
- package/dist/chunk-SUYMGQBY.js +67 -0
- package/dist/chunk-SUYMGQBY.js.map +1 -0
- package/dist/client-BxJG56Ey.d.cts +647 -0
- package/dist/client-DtGq9dJp.d.ts +647 -0
- package/dist/client.cjs +347 -0
- package/dist/client.cjs.map +1 -0
- package/dist/client.d.cts +7 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +11 -0
- package/dist/client.js.map +1 -0
- package/dist/drizzle/index.cjs +1528 -0
- package/dist/drizzle/index.cjs.map +1 -0
- package/dist/drizzle/index.d.cts +350 -0
- package/dist/drizzle/index.d.ts +350 -0
- package/dist/drizzle/index.js +1212 -0
- package/dist/drizzle/index.js.map +1 -0
- package/dist/dynamodb/index.cjs +382 -0
- package/dist/dynamodb/index.cjs.map +1 -0
- package/dist/dynamodb/index.d.cts +125 -0
- package/dist/dynamodb/index.d.ts +125 -0
- package/dist/dynamodb/index.js +355 -0
- package/dist/dynamodb/index.js.map +1 -0
- package/dist/identity/index.cjs +271 -0
- package/dist/identity/index.cjs.map +1 -0
- package/dist/identity/index.d.cts +3 -0
- package/dist/identity/index.d.ts +3 -0
- package/dist/identity/index.js +117 -0
- package/dist/identity/index.js.map +1 -0
- package/dist/index-9-Ya3fDK.d.cts +169 -0
- package/dist/index-9-Ya3fDK.d.ts +169 -0
- package/dist/index.cjs +2915 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +22 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/schema/index.cjs +368 -0
- package/dist/schema/index.cjs.map +1 -0
- package/dist/schema/index.d.cts +4 -0
- package/dist/schema/index.d.ts +4 -0
- package/dist/schema/index.js +23 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/secrets/index.cjs +3207 -0
- package/dist/secrets/index.cjs.map +1 -0
- package/dist/secrets/index.d.cts +227 -0
- package/dist/secrets/index.d.ts +227 -0
- package/dist/secrets/index.js +323 -0
- package/dist/secrets/index.js.map +1 -0
- package/dist/supabase/index.cjs +1113 -0
- package/dist/supabase/index.cjs.map +1 -0
- package/dist/supabase/index.d.cts +144 -0
- package/dist/supabase/index.d.ts +144 -0
- package/dist/supabase/index.js +864 -0
- package/dist/supabase/index.js.map +1 -0
- package/dist/types-public-BCj1L4fi.d.cts +1013 -0
- package/dist/types-public-BCj1L4fi.d.ts +1013 -0
- package/dist/types-public.cjs +40 -0
- package/dist/types-public.cjs.map +1 -0
- package/dist/types-public.d.cts +4 -0
- package/dist/types-public.d.ts +4 -0
- package/dist/types-public.js +7 -0
- package/dist/types-public.js.map +1 -0
- package/package.json +202 -0
|
@@ -0,0 +1,1212 @@
|
|
|
1
|
+
import {
|
|
2
|
+
queryTypes
|
|
3
|
+
} from "../chunk-SJ7JO4ME.js";
|
|
4
|
+
import {
|
|
5
|
+
encryptedColumn,
|
|
6
|
+
encryptedTable
|
|
7
|
+
} from "../chunk-7XRPN2KX.js";
|
|
8
|
+
|
|
9
|
+
// src/drizzle/index.ts
|
|
10
|
+
import { customType } from "drizzle-orm/pg-core";
|
|
11
|
+
|
|
12
|
+
// src/drizzle/schema-extraction.ts
|
|
13
|
+
function extractEncryptionSchema(table) {
|
|
14
|
+
const tableName = table[Symbol.for("drizzle:Name")];
|
|
15
|
+
if (!tableName) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
"Unable to extract table name from Drizzle table. Ensure you are using a table created with pgTable()."
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
const columns = {};
|
|
21
|
+
for (const [columnName, column] of Object.entries(table)) {
|
|
22
|
+
if (typeof column !== "object" || column === null) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const config = getEncryptedColumnConfig(columnName, column);
|
|
26
|
+
if (config) {
|
|
27
|
+
const actualColumnName = column.name || config.name;
|
|
28
|
+
const csCol = encryptedColumn(actualColumnName);
|
|
29
|
+
if (config.dataType && config.dataType !== "string") {
|
|
30
|
+
csCol.dataType(config.dataType);
|
|
31
|
+
}
|
|
32
|
+
if (config.orderAndRange) {
|
|
33
|
+
csCol.orderAndRange();
|
|
34
|
+
}
|
|
35
|
+
if (config.equality) {
|
|
36
|
+
if (Array.isArray(config.equality)) {
|
|
37
|
+
csCol.equality(config.equality);
|
|
38
|
+
} else {
|
|
39
|
+
csCol.equality();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (config.freeTextSearch) {
|
|
43
|
+
if (typeof config.freeTextSearch === "object") {
|
|
44
|
+
csCol.freeTextSearch(config.freeTextSearch);
|
|
45
|
+
} else {
|
|
46
|
+
csCol.freeTextSearch();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (config.searchableJson) {
|
|
50
|
+
if (config.dataType !== "json") {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`Column "${columnName}" has searchableJson enabled but dataType is "${config.dataType ?? "string"}". searchableJson requires dataType: 'json'.`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
csCol.searchableJson();
|
|
56
|
+
}
|
|
57
|
+
columns[actualColumnName] = csCol;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (Object.keys(columns).length === 0) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`No encrypted columns found in table "${tableName}". Use encryptedType() to define encrypted columns.`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return encryptedTable(tableName, columns);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/drizzle/operators.ts
|
|
69
|
+
import {
|
|
70
|
+
and,
|
|
71
|
+
arrayContained,
|
|
72
|
+
arrayContains,
|
|
73
|
+
arrayOverlaps,
|
|
74
|
+
asc,
|
|
75
|
+
between,
|
|
76
|
+
desc,
|
|
77
|
+
eq,
|
|
78
|
+
exists,
|
|
79
|
+
gt,
|
|
80
|
+
gte,
|
|
81
|
+
ilike,
|
|
82
|
+
inArray,
|
|
83
|
+
isNotNull,
|
|
84
|
+
isNull,
|
|
85
|
+
like,
|
|
86
|
+
lt,
|
|
87
|
+
lte,
|
|
88
|
+
ne,
|
|
89
|
+
not,
|
|
90
|
+
notBetween,
|
|
91
|
+
notExists,
|
|
92
|
+
notIlike,
|
|
93
|
+
notInArray,
|
|
94
|
+
or
|
|
95
|
+
} from "drizzle-orm";
|
|
96
|
+
import { bindIfParam, sql } from "drizzle-orm";
|
|
97
|
+
function isSQLWrapper(value) {
|
|
98
|
+
return typeof value === "object" && value !== null && "sql" in value && typeof value.sql !== "undefined";
|
|
99
|
+
}
|
|
100
|
+
function isPgTable(value) {
|
|
101
|
+
return typeof value === "object" && value !== null && Symbol.for("drizzle:Name") in value;
|
|
102
|
+
}
|
|
103
|
+
var EncryptionOperatorError = class extends Error {
|
|
104
|
+
constructor(message, context) {
|
|
105
|
+
super(message);
|
|
106
|
+
this.context = context;
|
|
107
|
+
this.name = "EncryptionOperatorError";
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
var EncryptionConfigError = class extends EncryptionOperatorError {
|
|
111
|
+
constructor(message, context) {
|
|
112
|
+
super(message, context);
|
|
113
|
+
this.name = "EncryptionConfigError";
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
function getDrizzleTableName(drizzleTable) {
|
|
117
|
+
if (!isPgTable(drizzleTable)) {
|
|
118
|
+
return void 0;
|
|
119
|
+
}
|
|
120
|
+
const tableWithSymbol = drizzleTable;
|
|
121
|
+
return tableWithSymbol[Symbol.for("drizzle:Name")];
|
|
122
|
+
}
|
|
123
|
+
function getDrizzleTableFromColumn(drizzleColumn) {
|
|
124
|
+
const column = drizzleColumn;
|
|
125
|
+
return column.table;
|
|
126
|
+
}
|
|
127
|
+
function getEncryptedTableFromColumn(drizzleColumn, tableCache) {
|
|
128
|
+
const drizzleTable = getDrizzleTableFromColumn(drizzleColumn);
|
|
129
|
+
if (!drizzleTable) {
|
|
130
|
+
return void 0;
|
|
131
|
+
}
|
|
132
|
+
const tableName = getDrizzleTableName(drizzleTable);
|
|
133
|
+
if (!tableName) {
|
|
134
|
+
return void 0;
|
|
135
|
+
}
|
|
136
|
+
let encryptedTable2 = tableCache.get(tableName);
|
|
137
|
+
if (encryptedTable2) {
|
|
138
|
+
return encryptedTable2;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
encryptedTable2 = extractEncryptionSchema(drizzleTable);
|
|
142
|
+
tableCache.set(tableName, encryptedTable2);
|
|
143
|
+
return encryptedTable2;
|
|
144
|
+
} catch {
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
function getEncryptedColumn(drizzleColumn, encryptedTable2) {
|
|
149
|
+
const column = drizzleColumn;
|
|
150
|
+
const columnName = column.name;
|
|
151
|
+
if (!columnName) {
|
|
152
|
+
return void 0;
|
|
153
|
+
}
|
|
154
|
+
const tableRecord = encryptedTable2;
|
|
155
|
+
return tableRecord[columnName];
|
|
156
|
+
}
|
|
157
|
+
function getColumnInfo(drizzleColumn, encryptedTable2, tableCache) {
|
|
158
|
+
const column = drizzleColumn;
|
|
159
|
+
const columnName = column.name || "unknown";
|
|
160
|
+
let resolvedTable = encryptedTable2;
|
|
161
|
+
if (!resolvedTable) {
|
|
162
|
+
resolvedTable = getEncryptedTableFromColumn(drizzleColumn, tableCache);
|
|
163
|
+
}
|
|
164
|
+
const drizzleTable = getDrizzleTableFromColumn(drizzleColumn);
|
|
165
|
+
const tableName = getDrizzleTableName(drizzleTable);
|
|
166
|
+
if (!resolvedTable) {
|
|
167
|
+
const config2 = getEncryptedColumnConfig(columnName, drizzleColumn);
|
|
168
|
+
return {
|
|
169
|
+
encryptedColumn: void 0,
|
|
170
|
+
config: config2,
|
|
171
|
+
encryptedTable: void 0,
|
|
172
|
+
columnName,
|
|
173
|
+
tableName
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const encryptedColumn2 = getEncryptedColumn(drizzleColumn, resolvedTable);
|
|
177
|
+
const config = getEncryptedColumnConfig(columnName, drizzleColumn);
|
|
178
|
+
return {
|
|
179
|
+
encryptedColumn: encryptedColumn2,
|
|
180
|
+
config,
|
|
181
|
+
encryptedTable: resolvedTable,
|
|
182
|
+
columnName,
|
|
183
|
+
tableName
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function toPlaintext(value) {
|
|
187
|
+
if (typeof value === "boolean") {
|
|
188
|
+
return value ? 1 : 0;
|
|
189
|
+
}
|
|
190
|
+
if (typeof value === "string" || typeof value === "number") {
|
|
191
|
+
return value;
|
|
192
|
+
}
|
|
193
|
+
if (value instanceof Date) {
|
|
194
|
+
return value.toISOString();
|
|
195
|
+
}
|
|
196
|
+
return String(value);
|
|
197
|
+
}
|
|
198
|
+
async function encryptValues(encryptionClient, values, encryptedTable2, tableCache) {
|
|
199
|
+
if (values.length === 0) {
|
|
200
|
+
return [];
|
|
201
|
+
}
|
|
202
|
+
const valuesToEncrypt = [];
|
|
203
|
+
const results = new Array(values.length);
|
|
204
|
+
for (let i = 0; i < values.length; i++) {
|
|
205
|
+
const { value, column, queryType } = values[i];
|
|
206
|
+
const columnInfo = getColumnInfo(column, encryptedTable2, tableCache);
|
|
207
|
+
if (!columnInfo.encryptedColumn || !columnInfo.config || !columnInfo.encryptedTable) {
|
|
208
|
+
results[i] = value;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const plaintextValue = toPlaintext(value);
|
|
212
|
+
valuesToEncrypt.push({
|
|
213
|
+
value: plaintextValue,
|
|
214
|
+
column,
|
|
215
|
+
columnInfo,
|
|
216
|
+
queryType,
|
|
217
|
+
originalIndex: i
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
if (valuesToEncrypt.length === 0) {
|
|
221
|
+
return results;
|
|
222
|
+
}
|
|
223
|
+
const columnGroups = /* @__PURE__ */ new Map();
|
|
224
|
+
let valueIndex = 0;
|
|
225
|
+
for (const {
|
|
226
|
+
value,
|
|
227
|
+
columnInfo,
|
|
228
|
+
queryType,
|
|
229
|
+
originalIndex
|
|
230
|
+
} of valuesToEncrypt) {
|
|
231
|
+
if (!columnInfo.config || !columnInfo.encryptedColumn || !columnInfo.encryptedTable) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const columnName = columnInfo.config.name;
|
|
235
|
+
const groupKey = `${columnInfo.tableName ?? "unknown"}/${columnName}`;
|
|
236
|
+
let group = columnGroups.get(groupKey);
|
|
237
|
+
if (!group) {
|
|
238
|
+
group = {
|
|
239
|
+
column: columnInfo.encryptedColumn,
|
|
240
|
+
table: columnInfo.encryptedTable,
|
|
241
|
+
columnName,
|
|
242
|
+
values: [],
|
|
243
|
+
resultIndices: []
|
|
244
|
+
};
|
|
245
|
+
columnGroups.set(groupKey, group);
|
|
246
|
+
}
|
|
247
|
+
group.values.push({ value, index: valueIndex++, queryType });
|
|
248
|
+
group.resultIndices.push(originalIndex);
|
|
249
|
+
}
|
|
250
|
+
for (const [, group] of columnGroups) {
|
|
251
|
+
const { columnName } = group;
|
|
252
|
+
try {
|
|
253
|
+
const terms = group.values.map((v) => ({
|
|
254
|
+
value: v.value,
|
|
255
|
+
column: group.column,
|
|
256
|
+
table: group.table,
|
|
257
|
+
queryType: v.queryType
|
|
258
|
+
}));
|
|
259
|
+
const encryptedTerms = await encryptionClient.encryptQuery(terms);
|
|
260
|
+
if (encryptedTerms.failure) {
|
|
261
|
+
throw new EncryptionOperatorError(
|
|
262
|
+
`Failed to encrypt query terms for column "${columnName}": ${encryptedTerms.failure.message}`,
|
|
263
|
+
{ columnName }
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
for (let i = 0; i < group.values.length; i++) {
|
|
267
|
+
const resultIndex = group.resultIndices[i] ?? -1;
|
|
268
|
+
if (resultIndex >= 0 && resultIndex < results.length) {
|
|
269
|
+
results[resultIndex] = encryptedTerms.data[i];
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
} catch (error) {
|
|
273
|
+
if (error instanceof EncryptionOperatorError) {
|
|
274
|
+
throw error;
|
|
275
|
+
}
|
|
276
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
277
|
+
throw new EncryptionOperatorError(
|
|
278
|
+
`Unexpected error encrypting values for column "${columnName}": ${errorMessage}`,
|
|
279
|
+
{ columnName }
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return results;
|
|
284
|
+
}
|
|
285
|
+
async function encryptValue(encryptionClient, value, drizzleColumn, encryptedTable2, tableCache, queryType) {
|
|
286
|
+
const results = await encryptValues(
|
|
287
|
+
encryptionClient,
|
|
288
|
+
[{ value, column: drizzleColumn, queryType }],
|
|
289
|
+
encryptedTable2,
|
|
290
|
+
tableCache
|
|
291
|
+
);
|
|
292
|
+
return results[0];
|
|
293
|
+
}
|
|
294
|
+
function isLazyOperator(value) {
|
|
295
|
+
return typeof value === "object" && value !== null && "__isLazyOperator" in value && value.__isLazyOperator === true;
|
|
296
|
+
}
|
|
297
|
+
function createLazyOperator(operator, left, right, execute, needsEncryption, columnInfo, encryptionClient, defaultTable, tableCache, min, max, queryType) {
|
|
298
|
+
let resolvedSQL;
|
|
299
|
+
let encryptionPromise;
|
|
300
|
+
const lazyOp = {
|
|
301
|
+
__isLazyOperator: true,
|
|
302
|
+
operator,
|
|
303
|
+
queryType,
|
|
304
|
+
left,
|
|
305
|
+
right,
|
|
306
|
+
min,
|
|
307
|
+
max,
|
|
308
|
+
needsEncryption,
|
|
309
|
+
columnInfo,
|
|
310
|
+
execute
|
|
311
|
+
};
|
|
312
|
+
const promise = new Promise((resolve, reject) => {
|
|
313
|
+
queueMicrotask(async () => {
|
|
314
|
+
if (resolvedSQL !== void 0) {
|
|
315
|
+
resolve(resolvedSQL);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
if (!encryptionPromise) {
|
|
320
|
+
encryptionPromise = executeLazyOperatorDirect(
|
|
321
|
+
lazyOp,
|
|
322
|
+
encryptionClient,
|
|
323
|
+
defaultTable,
|
|
324
|
+
tableCache
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
const sql2 = await encryptionPromise;
|
|
328
|
+
resolvedSQL = sql2;
|
|
329
|
+
resolve(sql2);
|
|
330
|
+
} catch (error) {
|
|
331
|
+
reject(error);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
return Object.assign(promise, lazyOp);
|
|
336
|
+
}
|
|
337
|
+
async function executeLazyOperator(lazyOp, encryptedValues) {
|
|
338
|
+
if (!lazyOp.needsEncryption) {
|
|
339
|
+
return lazyOp.execute(lazyOp.right);
|
|
340
|
+
}
|
|
341
|
+
if (lazyOp.min !== void 0 && lazyOp.max !== void 0) {
|
|
342
|
+
let encryptedMin;
|
|
343
|
+
let encryptedMax;
|
|
344
|
+
if (encryptedValues && encryptedValues.length >= 2) {
|
|
345
|
+
encryptedMin = encryptedValues[0]?.encrypted;
|
|
346
|
+
encryptedMax = encryptedValues[1]?.encrypted;
|
|
347
|
+
} else {
|
|
348
|
+
throw new EncryptionOperatorError(
|
|
349
|
+
"Between operator requires both min and max encrypted values",
|
|
350
|
+
{
|
|
351
|
+
columnName: lazyOp.columnInfo.columnName,
|
|
352
|
+
tableName: lazyOp.columnInfo.tableName,
|
|
353
|
+
operator: lazyOp.operator
|
|
354
|
+
}
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
if (encryptedMin === void 0 || encryptedMax === void 0) {
|
|
358
|
+
throw new EncryptionOperatorError(
|
|
359
|
+
"Between operator requires both min and max values to be encrypted",
|
|
360
|
+
{
|
|
361
|
+
columnName: lazyOp.columnInfo.columnName,
|
|
362
|
+
tableName: lazyOp.columnInfo.tableName,
|
|
363
|
+
operator: lazyOp.operator
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
}
|
|
367
|
+
return lazyOp.execute(void 0, encryptedMin, encryptedMax);
|
|
368
|
+
}
|
|
369
|
+
let encrypted;
|
|
370
|
+
if (encryptedValues && encryptedValues.length > 0) {
|
|
371
|
+
encrypted = encryptedValues[0]?.encrypted;
|
|
372
|
+
} else {
|
|
373
|
+
throw new EncryptionOperatorError(
|
|
374
|
+
"Operator requires encrypted value but none provided",
|
|
375
|
+
{
|
|
376
|
+
columnName: lazyOp.columnInfo.columnName,
|
|
377
|
+
tableName: lazyOp.columnInfo.tableName,
|
|
378
|
+
operator: lazyOp.operator
|
|
379
|
+
}
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
if (encrypted === void 0) {
|
|
383
|
+
throw new EncryptionOperatorError(
|
|
384
|
+
"Encryption failed or value was not encrypted",
|
|
385
|
+
{
|
|
386
|
+
columnName: lazyOp.columnInfo.columnName,
|
|
387
|
+
tableName: lazyOp.columnInfo.tableName,
|
|
388
|
+
operator: lazyOp.operator
|
|
389
|
+
}
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
return lazyOp.execute(encrypted);
|
|
393
|
+
}
|
|
394
|
+
async function executeLazyOperatorDirect(lazyOp, encryptionClient, defaultTable, tableCache) {
|
|
395
|
+
if (!lazyOp.needsEncryption) {
|
|
396
|
+
return lazyOp.execute(lazyOp.right);
|
|
397
|
+
}
|
|
398
|
+
if (lazyOp.min !== void 0 && lazyOp.max !== void 0) {
|
|
399
|
+
const [encryptedMin, encryptedMax] = await encryptValues(
|
|
400
|
+
encryptionClient,
|
|
401
|
+
[
|
|
402
|
+
{ value: lazyOp.min, column: lazyOp.left, queryType: lazyOp.queryType },
|
|
403
|
+
{ value: lazyOp.max, column: lazyOp.left, queryType: lazyOp.queryType }
|
|
404
|
+
],
|
|
405
|
+
defaultTable,
|
|
406
|
+
tableCache
|
|
407
|
+
);
|
|
408
|
+
return lazyOp.execute(void 0, encryptedMin, encryptedMax);
|
|
409
|
+
}
|
|
410
|
+
const encrypted = await encryptValue(
|
|
411
|
+
encryptionClient,
|
|
412
|
+
lazyOp.right,
|
|
413
|
+
lazyOp.left,
|
|
414
|
+
defaultTable,
|
|
415
|
+
tableCache,
|
|
416
|
+
lazyOp.queryType
|
|
417
|
+
);
|
|
418
|
+
return lazyOp.execute(encrypted);
|
|
419
|
+
}
|
|
420
|
+
function createComparisonOperator(operator, left, right, columnInfo, encryptionClient, defaultTable, tableCache) {
|
|
421
|
+
const { config } = columnInfo;
|
|
422
|
+
const requiresOrderAndRange = ["gt", "gte", "lt", "lte"].includes(operator);
|
|
423
|
+
if (requiresOrderAndRange) {
|
|
424
|
+
if (!config?.orderAndRange) {
|
|
425
|
+
switch (operator) {
|
|
426
|
+
case "gt":
|
|
427
|
+
return gt(left, right);
|
|
428
|
+
case "gte":
|
|
429
|
+
return gte(left, right);
|
|
430
|
+
case "lt":
|
|
431
|
+
return lt(left, right);
|
|
432
|
+
case "lte":
|
|
433
|
+
return lte(left, right);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
const executeFn = (encrypted) => {
|
|
437
|
+
if (encrypted === void 0) {
|
|
438
|
+
throw new EncryptionOperatorError(
|
|
439
|
+
`Encryption failed for ${operator} operator`,
|
|
440
|
+
{
|
|
441
|
+
columnName: columnInfo.columnName,
|
|
442
|
+
tableName: columnInfo.tableName,
|
|
443
|
+
operator
|
|
444
|
+
}
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
return sql`eql_v2.${sql.raw(operator)}(${left}, ${bindIfParam(encrypted, left)})`;
|
|
448
|
+
};
|
|
449
|
+
return createLazyOperator(
|
|
450
|
+
operator,
|
|
451
|
+
left,
|
|
452
|
+
right,
|
|
453
|
+
executeFn,
|
|
454
|
+
true,
|
|
455
|
+
columnInfo,
|
|
456
|
+
encryptionClient,
|
|
457
|
+
defaultTable,
|
|
458
|
+
tableCache,
|
|
459
|
+
void 0,
|
|
460
|
+
// min
|
|
461
|
+
void 0,
|
|
462
|
+
// max
|
|
463
|
+
queryTypes.orderAndRange
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
const requiresEquality = ["eq", "ne"].includes(operator);
|
|
467
|
+
if (requiresEquality && config?.equality) {
|
|
468
|
+
const executeFn = (encrypted) => {
|
|
469
|
+
if (encrypted === void 0) {
|
|
470
|
+
throw new EncryptionOperatorError(
|
|
471
|
+
`Encryption failed for ${operator} operator`,
|
|
472
|
+
{
|
|
473
|
+
columnName: columnInfo.columnName,
|
|
474
|
+
tableName: columnInfo.tableName,
|
|
475
|
+
operator
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
return operator === "eq" ? eq(left, encrypted) : ne(left, encrypted);
|
|
480
|
+
};
|
|
481
|
+
return createLazyOperator(
|
|
482
|
+
operator,
|
|
483
|
+
left,
|
|
484
|
+
right,
|
|
485
|
+
executeFn,
|
|
486
|
+
true,
|
|
487
|
+
columnInfo,
|
|
488
|
+
encryptionClient,
|
|
489
|
+
defaultTable,
|
|
490
|
+
tableCache,
|
|
491
|
+
void 0,
|
|
492
|
+
// min
|
|
493
|
+
void 0,
|
|
494
|
+
// max
|
|
495
|
+
queryTypes.equality
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
return operator === "eq" ? eq(left, right) : ne(left, right);
|
|
499
|
+
}
|
|
500
|
+
function createRangeOperator(operator, left, min, max, columnInfo, encryptionClient, defaultTable, tableCache) {
|
|
501
|
+
const { config } = columnInfo;
|
|
502
|
+
if (!config?.orderAndRange) {
|
|
503
|
+
return operator === "between" ? between(left, min, max) : notBetween(left, min, max);
|
|
504
|
+
}
|
|
505
|
+
const executeFn = (_encrypted, encryptedMin, encryptedMax) => {
|
|
506
|
+
if (encryptedMin === void 0 || encryptedMax === void 0) {
|
|
507
|
+
throw new EncryptionOperatorError(
|
|
508
|
+
`${operator} operator requires both min and max values`,
|
|
509
|
+
{
|
|
510
|
+
columnName: columnInfo.columnName,
|
|
511
|
+
tableName: columnInfo.tableName,
|
|
512
|
+
operator
|
|
513
|
+
}
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
const rangeCondition = sql`eql_v2.gte(${left}, ${bindIfParam(encryptedMin, left)}) AND eql_v2.lte(${left}, ${bindIfParam(encryptedMax, left)})`;
|
|
517
|
+
return operator === "between" ? rangeCondition : sql`NOT (${rangeCondition})`;
|
|
518
|
+
};
|
|
519
|
+
return createLazyOperator(
|
|
520
|
+
operator,
|
|
521
|
+
left,
|
|
522
|
+
void 0,
|
|
523
|
+
executeFn,
|
|
524
|
+
true,
|
|
525
|
+
columnInfo,
|
|
526
|
+
encryptionClient,
|
|
527
|
+
defaultTable,
|
|
528
|
+
tableCache,
|
|
529
|
+
min,
|
|
530
|
+
max,
|
|
531
|
+
queryTypes.orderAndRange
|
|
532
|
+
);
|
|
533
|
+
}
|
|
534
|
+
function createTextSearchOperator(operator, left, right, columnInfo, encryptionClient, defaultTable, tableCache) {
|
|
535
|
+
const { config } = columnInfo;
|
|
536
|
+
if (!config?.freeTextSearch) {
|
|
537
|
+
const rightValue = right;
|
|
538
|
+
switch (operator) {
|
|
539
|
+
case "like":
|
|
540
|
+
return like(left, rightValue);
|
|
541
|
+
case "ilike":
|
|
542
|
+
return ilike(left, rightValue);
|
|
543
|
+
case "notIlike":
|
|
544
|
+
return notIlike(left, rightValue);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
const executeFn = (encrypted) => {
|
|
548
|
+
if (encrypted === void 0) {
|
|
549
|
+
throw new EncryptionOperatorError(
|
|
550
|
+
`Encryption failed for ${operator} operator`,
|
|
551
|
+
{
|
|
552
|
+
columnName: columnInfo.columnName,
|
|
553
|
+
tableName: columnInfo.tableName,
|
|
554
|
+
operator
|
|
555
|
+
}
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
const sqlFn = sql`eql_v2.${sql.raw(operator === "notIlike" ? "ilike" : operator)}(${left}, ${bindIfParam(encrypted, left)})`;
|
|
559
|
+
return operator === "notIlike" ? sql`NOT (${sqlFn})` : sqlFn;
|
|
560
|
+
};
|
|
561
|
+
return createLazyOperator(
|
|
562
|
+
operator,
|
|
563
|
+
left,
|
|
564
|
+
right,
|
|
565
|
+
executeFn,
|
|
566
|
+
true,
|
|
567
|
+
columnInfo,
|
|
568
|
+
encryptionClient,
|
|
569
|
+
defaultTable,
|
|
570
|
+
tableCache,
|
|
571
|
+
void 0,
|
|
572
|
+
// min
|
|
573
|
+
void 0,
|
|
574
|
+
// max
|
|
575
|
+
queryTypes.freeTextSearch
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
function createJsonbOperator(operator, left, right, columnInfo, encryptionClient, defaultTable, tableCache) {
|
|
579
|
+
const { config } = columnInfo;
|
|
580
|
+
const encryptedSelector = (value) => sql`${bindIfParam(value, left)}::eql_v2_encrypted`;
|
|
581
|
+
if (!config?.searchableJson) {
|
|
582
|
+
throw new EncryptionOperatorError(
|
|
583
|
+
`The ${operator} operator requires searchableJson to be enabled on the column configuration.`,
|
|
584
|
+
{
|
|
585
|
+
columnName: columnInfo.columnName,
|
|
586
|
+
tableName: columnInfo.tableName,
|
|
587
|
+
operator
|
|
588
|
+
}
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
const executeFn = (encrypted) => {
|
|
592
|
+
if (encrypted === void 0) {
|
|
593
|
+
throw new EncryptionOperatorError(
|
|
594
|
+
`Encryption failed for ${operator} operator`,
|
|
595
|
+
{
|
|
596
|
+
columnName: columnInfo.columnName,
|
|
597
|
+
tableName: columnInfo.tableName,
|
|
598
|
+
operator
|
|
599
|
+
}
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
switch (operator) {
|
|
603
|
+
case "jsonbPathQueryFirst":
|
|
604
|
+
return sql`eql_v2.jsonb_path_query_first(${left}, ${encryptedSelector(encrypted)})`;
|
|
605
|
+
case "jsonbGet":
|
|
606
|
+
return sql`${left} -> ${encryptedSelector(encrypted)}`;
|
|
607
|
+
case "jsonbPathExists":
|
|
608
|
+
return sql`eql_v2.jsonb_path_exists(${left}, ${encryptedSelector(encrypted)})`;
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
return createLazyOperator(
|
|
612
|
+
operator,
|
|
613
|
+
left,
|
|
614
|
+
right,
|
|
615
|
+
executeFn,
|
|
616
|
+
true,
|
|
617
|
+
columnInfo,
|
|
618
|
+
encryptionClient,
|
|
619
|
+
defaultTable,
|
|
620
|
+
tableCache,
|
|
621
|
+
void 0,
|
|
622
|
+
void 0,
|
|
623
|
+
queryTypes.steVecSelector
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
function createEncryptionOperators(encryptionClient) {
|
|
627
|
+
const tableCache = /* @__PURE__ */ new Map();
|
|
628
|
+
const defaultTable = void 0;
|
|
629
|
+
const encryptedEq = (left, right) => {
|
|
630
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
631
|
+
return createComparisonOperator(
|
|
632
|
+
"eq",
|
|
633
|
+
left,
|
|
634
|
+
right,
|
|
635
|
+
columnInfo,
|
|
636
|
+
encryptionClient,
|
|
637
|
+
defaultTable,
|
|
638
|
+
tableCache
|
|
639
|
+
);
|
|
640
|
+
};
|
|
641
|
+
const encryptedNe = (left, right) => {
|
|
642
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
643
|
+
return createComparisonOperator(
|
|
644
|
+
"ne",
|
|
645
|
+
left,
|
|
646
|
+
right,
|
|
647
|
+
columnInfo,
|
|
648
|
+
encryptionClient,
|
|
649
|
+
defaultTable,
|
|
650
|
+
tableCache
|
|
651
|
+
);
|
|
652
|
+
};
|
|
653
|
+
const encryptedGt = (left, right) => {
|
|
654
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
655
|
+
return createComparisonOperator(
|
|
656
|
+
"gt",
|
|
657
|
+
left,
|
|
658
|
+
right,
|
|
659
|
+
columnInfo,
|
|
660
|
+
encryptionClient,
|
|
661
|
+
defaultTable,
|
|
662
|
+
tableCache
|
|
663
|
+
);
|
|
664
|
+
};
|
|
665
|
+
const encryptedGte = (left, right) => {
|
|
666
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
667
|
+
return createComparisonOperator(
|
|
668
|
+
"gte",
|
|
669
|
+
left,
|
|
670
|
+
right,
|
|
671
|
+
columnInfo,
|
|
672
|
+
encryptionClient,
|
|
673
|
+
defaultTable,
|
|
674
|
+
tableCache
|
|
675
|
+
);
|
|
676
|
+
};
|
|
677
|
+
const encryptedLt = (left, right) => {
|
|
678
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
679
|
+
return createComparisonOperator(
|
|
680
|
+
"lt",
|
|
681
|
+
left,
|
|
682
|
+
right,
|
|
683
|
+
columnInfo,
|
|
684
|
+
encryptionClient,
|
|
685
|
+
defaultTable,
|
|
686
|
+
tableCache
|
|
687
|
+
);
|
|
688
|
+
};
|
|
689
|
+
const encryptedLte = (left, right) => {
|
|
690
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
691
|
+
return createComparisonOperator(
|
|
692
|
+
"lte",
|
|
693
|
+
left,
|
|
694
|
+
right,
|
|
695
|
+
columnInfo,
|
|
696
|
+
encryptionClient,
|
|
697
|
+
defaultTable,
|
|
698
|
+
tableCache
|
|
699
|
+
);
|
|
700
|
+
};
|
|
701
|
+
const encryptedBetween = (left, min, max) => {
|
|
702
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
703
|
+
return createRangeOperator(
|
|
704
|
+
"between",
|
|
705
|
+
left,
|
|
706
|
+
min,
|
|
707
|
+
max,
|
|
708
|
+
columnInfo,
|
|
709
|
+
encryptionClient,
|
|
710
|
+
defaultTable,
|
|
711
|
+
tableCache
|
|
712
|
+
);
|
|
713
|
+
};
|
|
714
|
+
const encryptedNotBetween = (left, min, max) => {
|
|
715
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
716
|
+
return createRangeOperator(
|
|
717
|
+
"notBetween",
|
|
718
|
+
left,
|
|
719
|
+
min,
|
|
720
|
+
max,
|
|
721
|
+
columnInfo,
|
|
722
|
+
encryptionClient,
|
|
723
|
+
defaultTable,
|
|
724
|
+
tableCache
|
|
725
|
+
);
|
|
726
|
+
};
|
|
727
|
+
const encryptedLike = (left, right) => {
|
|
728
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
729
|
+
return createTextSearchOperator(
|
|
730
|
+
"like",
|
|
731
|
+
left,
|
|
732
|
+
right,
|
|
733
|
+
columnInfo,
|
|
734
|
+
encryptionClient,
|
|
735
|
+
defaultTable,
|
|
736
|
+
tableCache
|
|
737
|
+
);
|
|
738
|
+
};
|
|
739
|
+
const encryptedIlike = (left, right) => {
|
|
740
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
741
|
+
return createTextSearchOperator(
|
|
742
|
+
"ilike",
|
|
743
|
+
left,
|
|
744
|
+
right,
|
|
745
|
+
columnInfo,
|
|
746
|
+
encryptionClient,
|
|
747
|
+
defaultTable,
|
|
748
|
+
tableCache
|
|
749
|
+
);
|
|
750
|
+
};
|
|
751
|
+
const encryptedNotIlike = (left, right) => {
|
|
752
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
753
|
+
return createTextSearchOperator(
|
|
754
|
+
"notIlike",
|
|
755
|
+
left,
|
|
756
|
+
right,
|
|
757
|
+
columnInfo,
|
|
758
|
+
encryptionClient,
|
|
759
|
+
defaultTable,
|
|
760
|
+
tableCache
|
|
761
|
+
);
|
|
762
|
+
};
|
|
763
|
+
const encryptedJsonbPathQueryFirst = (left, right) => {
|
|
764
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
765
|
+
return createJsonbOperator(
|
|
766
|
+
"jsonbPathQueryFirst",
|
|
767
|
+
left,
|
|
768
|
+
right,
|
|
769
|
+
columnInfo,
|
|
770
|
+
encryptionClient,
|
|
771
|
+
defaultTable,
|
|
772
|
+
tableCache
|
|
773
|
+
);
|
|
774
|
+
};
|
|
775
|
+
const encryptedJsonbGet = (left, right) => {
|
|
776
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
777
|
+
return createJsonbOperator(
|
|
778
|
+
"jsonbGet",
|
|
779
|
+
left,
|
|
780
|
+
right,
|
|
781
|
+
columnInfo,
|
|
782
|
+
encryptionClient,
|
|
783
|
+
defaultTable,
|
|
784
|
+
tableCache
|
|
785
|
+
);
|
|
786
|
+
};
|
|
787
|
+
const encryptedJsonbPathExists = (left, right) => {
|
|
788
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
789
|
+
return createJsonbOperator(
|
|
790
|
+
"jsonbPathExists",
|
|
791
|
+
left,
|
|
792
|
+
right,
|
|
793
|
+
columnInfo,
|
|
794
|
+
encryptionClient,
|
|
795
|
+
defaultTable,
|
|
796
|
+
tableCache
|
|
797
|
+
);
|
|
798
|
+
};
|
|
799
|
+
const encryptedInArray = async (left, right) => {
|
|
800
|
+
if (isSQLWrapper(right)) {
|
|
801
|
+
return inArray(left, right);
|
|
802
|
+
}
|
|
803
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
804
|
+
if (!columnInfo.config?.equality || !Array.isArray(right)) {
|
|
805
|
+
return inArray(left, right);
|
|
806
|
+
}
|
|
807
|
+
const encryptedValues = await encryptValues(
|
|
808
|
+
encryptionClient,
|
|
809
|
+
right.map((value) => ({
|
|
810
|
+
value,
|
|
811
|
+
column: left,
|
|
812
|
+
queryType: queryTypes.equality
|
|
813
|
+
})),
|
|
814
|
+
defaultTable,
|
|
815
|
+
tableCache
|
|
816
|
+
);
|
|
817
|
+
const conditions = encryptedValues.filter((encrypted) => encrypted !== void 0).map((encrypted) => eq(left, encrypted));
|
|
818
|
+
if (conditions.length === 0) {
|
|
819
|
+
return sql`false`;
|
|
820
|
+
}
|
|
821
|
+
const combined = or(...conditions);
|
|
822
|
+
return combined ?? sql`false`;
|
|
823
|
+
};
|
|
824
|
+
const encryptedNotInArray = async (left, right) => {
|
|
825
|
+
if (isSQLWrapper(right)) {
|
|
826
|
+
return notInArray(
|
|
827
|
+
left,
|
|
828
|
+
right
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
const columnInfo = getColumnInfo(left, defaultTable, tableCache);
|
|
832
|
+
if (!columnInfo.config?.equality || !Array.isArray(right)) {
|
|
833
|
+
return notInArray(left, right);
|
|
834
|
+
}
|
|
835
|
+
const encryptedValues = await encryptValues(
|
|
836
|
+
encryptionClient,
|
|
837
|
+
right.map((value) => ({
|
|
838
|
+
value,
|
|
839
|
+
column: left,
|
|
840
|
+
queryType: queryTypes.equality
|
|
841
|
+
})),
|
|
842
|
+
defaultTable,
|
|
843
|
+
tableCache
|
|
844
|
+
);
|
|
845
|
+
const conditions = encryptedValues.filter((encrypted) => encrypted !== void 0).map((encrypted) => ne(left, encrypted));
|
|
846
|
+
if (conditions.length === 0) {
|
|
847
|
+
return sql`true`;
|
|
848
|
+
}
|
|
849
|
+
const combined = and(...conditions);
|
|
850
|
+
return combined ?? sql`true`;
|
|
851
|
+
};
|
|
852
|
+
const encryptedAsc = (column) => {
|
|
853
|
+
const columnInfo = getColumnInfo(column, defaultTable, tableCache);
|
|
854
|
+
if (columnInfo.config?.orderAndRange) {
|
|
855
|
+
return asc(sql`eql_v2.order_by(${column})`);
|
|
856
|
+
}
|
|
857
|
+
return asc(column);
|
|
858
|
+
};
|
|
859
|
+
const encryptedDesc = (column) => {
|
|
860
|
+
const columnInfo = getColumnInfo(column, defaultTable, tableCache);
|
|
861
|
+
if (columnInfo.config?.orderAndRange) {
|
|
862
|
+
return desc(sql`eql_v2.order_by(${column})`);
|
|
863
|
+
}
|
|
864
|
+
return desc(column);
|
|
865
|
+
};
|
|
866
|
+
const encryptedAnd = async (...conditions) => {
|
|
867
|
+
const lazyOperators = [];
|
|
868
|
+
const regularConditions = [];
|
|
869
|
+
const regularPromises = [];
|
|
870
|
+
for (const condition of conditions) {
|
|
871
|
+
if (condition === void 0) {
|
|
872
|
+
continue;
|
|
873
|
+
}
|
|
874
|
+
if (isLazyOperator(condition)) {
|
|
875
|
+
lazyOperators.push(condition);
|
|
876
|
+
} else if (condition instanceof Promise) {
|
|
877
|
+
if (isLazyOperator(condition)) {
|
|
878
|
+
lazyOperators.push(condition);
|
|
879
|
+
} else {
|
|
880
|
+
regularPromises.push(condition);
|
|
881
|
+
}
|
|
882
|
+
} else {
|
|
883
|
+
regularConditions.push(condition);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
if (lazyOperators.length === 0) {
|
|
887
|
+
const allConditions2 = [
|
|
888
|
+
...regularConditions,
|
|
889
|
+
...await Promise.all(regularPromises)
|
|
890
|
+
];
|
|
891
|
+
return and(...allConditions2) ?? sql`true`;
|
|
892
|
+
}
|
|
893
|
+
const valuesToEncrypt = [];
|
|
894
|
+
for (let i = 0; i < lazyOperators.length; i++) {
|
|
895
|
+
const lazyOp = lazyOperators[i];
|
|
896
|
+
if (!lazyOp.needsEncryption) {
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
if (lazyOp.min !== void 0 && lazyOp.max !== void 0) {
|
|
900
|
+
valuesToEncrypt.push({
|
|
901
|
+
value: lazyOp.min,
|
|
902
|
+
column: lazyOp.left,
|
|
903
|
+
columnInfo: lazyOp.columnInfo,
|
|
904
|
+
queryType: lazyOp.queryType,
|
|
905
|
+
lazyOpIndex: i,
|
|
906
|
+
isMin: true
|
|
907
|
+
});
|
|
908
|
+
valuesToEncrypt.push({
|
|
909
|
+
value: lazyOp.max,
|
|
910
|
+
column: lazyOp.left,
|
|
911
|
+
columnInfo: lazyOp.columnInfo,
|
|
912
|
+
queryType: lazyOp.queryType,
|
|
913
|
+
lazyOpIndex: i,
|
|
914
|
+
isMax: true
|
|
915
|
+
});
|
|
916
|
+
} else if (lazyOp.right !== void 0) {
|
|
917
|
+
valuesToEncrypt.push({
|
|
918
|
+
value: lazyOp.right,
|
|
919
|
+
column: lazyOp.left,
|
|
920
|
+
columnInfo: lazyOp.columnInfo,
|
|
921
|
+
queryType: lazyOp.queryType,
|
|
922
|
+
lazyOpIndex: i
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
const encryptedResults = await encryptValues(
|
|
927
|
+
encryptionClient,
|
|
928
|
+
valuesToEncrypt.map((v) => ({
|
|
929
|
+
value: v.value,
|
|
930
|
+
column: v.column,
|
|
931
|
+
queryType: v.queryType
|
|
932
|
+
})),
|
|
933
|
+
defaultTable,
|
|
934
|
+
tableCache
|
|
935
|
+
);
|
|
936
|
+
const encryptedByLazyOp = /* @__PURE__ */ new Map();
|
|
937
|
+
for (let i = 0; i < valuesToEncrypt.length; i++) {
|
|
938
|
+
const { lazyOpIndex, isMin, isMax } = valuesToEncrypt[i];
|
|
939
|
+
const encrypted = encryptedResults[i];
|
|
940
|
+
let group = encryptedByLazyOp.get(lazyOpIndex);
|
|
941
|
+
if (!group) {
|
|
942
|
+
group = {};
|
|
943
|
+
encryptedByLazyOp.set(lazyOpIndex, group);
|
|
944
|
+
}
|
|
945
|
+
if (isMin) {
|
|
946
|
+
group.min = encrypted;
|
|
947
|
+
} else if (isMax) {
|
|
948
|
+
group.max = encrypted;
|
|
949
|
+
} else {
|
|
950
|
+
group.value = encrypted;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
const sqlConditions = [];
|
|
954
|
+
for (let i = 0; i < lazyOperators.length; i++) {
|
|
955
|
+
const lazyOp = lazyOperators[i];
|
|
956
|
+
const encrypted = encryptedByLazyOp.get(i);
|
|
957
|
+
let sqlCondition;
|
|
958
|
+
if (lazyOp.needsEncryption && encrypted) {
|
|
959
|
+
const encryptedValues = [];
|
|
960
|
+
if (encrypted.value !== void 0) {
|
|
961
|
+
encryptedValues.push({
|
|
962
|
+
value: lazyOp.right,
|
|
963
|
+
encrypted: encrypted.value
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
if (encrypted.min !== void 0) {
|
|
967
|
+
encryptedValues.push({ value: lazyOp.min, encrypted: encrypted.min });
|
|
968
|
+
}
|
|
969
|
+
if (encrypted.max !== void 0) {
|
|
970
|
+
encryptedValues.push({ value: lazyOp.max, encrypted: encrypted.max });
|
|
971
|
+
}
|
|
972
|
+
sqlCondition = await executeLazyOperator(lazyOp, encryptedValues);
|
|
973
|
+
} else {
|
|
974
|
+
sqlCondition = lazyOp.execute(lazyOp.right);
|
|
975
|
+
}
|
|
976
|
+
sqlConditions.push(sqlCondition);
|
|
977
|
+
}
|
|
978
|
+
const regularPromisesResults = await Promise.all(regularPromises);
|
|
979
|
+
const allConditions = [
|
|
980
|
+
...regularConditions,
|
|
981
|
+
...sqlConditions,
|
|
982
|
+
...regularPromisesResults
|
|
983
|
+
];
|
|
984
|
+
return and(...allConditions) ?? sql`true`;
|
|
985
|
+
};
|
|
986
|
+
const encryptedOr = async (...conditions) => {
|
|
987
|
+
const lazyOperators = [];
|
|
988
|
+
const regularConditions = [];
|
|
989
|
+
const regularPromises = [];
|
|
990
|
+
for (const condition of conditions) {
|
|
991
|
+
if (condition === void 0) {
|
|
992
|
+
continue;
|
|
993
|
+
}
|
|
994
|
+
if (isLazyOperator(condition)) {
|
|
995
|
+
lazyOperators.push(condition);
|
|
996
|
+
} else if (condition instanceof Promise) {
|
|
997
|
+
if (isLazyOperator(condition)) {
|
|
998
|
+
lazyOperators.push(condition);
|
|
999
|
+
} else {
|
|
1000
|
+
regularPromises.push(condition);
|
|
1001
|
+
}
|
|
1002
|
+
} else {
|
|
1003
|
+
regularConditions.push(condition);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (lazyOperators.length === 0) {
|
|
1007
|
+
const allConditions2 = [
|
|
1008
|
+
...regularConditions,
|
|
1009
|
+
...await Promise.all(regularPromises)
|
|
1010
|
+
];
|
|
1011
|
+
return or(...allConditions2) ?? sql`false`;
|
|
1012
|
+
}
|
|
1013
|
+
const valuesToEncrypt = [];
|
|
1014
|
+
for (let i = 0; i < lazyOperators.length; i++) {
|
|
1015
|
+
const lazyOp = lazyOperators[i];
|
|
1016
|
+
if (!lazyOp.needsEncryption) {
|
|
1017
|
+
continue;
|
|
1018
|
+
}
|
|
1019
|
+
if (lazyOp.min !== void 0 && lazyOp.max !== void 0) {
|
|
1020
|
+
valuesToEncrypt.push({
|
|
1021
|
+
value: lazyOp.min,
|
|
1022
|
+
column: lazyOp.left,
|
|
1023
|
+
columnInfo: lazyOp.columnInfo,
|
|
1024
|
+
queryType: lazyOp.queryType,
|
|
1025
|
+
lazyOpIndex: i,
|
|
1026
|
+
isMin: true
|
|
1027
|
+
});
|
|
1028
|
+
valuesToEncrypt.push({
|
|
1029
|
+
value: lazyOp.max,
|
|
1030
|
+
column: lazyOp.left,
|
|
1031
|
+
columnInfo: lazyOp.columnInfo,
|
|
1032
|
+
queryType: lazyOp.queryType,
|
|
1033
|
+
lazyOpIndex: i,
|
|
1034
|
+
isMax: true
|
|
1035
|
+
});
|
|
1036
|
+
} else if (lazyOp.right !== void 0) {
|
|
1037
|
+
valuesToEncrypt.push({
|
|
1038
|
+
value: lazyOp.right,
|
|
1039
|
+
column: lazyOp.left,
|
|
1040
|
+
columnInfo: lazyOp.columnInfo,
|
|
1041
|
+
queryType: lazyOp.queryType,
|
|
1042
|
+
lazyOpIndex: i
|
|
1043
|
+
});
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
const encryptedResults = await encryptValues(
|
|
1047
|
+
encryptionClient,
|
|
1048
|
+
valuesToEncrypt.map((v) => ({
|
|
1049
|
+
value: v.value,
|
|
1050
|
+
column: v.column,
|
|
1051
|
+
queryType: v.queryType
|
|
1052
|
+
})),
|
|
1053
|
+
defaultTable,
|
|
1054
|
+
tableCache
|
|
1055
|
+
);
|
|
1056
|
+
const encryptedByLazyOp = /* @__PURE__ */ new Map();
|
|
1057
|
+
for (let i = 0; i < valuesToEncrypt.length; i++) {
|
|
1058
|
+
const { lazyOpIndex, isMin, isMax } = valuesToEncrypt[i];
|
|
1059
|
+
const encrypted = encryptedResults[i];
|
|
1060
|
+
let group = encryptedByLazyOp.get(lazyOpIndex);
|
|
1061
|
+
if (!group) {
|
|
1062
|
+
group = {};
|
|
1063
|
+
encryptedByLazyOp.set(lazyOpIndex, group);
|
|
1064
|
+
}
|
|
1065
|
+
if (isMin) {
|
|
1066
|
+
group.min = encrypted;
|
|
1067
|
+
} else if (isMax) {
|
|
1068
|
+
group.max = encrypted;
|
|
1069
|
+
} else {
|
|
1070
|
+
group.value = encrypted;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
const sqlConditions = [];
|
|
1074
|
+
for (let i = 0; i < lazyOperators.length; i++) {
|
|
1075
|
+
const lazyOp = lazyOperators[i];
|
|
1076
|
+
const encrypted = encryptedByLazyOp.get(i);
|
|
1077
|
+
let sqlCondition;
|
|
1078
|
+
if (lazyOp.needsEncryption && encrypted) {
|
|
1079
|
+
const encryptedValues = [];
|
|
1080
|
+
if (encrypted.value !== void 0) {
|
|
1081
|
+
encryptedValues.push({
|
|
1082
|
+
value: lazyOp.right,
|
|
1083
|
+
encrypted: encrypted.value
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
if (encrypted.min !== void 0) {
|
|
1087
|
+
encryptedValues.push({ value: lazyOp.min, encrypted: encrypted.min });
|
|
1088
|
+
}
|
|
1089
|
+
if (encrypted.max !== void 0) {
|
|
1090
|
+
encryptedValues.push({ value: lazyOp.max, encrypted: encrypted.max });
|
|
1091
|
+
}
|
|
1092
|
+
sqlCondition = await executeLazyOperator(lazyOp, encryptedValues);
|
|
1093
|
+
} else {
|
|
1094
|
+
sqlCondition = lazyOp.execute(lazyOp.right);
|
|
1095
|
+
}
|
|
1096
|
+
sqlConditions.push(sqlCondition);
|
|
1097
|
+
}
|
|
1098
|
+
const regularPromisesResults = await Promise.all(regularPromises);
|
|
1099
|
+
const allConditions = [
|
|
1100
|
+
...regularConditions,
|
|
1101
|
+
...sqlConditions,
|
|
1102
|
+
...regularPromisesResults
|
|
1103
|
+
];
|
|
1104
|
+
return or(...allConditions) ?? sql`false`;
|
|
1105
|
+
};
|
|
1106
|
+
return {
|
|
1107
|
+
// Comparison operators
|
|
1108
|
+
eq: encryptedEq,
|
|
1109
|
+
ne: encryptedNe,
|
|
1110
|
+
gt: encryptedGt,
|
|
1111
|
+
gte: encryptedGte,
|
|
1112
|
+
lt: encryptedLt,
|
|
1113
|
+
lte: encryptedLte,
|
|
1114
|
+
// Range operators
|
|
1115
|
+
between: encryptedBetween,
|
|
1116
|
+
notBetween: encryptedNotBetween,
|
|
1117
|
+
// Text search operators
|
|
1118
|
+
like: encryptedLike,
|
|
1119
|
+
ilike: encryptedIlike,
|
|
1120
|
+
notIlike: encryptedNotIlike,
|
|
1121
|
+
// Searchable JSON operators
|
|
1122
|
+
jsonbPathQueryFirst: encryptedJsonbPathQueryFirst,
|
|
1123
|
+
jsonbGet: encryptedJsonbGet,
|
|
1124
|
+
jsonbPathExists: encryptedJsonbPathExists,
|
|
1125
|
+
// Array operators
|
|
1126
|
+
inArray: encryptedInArray,
|
|
1127
|
+
notInArray: encryptedNotInArray,
|
|
1128
|
+
// Sorting operators
|
|
1129
|
+
asc: encryptedAsc,
|
|
1130
|
+
desc: encryptedDesc,
|
|
1131
|
+
// AND operator - batches encryption operations
|
|
1132
|
+
and: encryptedAnd,
|
|
1133
|
+
// OR operator - batches encryption operations
|
|
1134
|
+
or: encryptedOr,
|
|
1135
|
+
// Operators that don't need encryption (pass through to Drizzle)
|
|
1136
|
+
exists,
|
|
1137
|
+
notExists,
|
|
1138
|
+
isNull,
|
|
1139
|
+
isNotNull,
|
|
1140
|
+
not,
|
|
1141
|
+
// Array operators that work with arrays directly (not encrypted values)
|
|
1142
|
+
arrayContains,
|
|
1143
|
+
arrayContained,
|
|
1144
|
+
arrayOverlaps
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// src/drizzle/index.ts
|
|
1149
|
+
var columnConfigMap = /* @__PURE__ */ new Map();
|
|
1150
|
+
var encryptedType = (name, config) => {
|
|
1151
|
+
const customColumnType = customType({
|
|
1152
|
+
dataType() {
|
|
1153
|
+
return "eql_v2_encrypted";
|
|
1154
|
+
},
|
|
1155
|
+
toDriver(value) {
|
|
1156
|
+
const jsonStr = JSON.stringify(value);
|
|
1157
|
+
const escaped = jsonStr.replace(/"/g, '""');
|
|
1158
|
+
return `("${escaped}")`;
|
|
1159
|
+
},
|
|
1160
|
+
fromDriver(value) {
|
|
1161
|
+
const parseComposite = (str) => {
|
|
1162
|
+
if (!str || str === "") return null;
|
|
1163
|
+
const trimmed = str.trim();
|
|
1164
|
+
if (trimmed.startsWith("(") && trimmed.endsWith(")")) {
|
|
1165
|
+
let inner = trimmed.slice(1, -1);
|
|
1166
|
+
inner = inner.replace(/""/g, '"');
|
|
1167
|
+
if (inner.startsWith('"') && inner.endsWith('"')) {
|
|
1168
|
+
const stripped = inner.slice(1, -1);
|
|
1169
|
+
return JSON.parse(stripped);
|
|
1170
|
+
}
|
|
1171
|
+
if (inner.startsWith("{") || inner.startsWith("[")) {
|
|
1172
|
+
return JSON.parse(inner);
|
|
1173
|
+
}
|
|
1174
|
+
return inner;
|
|
1175
|
+
}
|
|
1176
|
+
return JSON.parse(str);
|
|
1177
|
+
};
|
|
1178
|
+
return parseComposite(value);
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
const column = customColumnType(name);
|
|
1182
|
+
const fullConfig = {
|
|
1183
|
+
name,
|
|
1184
|
+
...config
|
|
1185
|
+
};
|
|
1186
|
+
columnConfigMap.set(name, fullConfig);
|
|
1187
|
+
column._encryptionConfig = fullConfig;
|
|
1188
|
+
return column;
|
|
1189
|
+
};
|
|
1190
|
+
function getEncryptedColumnConfig(columnName, column) {
|
|
1191
|
+
if (column && typeof column === "object") {
|
|
1192
|
+
const columnAny = column;
|
|
1193
|
+
const isEncrypted = columnAny.sqlName === "eql_v2_encrypted" || columnAny.dataType === "eql_v2_encrypted" || columnAny.dataType && typeof columnAny.dataType === "function" && columnAny.dataType() === "eql_v2_encrypted";
|
|
1194
|
+
if (isEncrypted) {
|
|
1195
|
+
if (columnAny._encryptionConfig) {
|
|
1196
|
+
return columnAny._encryptionConfig;
|
|
1197
|
+
}
|
|
1198
|
+
const lookupName = columnAny.name || columnName;
|
|
1199
|
+
return columnConfigMap.get(lookupName);
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
return void 0;
|
|
1203
|
+
}
|
|
1204
|
+
export {
|
|
1205
|
+
EncryptionConfigError,
|
|
1206
|
+
EncryptionOperatorError,
|
|
1207
|
+
createEncryptionOperators,
|
|
1208
|
+
encryptedType,
|
|
1209
|
+
extractEncryptionSchema,
|
|
1210
|
+
getEncryptedColumnConfig
|
|
1211
|
+
};
|
|
1212
|
+
//# sourceMappingURL=index.js.map
|