mask-privacy 4.0.0 → 4.2.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/dist/index.d.mts +37 -31
- package/dist/index.d.ts +37 -31
- package/dist/index.js +794 -370
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +767 -342
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/config.ts +5 -0
- package/src/core/crypto.ts +171 -87
- package/src/core/exceptions.ts +25 -0
- package/src/core/ff1.ts +196 -0
- package/src/core/fpe.ts +97 -175
- package/src/core/fpe_utils.ts +57 -11
- package/src/core/key_provider.ts +80 -0
- package/src/core/vault.ts +152 -78
- package/src/telemetry/audit_logger.ts +136 -16
- package/tests/bijective_fpe.test.ts +16 -12
- package/tests/fpe.test.ts +17 -8
- package/tests/security_hardening.test.ts +117 -0
- package/tests/vault.test.ts +67 -0
- package/tests/vault_backends.test.ts +7 -7
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import * as process2 from 'process';
|
|
2
2
|
import { env, versions } from 'process';
|
|
3
|
-
import * as
|
|
3
|
+
import * as path2 from 'path';
|
|
4
4
|
import { join, normalize, sep, dirname } from 'path';
|
|
5
5
|
import * as os from 'os';
|
|
6
6
|
import { platform, release, homedir } from 'os';
|
|
7
|
-
import * as
|
|
8
|
-
import
|
|
7
|
+
import * as cryptoNode from 'crypto';
|
|
8
|
+
import cryptoNode__default, { createHmac, createHash, createPrivateKey, createPublicKey, sign } from 'crypto';
|
|
9
|
+
import * as fs from 'fs';
|
|
10
|
+
import { ReadStream, lstatSync, fstatSync, readFileSync, promises } from 'fs';
|
|
9
11
|
import { Buffer as Buffer$1 } from 'buffer';
|
|
10
12
|
import { Writable, Readable } from 'stream';
|
|
11
13
|
import { Agent, request as request$1 } from 'https';
|
|
12
14
|
import http2, { constants } from 'http2';
|
|
13
|
-
import
|
|
15
|
+
import fs2, { readFile } from 'fs/promises';
|
|
14
16
|
import { request } from 'http';
|
|
15
17
|
import { parse } from 'url';
|
|
16
|
-
import { ReadStream, lstatSync, fstatSync, readFileSync, promises } from 'fs';
|
|
17
18
|
import { exec } from 'child_process';
|
|
18
19
|
import { promisify } from 'util';
|
|
19
20
|
|
|
@@ -103,6 +104,11 @@ var init_config = __esm({
|
|
|
103
104
|
get MASK_ENCRYPTION_KEY() {
|
|
104
105
|
return process2.env.MASK_ENCRYPTION_KEY || null;
|
|
105
106
|
},
|
|
107
|
+
// JSON map of keyId -> base64 key string for key rotation, e.g. {"v1":"...","v2":"..."}
|
|
108
|
+
// The last entry in the map is treated as the active (encryption) key.
|
|
109
|
+
get MASK_KEYRING() {
|
|
110
|
+
return process2.env.MASK_KEYRING || null;
|
|
111
|
+
},
|
|
106
112
|
get MASK_MASTER_KEY() {
|
|
107
113
|
return process2.env.MASK_MASTER_KEY || process2.env.MASK_ENCRYPTION_KEY || "";
|
|
108
114
|
},
|
|
@@ -115,6 +121,9 @@ var init_config = __esm({
|
|
|
115
121
|
get MASK_BLIND_INDEX_SALT() {
|
|
116
122
|
return process2.env.MASK_BLIND_INDEX_SALT || "mask-blind-index";
|
|
117
123
|
},
|
|
124
|
+
get MASK_KDF_SALT() {
|
|
125
|
+
return process2.env.MASK_KDF_SALT || "mask-kdf-v4-argon2id";
|
|
126
|
+
},
|
|
118
127
|
get VAULT_TOKEN() {
|
|
119
128
|
return process2.env.VAULT_TOKEN || null;
|
|
120
129
|
},
|
|
@@ -131,6 +140,9 @@ var init_config = __esm({
|
|
|
131
140
|
get MASK_VAULT_CLEANUP_FREQUENCY() {
|
|
132
141
|
return getEnvFloat("MASK_VAULT_CLEANUP_FREQUENCY", 0.01);
|
|
133
142
|
},
|
|
143
|
+
get MASK_VAULT_MAX_MEMORY_KEYS() {
|
|
144
|
+
return getEnvInt("MASK_VAULT_MAX_MEMORY_KEYS", 1e5);
|
|
145
|
+
},
|
|
134
146
|
// --- BACKEND CONNECTIONS ---
|
|
135
147
|
get MASK_REDIS_URL() {
|
|
136
148
|
return process2.env.MASK_REDIS_URL || "redis://localhost:6379/0";
|
|
@@ -170,7 +182,7 @@ var init_config = __esm({
|
|
|
170
182
|
return process2.env.MASK_SCANNER_URL || "http://localhost:5001/analyze";
|
|
171
183
|
},
|
|
172
184
|
get MASK_MODEL_CACHE_DIR() {
|
|
173
|
-
return process2.env.MASK_MODEL_CACHE_DIR ||
|
|
185
|
+
return process2.env.MASK_MODEL_CACHE_DIR || path2.join(os.homedir(), ".cache", "mask");
|
|
174
186
|
},
|
|
175
187
|
// --- TELEMETRY & AUDIT ---
|
|
176
188
|
get MASK_AUDIT_LOG_STRICT() {
|
|
@@ -195,6 +207,16 @@ var init_key_provider = __esm({
|
|
|
195
207
|
"src/core/key_provider.ts"() {
|
|
196
208
|
init_config();
|
|
197
209
|
BaseKeyProvider = class {
|
|
210
|
+
/**
|
|
211
|
+
* Return a JSON keyring string (e.g. from KMS / Secrets Manager), or null
|
|
212
|
+
* to fall back to the MASK_KEYRING environment variable.
|
|
213
|
+
*
|
|
214
|
+
* Override in KMS-backed providers to source the full keyring from a
|
|
215
|
+
* secure external store, removing the need for MASK_KEYRING in env vars.
|
|
216
|
+
*/
|
|
217
|
+
getKeyring() {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
198
220
|
};
|
|
199
221
|
EnvKeyProvider = class extends BaseKeyProvider {
|
|
200
222
|
async getEncryptionKey() {
|
|
@@ -210,13 +232,17 @@ var init_key_provider = __esm({
|
|
|
210
232
|
let key = config.MASK_MASTER_KEY;
|
|
211
233
|
return key || null;
|
|
212
234
|
}
|
|
235
|
+
/** Return MASK_KEYRING from environment (default behaviour). */
|
|
236
|
+
async getKeyring() {
|
|
237
|
+
return config.MASK_KEYRING || null;
|
|
238
|
+
}
|
|
213
239
|
};
|
|
214
240
|
providerInstance = null;
|
|
215
241
|
}
|
|
216
242
|
});
|
|
217
243
|
|
|
218
244
|
// src/core/exceptions.ts
|
|
219
|
-
var MaskError, MaskVaultConnectionError, MaskDecryptionError, MaskNLPTimeout, MaskSecurityError;
|
|
245
|
+
var MaskError, MaskVaultConnectionError, MaskDecryptionError, MaskNLPTimeout, MaskSecurityError, TokenCollisionError;
|
|
220
246
|
var init_exceptions = __esm({
|
|
221
247
|
"src/core/exceptions.ts"() {
|
|
222
248
|
MaskError = class extends Error {
|
|
@@ -234,6 +260,185 @@ var init_exceptions = __esm({
|
|
|
234
260
|
};
|
|
235
261
|
MaskSecurityError = class extends MaskError {
|
|
236
262
|
};
|
|
263
|
+
TokenCollisionError = class extends MaskError {
|
|
264
|
+
constructor(token, existingHash, incomingHash) {
|
|
265
|
+
super(
|
|
266
|
+
`Token collision detected for token '${token}'. Existing plaintext hash '${existingHash.slice(0, 8)}\u2026' conflicts with incoming hash '${incomingHash.slice(0, 8)}\u2026'. Increase token entropy or adjust tenant salt configuration.`
|
|
267
|
+
);
|
|
268
|
+
this.token = token;
|
|
269
|
+
this.existingHash = existingHash;
|
|
270
|
+
this.incomingHash = incomingHash;
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
var FF1;
|
|
276
|
+
var init_ff1 = __esm({
|
|
277
|
+
"src/core/ff1.ts"() {
|
|
278
|
+
FF1 = class {
|
|
279
|
+
constructor(key, tweak, radix) {
|
|
280
|
+
this.chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
281
|
+
this.key = key;
|
|
282
|
+
this.tweak = tweak;
|
|
283
|
+
this.radix = radix;
|
|
284
|
+
if (radix > this.chars.length) {
|
|
285
|
+
throw new Error(`Radix ${radix} not supported`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
_prf(x6) {
|
|
289
|
+
const cipher = cryptoNode.createCipheriv("aes-256-cbc", this.key, Buffer.alloc(16, 0));
|
|
290
|
+
cipher.setAutoPadding(false);
|
|
291
|
+
return Buffer.concat([cipher.update(x6), cipher.final()]).subarray(-16);
|
|
292
|
+
}
|
|
293
|
+
_ciph(x6) {
|
|
294
|
+
const cipher = cryptoNode.createCipheriv("aes-256-ecb", this.key, null);
|
|
295
|
+
cipher.setAutoPadding(false);
|
|
296
|
+
return Buffer.concat([cipher.update(x6), cipher.final()]);
|
|
297
|
+
}
|
|
298
|
+
_strToInt(s6) {
|
|
299
|
+
let n6 = 0n;
|
|
300
|
+
const r6 = BigInt(this.radix);
|
|
301
|
+
for (let i6 = 0; i6 < s6.length; i6++) {
|
|
302
|
+
n6 = n6 * r6 + BigInt(this.chars.indexOf(s6[i6]));
|
|
303
|
+
}
|
|
304
|
+
return n6;
|
|
305
|
+
}
|
|
306
|
+
_intToStr(num, length) {
|
|
307
|
+
if (num === 0n) {
|
|
308
|
+
return this.chars[0].repeat(length);
|
|
309
|
+
}
|
|
310
|
+
let digits = [];
|
|
311
|
+
let n6 = num;
|
|
312
|
+
const r6 = BigInt(this.radix);
|
|
313
|
+
while (n6 > 0n) {
|
|
314
|
+
digits.push(this.chars[Number(n6 % r6)]);
|
|
315
|
+
n6 /= r6;
|
|
316
|
+
}
|
|
317
|
+
let s6 = digits.reverse().join("");
|
|
318
|
+
while (s6.length < length) s6 = this.chars[0] + s6;
|
|
319
|
+
return s6;
|
|
320
|
+
}
|
|
321
|
+
_bigintToBuffer(num, bytes) {
|
|
322
|
+
const buf = Buffer.alloc(bytes);
|
|
323
|
+
let n6 = num;
|
|
324
|
+
for (let i6 = bytes - 1; i6 >= 0; i6--) {
|
|
325
|
+
buf[i6] = Number(n6 & 0xFFn);
|
|
326
|
+
n6 >>= 8n;
|
|
327
|
+
}
|
|
328
|
+
return buf;
|
|
329
|
+
}
|
|
330
|
+
encrypt(X) {
|
|
331
|
+
const n6 = X.length;
|
|
332
|
+
const t6 = this.tweak.length;
|
|
333
|
+
if (n6 < 2) return X;
|
|
334
|
+
const u6 = Math.floor(n6 / 2);
|
|
335
|
+
const v7 = n6 - u6;
|
|
336
|
+
let A3 = X.substring(0, u6);
|
|
337
|
+
let B3 = X.substring(u6);
|
|
338
|
+
const b6 = Math.ceil(Math.ceil(v7 * Math.log2(this.radix)) / 8);
|
|
339
|
+
const d6 = 4 * Math.ceil(b6 / 4) + 4;
|
|
340
|
+
const P2 = Buffer.alloc(16);
|
|
341
|
+
P2[0] = 1;
|
|
342
|
+
P2[1] = 2;
|
|
343
|
+
P2[2] = 1;
|
|
344
|
+
P2.writeUIntBE(this.radix, 3, 3);
|
|
345
|
+
P2[6] = 10;
|
|
346
|
+
P2[7] = u6 % 256;
|
|
347
|
+
P2.writeUInt32BE(n6, 8);
|
|
348
|
+
P2.writeUInt32BE(t6, 12);
|
|
349
|
+
for (let i6 = 0; i6 < 10; i6++) {
|
|
350
|
+
const m6 = i6 % 2 === 0 ? u6 : v7;
|
|
351
|
+
const padLen = ((-t6 - b6 - 1) % 16 + 16) % 16;
|
|
352
|
+
const Q2 = Buffer.alloc(t6 + padLen + 1 + b6);
|
|
353
|
+
this.tweak.copy(Q2, 0);
|
|
354
|
+
Q2[t6 + padLen] = i6;
|
|
355
|
+
this._bigintToBuffer(this._strToInt(B3), b6).copy(Q2, t6 + padLen + 1);
|
|
356
|
+
const R2 = this._prf(Buffer.concat([P2, Q2]));
|
|
357
|
+
let S2 = Buffer.from(R2);
|
|
358
|
+
let j6 = 1;
|
|
359
|
+
while (S2.length < d6) {
|
|
360
|
+
const xorBlock = Buffer.alloc(16);
|
|
361
|
+
const jBuf = Buffer.alloc(16);
|
|
362
|
+
jBuf.writeUInt32BE(j6, 12);
|
|
363
|
+
for (let k6 = 0; k6 < 16; k6++) xorBlock[k6] = R2[k6] ^ jBuf[k6];
|
|
364
|
+
S2 = Buffer.concat([S2, this._ciph(xorBlock)]);
|
|
365
|
+
j6++;
|
|
366
|
+
}
|
|
367
|
+
S2 = S2.subarray(0, d6);
|
|
368
|
+
let y3 = 0n;
|
|
369
|
+
for (let k6 = 0; k6 < S2.length; k6++) {
|
|
370
|
+
y3 = (y3 << 8n) + BigInt(S2[k6]);
|
|
371
|
+
}
|
|
372
|
+
const modulo = BigInt(this.radix) ** BigInt(m6);
|
|
373
|
+
const c6 = (this._strToInt(A3) + y3) % modulo;
|
|
374
|
+
const C3 = this._intToStr(c6, m6);
|
|
375
|
+
A3 = B3;
|
|
376
|
+
B3 = C3;
|
|
377
|
+
}
|
|
378
|
+
return A3 + B3;
|
|
379
|
+
}
|
|
380
|
+
decrypt(X) {
|
|
381
|
+
const n6 = X.length;
|
|
382
|
+
const t6 = this.tweak.length;
|
|
383
|
+
if (n6 < 2) return X;
|
|
384
|
+
const u6 = Math.floor(n6 / 2);
|
|
385
|
+
const v7 = n6 - u6;
|
|
386
|
+
let A3 = X.substring(0, u6);
|
|
387
|
+
let B3 = X.substring(u6);
|
|
388
|
+
if (n6 % 2 !== 0) {
|
|
389
|
+
const temp = A3;
|
|
390
|
+
A3 = B3;
|
|
391
|
+
B3 = temp;
|
|
392
|
+
}
|
|
393
|
+
const b6 = Math.ceil(Math.ceil(v7 * Math.log2(this.radix)) / 8);
|
|
394
|
+
const d6 = 4 * Math.ceil(b6 / 4) + 4;
|
|
395
|
+
const P2 = Buffer.alloc(16);
|
|
396
|
+
P2[0] = 1;
|
|
397
|
+
P2[1] = 2;
|
|
398
|
+
P2[2] = 1;
|
|
399
|
+
P2.writeUIntBE(this.radix, 3, 3);
|
|
400
|
+
P2[6] = 10;
|
|
401
|
+
P2[7] = u6 % 256;
|
|
402
|
+
P2.writeUInt32BE(n6, 8);
|
|
403
|
+
P2.writeUInt32BE(t6, 12);
|
|
404
|
+
for (let i6 = 9; i6 >= 0; i6--) {
|
|
405
|
+
const m6 = i6 % 2 === 0 ? u6 : v7;
|
|
406
|
+
const padLen = ((-t6 - b6 - 1) % 16 + 16) % 16;
|
|
407
|
+
const Q2 = Buffer.alloc(t6 + padLen + 1 + b6);
|
|
408
|
+
this.tweak.copy(Q2, 0);
|
|
409
|
+
Q2[t6 + padLen] = i6;
|
|
410
|
+
this._bigintToBuffer(this._strToInt(A3), b6).copy(Q2, t6 + padLen + 1);
|
|
411
|
+
const R2 = this._prf(Buffer.concat([P2, Q2]));
|
|
412
|
+
let S2 = Buffer.from(R2);
|
|
413
|
+
let j6 = 1;
|
|
414
|
+
while (S2.length < d6) {
|
|
415
|
+
const xorBlock = Buffer.alloc(16);
|
|
416
|
+
const jBuf = Buffer.alloc(16);
|
|
417
|
+
jBuf.writeUInt32BE(j6, 12);
|
|
418
|
+
for (let k6 = 0; k6 < 16; k6++) xorBlock[k6] = R2[k6] ^ jBuf[k6];
|
|
419
|
+
S2 = Buffer.concat([S2, this._ciph(xorBlock)]);
|
|
420
|
+
j6++;
|
|
421
|
+
}
|
|
422
|
+
S2 = S2.subarray(0, d6);
|
|
423
|
+
let y3 = 0n;
|
|
424
|
+
for (let k6 = 0; k6 < S2.length; k6++) {
|
|
425
|
+
y3 = (y3 << 8n) + BigInt(S2[k6]);
|
|
426
|
+
}
|
|
427
|
+
const modulo = BigInt(this.radix) ** BigInt(m6);
|
|
428
|
+
let c6 = (this._strToInt(B3) - y3) % modulo;
|
|
429
|
+
if (c6 < 0n) c6 += modulo;
|
|
430
|
+
const C3 = this._intToStr(c6, m6);
|
|
431
|
+
B3 = A3;
|
|
432
|
+
A3 = C3;
|
|
433
|
+
}
|
|
434
|
+
if (n6 % 2 !== 0) {
|
|
435
|
+
const temp = A3;
|
|
436
|
+
A3 = B3;
|
|
437
|
+
B3 = temp;
|
|
438
|
+
}
|
|
439
|
+
return A3 + B3;
|
|
440
|
+
}
|
|
441
|
+
};
|
|
237
442
|
}
|
|
238
443
|
});
|
|
239
444
|
|
|
@@ -460,13 +665,13 @@ function looksLikeToken(value) {
|
|
|
460
665
|
if (/^\+[1-9]\d{0,3}-555-\d{7}$/.test(v7)) {
|
|
461
666
|
return true;
|
|
462
667
|
}
|
|
463
|
-
if (
|
|
668
|
+
if (/^\d{3}-\d{2}-\d{4}$/.test(v7)) {
|
|
464
669
|
return true;
|
|
465
670
|
}
|
|
466
|
-
if (
|
|
671
|
+
if (/^\d{4}-\d{4}-\d{4}-\d{4}$/.test(v7)) {
|
|
467
672
|
return true;
|
|
468
673
|
}
|
|
469
|
-
if (v7.
|
|
674
|
+
if (v7.length === 9 && /^\d+$/.test(v7)) {
|
|
470
675
|
return true;
|
|
471
676
|
}
|
|
472
677
|
if (v7.length === 9 && v7.startsWith("000") && /[A-Z]$/.test(v7)) {
|
|
@@ -490,11 +695,28 @@ function looksLikeToken(value) {
|
|
|
490
695
|
}
|
|
491
696
|
return false;
|
|
492
697
|
}
|
|
698
|
+
function isUnambiguouslySafeToken(value) {
|
|
699
|
+
if (typeof value !== "string") return false;
|
|
700
|
+
const v7 = value.trim();
|
|
701
|
+
if (v7.startsWith("tkn-") && v7.includes("@")) {
|
|
702
|
+
const parts = v7.split("@");
|
|
703
|
+
if (parts.length === 2 && parts[0].length >= 12 && parts[1].includes(".")) {
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
if (/^\+[1-9]\d{0,3}-555-\d{7}$/.test(v7)) return true;
|
|
708
|
+
if (/^000\d{5}[A-Z]$/.test(v7)) return true;
|
|
709
|
+
if (/^[A-Z]{2}00[A-F0-9]{4,16}$/.test(v7)) return true;
|
|
710
|
+
if (/^<(PER|LOC|ORG):[^>]+>$/.test(v7)) return true;
|
|
711
|
+
if (v7.startsWith("[TKN-") && v7.endsWith("]")) return true;
|
|
712
|
+
if (/^[A-Z][a-zA-Z, ]+-[0-9]{3,4}$/.test(v7)) return true;
|
|
713
|
+
return false;
|
|
714
|
+
}
|
|
493
715
|
var TOKEN_PATTERN;
|
|
494
716
|
var init_fpe_utils = __esm({
|
|
495
717
|
"src/core/fpe_utils.ts"() {
|
|
496
718
|
TOKEN_PATTERN = new RegExp(
|
|
497
|
-
"tkn-[a-f0-9]{8,64}@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}|\\+[1-9]\\d{0,3}-555-\\d{7}
|
|
719
|
+
"tkn-[a-f0-9]{8,64}@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}|\\+[1-9]\\d{0,3}-555-\\d{7}|\\d{3}-\\d{2}-\\d{4}|\\d{4}-\\d{4}-\\d{4}-\\d{4}|\\b\\d{9}\\b|\\b000\\d{5}[A-Z]\\b|[A-Z]{2}00[A-F0-9]{4,16}|<(?:PER|LOC|ORG):[^>]+>|\\b[A-Z][a-zA-Z, ]+-[0-9]{3,4}\\b|\\[TKN-[^\\]]+\\]",
|
|
498
720
|
// Opaque
|
|
499
721
|
"g"
|
|
500
722
|
);
|
|
@@ -509,12 +731,10 @@ async function _getMasterKey() {
|
|
|
509
731
|
}
|
|
510
732
|
if (!raw) {
|
|
511
733
|
if (config.MASK_DEV_MODE) {
|
|
512
|
-
raw =
|
|
734
|
+
raw = cryptoNode.randomBytes(32).toString("hex");
|
|
513
735
|
process.env.MASK_MASTER_KEY = raw;
|
|
514
736
|
} else {
|
|
515
|
-
throw new MaskSecurityError(
|
|
516
|
-
"MASK_MASTER_KEY not set. Set it or use MASK_DEV_MODE=true for dev."
|
|
517
|
-
);
|
|
737
|
+
throw new MaskSecurityError("MASK_MASTER_KEY not set.");
|
|
518
738
|
}
|
|
519
739
|
}
|
|
520
740
|
_masterKey = Buffer.from(raw, "utf-8");
|
|
@@ -524,38 +744,34 @@ async function _getMasterKey() {
|
|
|
524
744
|
function resetMasterKey() {
|
|
525
745
|
_masterKey = null;
|
|
526
746
|
}
|
|
527
|
-
async function
|
|
747
|
+
async function _getAesKey() {
|
|
528
748
|
const masterKey = await _getMasterKey();
|
|
529
|
-
|
|
530
|
-
return digest.slice(0, n6);
|
|
749
|
+
return cryptoNode.createHmac("sha256", masterKey).update(config.MASK_TENANT_ID, "utf-8").digest();
|
|
531
750
|
}
|
|
532
|
-
async function
|
|
751
|
+
async function _hmacHex(plaintext, n6 = 8) {
|
|
533
752
|
const masterKey = await _getMasterKey();
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
for (let i6 = 0; i6 < 16; i6++) {
|
|
537
|
-
result = result << 8n | BigInt(raw[i6]);
|
|
538
|
-
}
|
|
539
|
-
return result;
|
|
540
|
-
}
|
|
541
|
-
async function _hmacDigits(plaintext, n6, offset = 0) {
|
|
542
|
-
const salted = offset ? `${plaintext}::${offset}` : plaintext;
|
|
543
|
-
const seed = await _hmacInt(salted);
|
|
544
|
-
const modulus = 10n ** BigInt(n6);
|
|
545
|
-
return (seed % modulus).toString().padStart(n6, "0");
|
|
753
|
+
const digest = cryptoNode.createHmac("sha256", masterKey).update(plaintext, "utf-8").digest("hex");
|
|
754
|
+
return digest.slice(0, n6);
|
|
546
755
|
}
|
|
547
756
|
async function _getBijectiveTweak() {
|
|
548
|
-
const masterKey = await _getMasterKey();
|
|
549
|
-
let base = config.MASK_TENANT_ID;
|
|
550
757
|
if (config.MASK_SALT_ROTATION !== "NONE") {
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
} else if (config.MASK_SALT_ROTATION === "YEARLY") {
|
|
555
|
-
base += `-${now.getUTCFullYear()}`;
|
|
556
|
-
}
|
|
758
|
+
console.warn(
|
|
759
|
+
`[mask] MASK_SALT_ROTATION=${config.MASK_SALT_ROTATION} is deprecated and ignored. Time-based tweaks caused permanent data loss on month/year rollovers. Use MASK_KEYRING for key rotation instead.`
|
|
760
|
+
);
|
|
557
761
|
}
|
|
558
|
-
|
|
762
|
+
const masterKey = await _getMasterKey();
|
|
763
|
+
return cryptoNode.createHmac("sha256", masterKey).update(config.MASK_TENANT_ID, "utf-8").digest();
|
|
764
|
+
}
|
|
765
|
+
async function _encryptBijectiveFF1(text) {
|
|
766
|
+
const canonical = text.toLowerCase().trim();
|
|
767
|
+
const hash = cryptoNode.createHash("sha256").update(canonical, "utf-8").digest();
|
|
768
|
+
const inputInt = hash.readBigUInt64BE(0);
|
|
769
|
+
const inputStr = inputInt.toString().padStart(20, "0");
|
|
770
|
+
const aesKey = await _getAesKey();
|
|
771
|
+
const tweak = await _getBijectiveTweak();
|
|
772
|
+
const engine = new FF1(aesKey, tweak, 10);
|
|
773
|
+
const cipherStr = engine.encrypt(inputStr);
|
|
774
|
+
return BigInt(cipherStr) % 2n ** 64n;
|
|
559
775
|
}
|
|
560
776
|
function _renderBijectivePerson(bits) {
|
|
561
777
|
const firstIdx = Number(bits & 0x7FFn);
|
|
@@ -603,7 +819,10 @@ function _computeLuhnDigit(partialNum) {
|
|
|
603
819
|
function _computeEsIdCheck(num) {
|
|
604
820
|
return "TRWAGMYFPDXBNJZSQVHLCKE"[num % 23];
|
|
605
821
|
}
|
|
606
|
-
|
|
822
|
+
function _stripCcSeparators(text) {
|
|
823
|
+
return text.replace(/[\s\-]/g, "");
|
|
824
|
+
}
|
|
825
|
+
async function generateDPToken(rawText, entityType = "UNKNOWN") {
|
|
607
826
|
const text = rawText.trim();
|
|
608
827
|
let type = (entityType || "UNKNOWN").toUpperCase();
|
|
609
828
|
if (type === "UNKNOWN") {
|
|
@@ -623,49 +842,73 @@ async function generateFPEToken(rawText, entityType = "UNKNOWN") {
|
|
|
623
842
|
if (type === "PHONE_NUMBER" || type === "PHONE_NUM" || type === "PHONE_NUM_INTL") {
|
|
624
843
|
const m6 = text.match(/^\+([1-9]\d{0,3})/);
|
|
625
844
|
const cc = m6 ? m6[1] : "1";
|
|
626
|
-
|
|
845
|
+
const digits = text.replace(/\D/g, "");
|
|
846
|
+
if (digits.length >= 7) {
|
|
847
|
+
const last7 = digits.slice(-7);
|
|
848
|
+
const engine = new FF1(await _getAesKey(), Buffer.from("PHONE"), 10);
|
|
849
|
+
const enc = engine.encrypt(last7);
|
|
850
|
+
return `+${cc}-555-${enc}`;
|
|
851
|
+
}
|
|
627
852
|
}
|
|
628
853
|
if (type === "US_SSN") {
|
|
629
|
-
|
|
854
|
+
const digits = text.replace(/-/g, "");
|
|
855
|
+
if (digits.length === 9) {
|
|
856
|
+
const engine = new FF1(await _getAesKey(), Buffer.from("US_SSN"), 10);
|
|
857
|
+
const enc = engine.encrypt(digits);
|
|
858
|
+
return `${enc.slice(0, 3)}-${enc.slice(3, 5)}-${enc.slice(5, 9)}`;
|
|
859
|
+
}
|
|
630
860
|
}
|
|
631
861
|
if (type === "CREDIT_CARD" || type === "CREDIT_CARD_NUMBER") {
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
862
|
+
const digits = _stripCcSeparators(text);
|
|
863
|
+
if (digits.length === 16) {
|
|
864
|
+
const bin6 = digits.slice(0, 6);
|
|
865
|
+
const last4 = digits.slice(12, 16);
|
|
866
|
+
const middle6 = digits.slice(6, 12);
|
|
867
|
+
const engine = new FF1(await _getAesKey(), Buffer.from("CREDIT_CARD"), 10);
|
|
868
|
+
const encMiddle = engine.encrypt(middle6);
|
|
869
|
+
const base15 = bin6 + encMiddle + last4.slice(0, 3);
|
|
870
|
+
const checkDig = _computeLuhnDigit(base15);
|
|
871
|
+
const full = bin6 + encMiddle + last4.slice(0, 3) + checkDig;
|
|
872
|
+
return `${full.slice(0, 4)}-${full.slice(4, 8)}-${full.slice(8, 12)}-${full.slice(12, 16)}`;
|
|
873
|
+
} else {
|
|
874
|
+
const fallbackDigits = digits.padEnd(16, "0").slice(0, 16);
|
|
875
|
+
const engine = new FF1(await _getAesKey(), Buffer.from("CREDIT_CARD"), 10);
|
|
876
|
+
const encMiddle = engine.encrypt(fallbackDigits.slice(6, 12));
|
|
877
|
+
const full = fallbackDigits.slice(0, 6) + encMiddle + fallbackDigits.slice(12);
|
|
878
|
+
return `${full.slice(0, 4)}-${full.slice(4, 8)}-${full.slice(8, 12)}-${full.slice(12, 16)}`;
|
|
879
|
+
}
|
|
636
880
|
}
|
|
637
881
|
if (type === "US_ROUTING_NUMBER" || type === "US_ABA_ROUTING") {
|
|
638
|
-
|
|
882
|
+
if (text.length === 9 && /^\d+$/.test(text)) {
|
|
883
|
+
const engine = new FF1(await _getAesKey(), Buffer.from("US_ROUTING"), 10);
|
|
884
|
+
return engine.encrypt(text);
|
|
885
|
+
}
|
|
639
886
|
}
|
|
640
887
|
if (type === "INTL_BANK_IBAN" || type === "IBAN_CODE") {
|
|
641
888
|
const countryCode = text.length >= 2 && /[a-zA-Z]{2}/.test(text.slice(0, 2)) ? text.slice(0, 2).toUpperCase() : "US";
|
|
642
889
|
return `${countryCode}00${(await _hmacHex(text, 8)).toUpperCase()}`;
|
|
643
890
|
}
|
|
644
891
|
if (type === "ES_ID" || type === "ES_DNI") {
|
|
645
|
-
|
|
646
|
-
|
|
892
|
+
let digits = text.toUpperCase().replace(/[A-Z]/g, "");
|
|
893
|
+
if (digits) {
|
|
894
|
+
digits = digits.padStart(8, "0");
|
|
895
|
+
const engine = new FF1(await _getAesKey(), Buffer.from("ES_ID"), 10);
|
|
896
|
+
const enc = engine.encrypt(digits.slice(-5));
|
|
897
|
+
const tokenDigits = `000${enc}`;
|
|
898
|
+
return tokenDigits + _computeEsIdCheck(parseInt(tokenDigits, 10));
|
|
899
|
+
}
|
|
647
900
|
}
|
|
648
901
|
if (type === "PERSON" || type === "PERSON_NAME") {
|
|
649
902
|
if (config.MASK_BIJECTIVE_MODE) {
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
const inputInt = hash.readBigUInt64BE(0);
|
|
653
|
-
const masterKey = await _getMasterKey();
|
|
654
|
-
const engine = new FF1(masterKey.slice(0, 16), await _getBijectiveTweak());
|
|
655
|
-
const cipher = engine.encrypt(inputInt);
|
|
656
|
-
return _renderBijectivePerson(cipher);
|
|
903
|
+
const cipherBits = await _encryptBijectiveFF1(text);
|
|
904
|
+
return _renderBijectivePerson(cipherBits);
|
|
657
905
|
}
|
|
658
906
|
return `[TKN-PERSON-${await _hmacHex(text)}]`;
|
|
659
907
|
}
|
|
660
908
|
if (type === "LOCATION" || type === "PHYS_ADDRESS") {
|
|
661
909
|
if (config.MASK_BIJECTIVE_MODE) {
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
const inputInt = hash.readBigUInt64BE(0);
|
|
665
|
-
const masterKey = await _getMasterKey();
|
|
666
|
-
const engine = new FF1(masterKey.slice(0, 16), await _getBijectiveTweak());
|
|
667
|
-
const cipher = engine.encrypt(inputInt);
|
|
668
|
-
return _renderBijectiveLocation(cipher);
|
|
910
|
+
const cipherBits = await _encryptBijectiveFF1(text);
|
|
911
|
+
return _renderBijectiveLocation(cipherBits);
|
|
669
912
|
}
|
|
670
913
|
return `[TKN-LOC-${await _hmacHex(text)}]`;
|
|
671
914
|
}
|
|
@@ -674,12 +917,13 @@ async function generateFPEToken(rawText, entityType = "UNKNOWN") {
|
|
|
674
917
|
}
|
|
675
918
|
return `[TKN-${await _hmacHex(text)}]`;
|
|
676
919
|
}
|
|
677
|
-
var _masterKey, _EMAIL_RE, _PHONE_RE, _SSN_RE, _CC_RE, _ROUTING_RE, _ES_ID_RE, _IBAN_RE,
|
|
920
|
+
var _masterKey, _EMAIL_RE, _PHONE_RE, _SSN_RE, _CC_RE, _ROUTING_RE, _ES_ID_RE, _IBAN_RE, generateFPEToken;
|
|
678
921
|
var init_fpe = __esm({
|
|
679
922
|
"src/core/fpe.ts"() {
|
|
680
923
|
init_config();
|
|
681
924
|
init_key_provider();
|
|
682
925
|
init_exceptions();
|
|
926
|
+
init_ff1();
|
|
683
927
|
init_synthesisLibrary();
|
|
684
928
|
init_fpe_utils();
|
|
685
929
|
_masterKey = null;
|
|
@@ -690,49 +934,7 @@ var init_fpe = __esm({
|
|
|
690
934
|
_ROUTING_RE = /^\d{9}$/;
|
|
691
935
|
_ES_ID_RE = /^(?:\d{8}[A-Z]|[XYZ]\d{7}[A-Z])$/;
|
|
692
936
|
_IBAN_RE = /^[A-Z]{2}\d{2}[A-Z0-9]{4,30}$/;
|
|
693
|
-
|
|
694
|
-
/** NIST SP 800-38G FF1 implementation (simplified for 64-bit domains). */
|
|
695
|
-
constructor(key, tweak) {
|
|
696
|
-
this.key = key;
|
|
697
|
-
this.tweak = tweak;
|
|
698
|
-
}
|
|
699
|
-
encrypt(n6) {
|
|
700
|
-
let A3 = n6 >> 32n;
|
|
701
|
-
let B3 = n6 & 0xFFFFFFFFn;
|
|
702
|
-
const radix = 2n ** 32n;
|
|
703
|
-
for (let i6 = 0; i6 < 10; i6++) {
|
|
704
|
-
const tweakInfoBuffer = Buffer.alloc(8);
|
|
705
|
-
tweakInfoBuffer.writeUInt32BE(i6, 0);
|
|
706
|
-
tweakInfoBuffer.writeUInt32BE(Number(B3), 4);
|
|
707
|
-
const tweakInfoCombined = Buffer.concat([this.tweak, tweakInfoBuffer]);
|
|
708
|
-
const h6 = crypto2.createHmac("sha256", this.key).update(tweakInfoCombined).digest();
|
|
709
|
-
const roundVal = BigInt(h6.readUInt32BE(0));
|
|
710
|
-
const Anext = B3;
|
|
711
|
-
const Bnext = (A3 + roundVal) % radix;
|
|
712
|
-
A3 = Anext;
|
|
713
|
-
B3 = Bnext;
|
|
714
|
-
}
|
|
715
|
-
return A3 << 32n | B3;
|
|
716
|
-
}
|
|
717
|
-
decrypt(n6) {
|
|
718
|
-
let A3 = n6 >> 32n;
|
|
719
|
-
let B3 = n6 & 0xFFFFFFFFn;
|
|
720
|
-
const radix = 2n ** 32n;
|
|
721
|
-
for (let i6 = 9; i6 >= 0; i6--) {
|
|
722
|
-
const tweakInfoBuffer = Buffer.alloc(8);
|
|
723
|
-
tweakInfoBuffer.writeUInt32BE(i6, 0);
|
|
724
|
-
tweakInfoBuffer.writeUInt32BE(Number(A3), 4);
|
|
725
|
-
const tweakInfoCombined = Buffer.concat([this.tweak, tweakInfoBuffer]);
|
|
726
|
-
const h6 = crypto2.createHmac("sha256", this.key).update(tweakInfoCombined).digest();
|
|
727
|
-
const roundVal = BigInt(h6.readUInt32BE(0));
|
|
728
|
-
const Bprev = A3;
|
|
729
|
-
const Aprev = (B3 - roundVal + radix) % radix;
|
|
730
|
-
A3 = Aprev;
|
|
731
|
-
B3 = Bprev;
|
|
732
|
-
}
|
|
733
|
-
return A3 << 32n | B3;
|
|
734
|
-
}
|
|
735
|
-
};
|
|
937
|
+
generateFPEToken = generateDPToken;
|
|
736
938
|
}
|
|
737
939
|
});
|
|
738
940
|
|
|
@@ -749,39 +951,39 @@ var require_core = __commonJS({
|
|
|
749
951
|
}
|
|
750
952
|
})(exports2, function() {
|
|
751
953
|
var CryptoJS = CryptoJS || (function(Math2, undefined2) {
|
|
752
|
-
var
|
|
954
|
+
var crypto7;
|
|
753
955
|
if (typeof window !== "undefined" && window.crypto) {
|
|
754
|
-
|
|
956
|
+
crypto7 = window.crypto;
|
|
755
957
|
}
|
|
756
958
|
if (typeof self !== "undefined" && self.crypto) {
|
|
757
|
-
|
|
959
|
+
crypto7 = self.crypto;
|
|
758
960
|
}
|
|
759
961
|
if (typeof globalThis !== "undefined" && globalThis.crypto) {
|
|
760
|
-
|
|
962
|
+
crypto7 = globalThis.crypto;
|
|
761
963
|
}
|
|
762
|
-
if (!
|
|
763
|
-
|
|
964
|
+
if (!crypto7 && typeof window !== "undefined" && window.msCrypto) {
|
|
965
|
+
crypto7 = window.msCrypto;
|
|
764
966
|
}
|
|
765
|
-
if (!
|
|
766
|
-
|
|
967
|
+
if (!crypto7 && typeof global !== "undefined" && global.crypto) {
|
|
968
|
+
crypto7 = global.crypto;
|
|
767
969
|
}
|
|
768
|
-
if (!
|
|
970
|
+
if (!crypto7 && typeof __require === "function") {
|
|
769
971
|
try {
|
|
770
|
-
|
|
972
|
+
crypto7 = __require("crypto");
|
|
771
973
|
} catch (err2) {
|
|
772
974
|
}
|
|
773
975
|
}
|
|
774
976
|
var cryptoSecureRandomInt = function() {
|
|
775
|
-
if (
|
|
776
|
-
if (typeof
|
|
977
|
+
if (crypto7) {
|
|
978
|
+
if (typeof crypto7.getRandomValues === "function") {
|
|
777
979
|
try {
|
|
778
|
-
return
|
|
980
|
+
return crypto7.getRandomValues(new Uint32Array(1))[0];
|
|
779
981
|
} catch (err2) {
|
|
780
982
|
}
|
|
781
983
|
}
|
|
782
|
-
if (typeof
|
|
984
|
+
if (typeof crypto7.randomBytes === "function") {
|
|
783
985
|
try {
|
|
784
|
-
return
|
|
986
|
+
return crypto7.randomBytes(4).readInt32LE();
|
|
785
987
|
} catch (err2) {
|
|
786
988
|
}
|
|
787
989
|
}
|
|
@@ -3047,7 +3249,7 @@ var require_fernet = __commonJS({
|
|
|
3047
3249
|
var Base64 = require_enc_base64();
|
|
3048
3250
|
var HmacSHA256 = require_hmac_sha256();
|
|
3049
3251
|
var URLBase64 = require_urlsafe_base642();
|
|
3050
|
-
var
|
|
3252
|
+
var crypto7 = __require("crypto");
|
|
3051
3253
|
String.prototype.lpad = function(padString, length) {
|
|
3052
3254
|
var str = this;
|
|
3053
3255
|
while (str.length < length) str = padString + str;
|
|
@@ -3074,7 +3276,7 @@ var require_fernet = __commonJS({
|
|
|
3074
3276
|
return hex;
|
|
3075
3277
|
};
|
|
3076
3278
|
var randomHex = function(size) {
|
|
3077
|
-
return
|
|
3279
|
+
return crypto7.randomBytes(128 / 8).toString("hex");
|
|
3078
3280
|
};
|
|
3079
3281
|
var setIV = function setIV2(iv_array) {
|
|
3080
3282
|
if (iv_array) {
|
|
@@ -3157,24 +3359,28 @@ function getCryptoEngine() {
|
|
|
3157
3359
|
async function getCryptoEngineAsync() {
|
|
3158
3360
|
return await CryptoEngine.getInstanceAsync();
|
|
3159
3361
|
}
|
|
3160
|
-
var GCM_IV_BYTES, GCM_AUTH_TAG_BYTES, GCM_ALGORITHM, AES_GCM_PREFIX, _CryptoEngine, CryptoEngine;
|
|
3362
|
+
var AES_KEY_BYTES, GCM_IV_BYTES, GCM_AUTH_TAG_BYTES, GCM_ALGORITHM, AES_V2_PREFIX, AES_GCM_PREFIX, AES_GCM_LEGACY_PREFIX, _CryptoEngine, CryptoEngine;
|
|
3161
3363
|
var init_crypto = __esm({
|
|
3162
3364
|
"src/core/crypto.ts"() {
|
|
3163
3365
|
init_config();
|
|
3164
3366
|
init_key_provider();
|
|
3165
3367
|
init_exceptions();
|
|
3368
|
+
AES_KEY_BYTES = 32;
|
|
3166
3369
|
GCM_IV_BYTES = 12;
|
|
3167
3370
|
GCM_AUTH_TAG_BYTES = 16;
|
|
3168
3371
|
GCM_ALGORITHM = "aes-256-gcm";
|
|
3169
|
-
|
|
3372
|
+
AES_V2_PREFIX = "aes:v2:";
|
|
3373
|
+
AES_GCM_PREFIX = "aes:v1:";
|
|
3374
|
+
AES_GCM_LEGACY_PREFIX = "aes:";
|
|
3170
3375
|
_CryptoEngine = class _CryptoEngine {
|
|
3171
3376
|
constructor() {
|
|
3172
|
-
this.
|
|
3377
|
+
this._keyring = /* @__PURE__ */ new Map();
|
|
3378
|
+
this._activeKeyId = "default";
|
|
3173
3379
|
this._indexSecret = null;
|
|
3174
3380
|
}
|
|
3175
|
-
/**
|
|
3381
|
+
/**
|
|
3176
3382
|
* Return the singleton instance, initialising it if necessary.
|
|
3177
|
-
*
|
|
3383
|
+
* Async because Argon2id key derivation is async.
|
|
3178
3384
|
*/
|
|
3179
3385
|
static async getInstanceAsync() {
|
|
3180
3386
|
if (this._instance === null) {
|
|
@@ -3190,33 +3396,96 @@ var init_crypto = __esm({
|
|
|
3190
3396
|
}
|
|
3191
3397
|
return this._instance;
|
|
3192
3398
|
}
|
|
3193
|
-
/** Clear the singleton
|
|
3399
|
+
/** Clear the singleton (useful for key rotation / tests). */
|
|
3194
3400
|
static reset() {
|
|
3195
3401
|
this._instance = null;
|
|
3196
3402
|
}
|
|
3403
|
+
async _deriveAesKey(rawKey, keyId) {
|
|
3404
|
+
let argon2;
|
|
3405
|
+
try {
|
|
3406
|
+
argon2 = __require("argon2");
|
|
3407
|
+
} catch (e6) {
|
|
3408
|
+
throw new Error(
|
|
3409
|
+
"The 'argon2' package is required for Mask SDK cryptographic operations. Install with: npm install argon2"
|
|
3410
|
+
);
|
|
3411
|
+
}
|
|
3412
|
+
const kdfSaltStr = config.MASK_KDF_SALT + "-" + config.MASK_TENANT_ID + "-" + keyId;
|
|
3413
|
+
const kdfSaltBytes = cryptoNode.createHash("sha256").update(kdfSaltStr).digest().subarray(0, 16);
|
|
3414
|
+
return await argon2.hash(rawKey, {
|
|
3415
|
+
type: argon2.argon2id,
|
|
3416
|
+
memoryCost: 19456,
|
|
3417
|
+
timeCost: 2,
|
|
3418
|
+
parallelism: 1,
|
|
3419
|
+
hashLength: AES_KEY_BYTES,
|
|
3420
|
+
salt: kdfSaltBytes,
|
|
3421
|
+
raw: true
|
|
3422
|
+
});
|
|
3423
|
+
}
|
|
3197
3424
|
async _init() {
|
|
3425
|
+
let argon2;
|
|
3426
|
+
try {
|
|
3427
|
+
argon2 = __require("argon2");
|
|
3428
|
+
} catch (e6) {
|
|
3429
|
+
throw new Error("The 'argon2' package is required. Install with: npm install argon2");
|
|
3430
|
+
}
|
|
3198
3431
|
const provider = getKeyProvider();
|
|
3199
|
-
const
|
|
3200
|
-
let
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
);
|
|
3432
|
+
const rawKeys = /* @__PURE__ */ new Map();
|
|
3433
|
+
let activeKeyId = "default";
|
|
3434
|
+
const keyringJson = await provider.getKeyring();
|
|
3435
|
+
if (keyringJson) {
|
|
3436
|
+
let parsed;
|
|
3437
|
+
try {
|
|
3438
|
+
parsed = JSON.parse(keyringJson);
|
|
3439
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
3440
|
+
throw new Error("MASK_KEYRING must be a non-empty JSON object.");
|
|
3441
|
+
}
|
|
3442
|
+
} catch (e6) {
|
|
3443
|
+
throw new Error(`Invalid MASK_KEYRING format: ${e6}`);
|
|
3212
3444
|
}
|
|
3445
|
+
const entries = Object.entries(parsed);
|
|
3446
|
+
if (entries.length === 0) throw new Error("MASK_KEYRING must contain at least one key.");
|
|
3447
|
+
for (const [kid, k6] of entries) rawKeys.set(kid, k6);
|
|
3448
|
+
activeKeyId = entries[entries.length - 1][0];
|
|
3213
3449
|
} else {
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3450
|
+
const keyFromProvider = await provider.getEncryptionKey();
|
|
3451
|
+
let key;
|
|
3452
|
+
if (!keyFromProvider) {
|
|
3453
|
+
if (config.MASK_DEV_MODE) {
|
|
3454
|
+
key = cryptoNode.randomBytes(32).toString("base64");
|
|
3455
|
+
process.env.MASK_ENCRYPTION_KEY = key;
|
|
3456
|
+
console.warn(
|
|
3457
|
+
"MASK_DEV_MODE is enabled. Using a generated throwaway key. DO NOT USE THIS IN PRODUCTION \u2014 tokens will be lost on restart."
|
|
3458
|
+
);
|
|
3459
|
+
} else {
|
|
3460
|
+
throw new Error(
|
|
3461
|
+
"MASK_ENCRYPTION_KEY or MASK_KEYRING is not set. Set one of these, or set MASK_DEV_MODE=true for ephemeral use."
|
|
3462
|
+
);
|
|
3463
|
+
}
|
|
3464
|
+
} else {
|
|
3465
|
+
key = keyFromProvider;
|
|
3466
|
+
}
|
|
3467
|
+
rawKeys.set("default", key);
|
|
3468
|
+
activeKeyId = "default";
|
|
3469
|
+
}
|
|
3470
|
+
this._keyring = /* @__PURE__ */ new Map();
|
|
3471
|
+
for (const [kid, rawKey] of rawKeys) {
|
|
3472
|
+
this._keyring.set(kid, await this._deriveAesKey(rawKey, kid));
|
|
3473
|
+
}
|
|
3474
|
+
this._activeKeyId = activeKeyId;
|
|
3475
|
+
const rawKeysArr = Array.from(rawKeys.values());
|
|
3476
|
+
const lastRawKey = rawKeysArr[rawKeysArr.length - 1];
|
|
3477
|
+
const masterKey = await provider.getMasterKey() || lastRawKey;
|
|
3478
|
+
const indexSaltStr = config.MASK_BLIND_INDEX_SALT + "-" + config.MASK_TENANT_ID;
|
|
3479
|
+
const indexSaltBytes = cryptoNode.createHash("sha256").update(indexSaltStr).digest().subarray(0, 16);
|
|
3480
|
+
this._indexSecret = await argon2.hash(masterKey, {
|
|
3481
|
+
type: argon2.argon2id,
|
|
3482
|
+
memoryCost: 19456,
|
|
3483
|
+
timeCost: 2,
|
|
3484
|
+
parallelism: 1,
|
|
3485
|
+
hashLength: AES_KEY_BYTES,
|
|
3486
|
+
salt: indexSaltBytes,
|
|
3487
|
+
raw: true
|
|
3488
|
+
});
|
|
3220
3489
|
}
|
|
3221
3490
|
/** Return the secret used for HMAC-based blind indexing. */
|
|
3222
3491
|
async getIndexSecret() {
|
|
@@ -3225,36 +3494,56 @@ var init_crypto = __esm({
|
|
|
3225
3494
|
}
|
|
3226
3495
|
return this._indexSecret;
|
|
3227
3496
|
}
|
|
3497
|
+
/** Encrypt plaintext using the active keyring key.
|
|
3498
|
+
* Envelope format: aes:v2:{keyId}:{base64(iv+authTag+ciphertext)}
|
|
3499
|
+
*/
|
|
3228
3500
|
encrypt(plaintext) {
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
const
|
|
3234
|
-
const
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
]);
|
|
3501
|
+
const aesKey = this._keyring.get(this._activeKeyId);
|
|
3502
|
+
if (!aesKey) {
|
|
3503
|
+
throw new Error(`CryptoEngine: active key ID '${this._activeKeyId}' not found in keyring.`);
|
|
3504
|
+
}
|
|
3505
|
+
const iv = cryptoNode.randomBytes(GCM_IV_BYTES);
|
|
3506
|
+
const cipher = cryptoNode.createCipheriv(GCM_ALGORITHM, aesKey, iv);
|
|
3507
|
+
const plaintextBuf = Buffer.from(plaintext, "utf8");
|
|
3508
|
+
const encrypted = Buffer.concat([cipher.update(plaintextBuf), cipher.final()]);
|
|
3238
3509
|
const authTag = cipher.getAuthTag();
|
|
3510
|
+
plaintextBuf.fill(0);
|
|
3239
3511
|
const combined = Buffer.concat([iv, authTag, encrypted]);
|
|
3240
|
-
return
|
|
3512
|
+
return `${AES_V2_PREFIX}${this._activeKeyId}:${combined.toString("base64")}`;
|
|
3241
3513
|
}
|
|
3514
|
+
/** Decrypt ciphertext. Supports all historical envelope formats. */
|
|
3242
3515
|
decrypt(ciphertext) {
|
|
3243
|
-
if (
|
|
3244
|
-
throw new Error("CryptoEngine not initialised.
|
|
3516
|
+
if (this._keyring.size === 0) {
|
|
3517
|
+
throw new Error("CryptoEngine not initialised.");
|
|
3245
3518
|
}
|
|
3246
3519
|
try {
|
|
3520
|
+
if (ciphertext.startsWith(AES_V2_PREFIX)) {
|
|
3521
|
+
const rest = ciphertext.slice(AES_V2_PREFIX.length);
|
|
3522
|
+
const sep3 = rest.indexOf(":");
|
|
3523
|
+
if (sep3 === -1) throw new Error("Malformed aes:v2 envelope: missing key ID separator.");
|
|
3524
|
+
const keyId = rest.slice(0, sep3);
|
|
3525
|
+
const b64 = rest.slice(sep3 + 1);
|
|
3526
|
+
return this._decryptAesGcm(keyId, b64);
|
|
3527
|
+
}
|
|
3247
3528
|
if (ciphertext.startsWith(AES_GCM_PREFIX)) {
|
|
3248
|
-
return this._decryptAesGcm(ciphertext.slice(AES_GCM_PREFIX.length));
|
|
3529
|
+
return this._decryptAesGcm("default", ciphertext.slice(AES_GCM_PREFIX.length));
|
|
3530
|
+
}
|
|
3531
|
+
if (ciphertext.startsWith(AES_GCM_LEGACY_PREFIX)) {
|
|
3532
|
+
return this._decryptAesGcm("default", ciphertext.slice(AES_GCM_LEGACY_PREFIX.length));
|
|
3249
3533
|
}
|
|
3250
3534
|
return this._decryptLegacyFernet(ciphertext);
|
|
3251
3535
|
} catch (e6) {
|
|
3252
|
-
console.error("Failed to decrypt vault payload. Check your MASK_ENCRYPTION_KEY. Inner error:", e6);
|
|
3536
|
+
console.error("Failed to decrypt vault payload. Check your MASK_ENCRYPTION_KEY / MASK_KEYRING. Inner error:", e6);
|
|
3253
3537
|
throw new MaskDecryptionError("Decryption failed");
|
|
3254
3538
|
}
|
|
3255
3539
|
}
|
|
3256
|
-
|
|
3257
|
-
|
|
3540
|
+
_decryptAesGcm(keyId, b64) {
|
|
3541
|
+
const aesKey = this._keyring.get(keyId);
|
|
3542
|
+
if (!aesKey) {
|
|
3543
|
+
throw new MaskDecryptionError(
|
|
3544
|
+
`No key found for key ID '${keyId}'. Ensure the key is present in MASK_KEYRING.`
|
|
3545
|
+
);
|
|
3546
|
+
}
|
|
3258
3547
|
const combined = Buffer.from(b64, "base64");
|
|
3259
3548
|
if (combined.length < GCM_IV_BYTES + GCM_AUTH_TAG_BYTES) {
|
|
3260
3549
|
throw new Error("Ciphertext too short for AES-GCM");
|
|
@@ -3262,22 +3551,11 @@ var init_crypto = __esm({
|
|
|
3262
3551
|
const iv = combined.subarray(0, GCM_IV_BYTES);
|
|
3263
3552
|
const authTag = combined.subarray(GCM_IV_BYTES, GCM_IV_BYTES + GCM_AUTH_TAG_BYTES);
|
|
3264
3553
|
const encrypted = combined.subarray(GCM_IV_BYTES + GCM_AUTH_TAG_BYTES);
|
|
3265
|
-
const decipher =
|
|
3554
|
+
const decipher = cryptoNode.createDecipheriv(GCM_ALGORITHM, aesKey, iv);
|
|
3266
3555
|
decipher.setAuthTag(authTag);
|
|
3267
|
-
const decrypted = Buffer.concat([
|
|
3268
|
-
decipher.update(encrypted),
|
|
3269
|
-
decipher.final()
|
|
3270
|
-
]);
|
|
3556
|
+
const decrypted = Buffer.concat([decipher.update(encrypted), decipher.final()]);
|
|
3271
3557
|
return decrypted.toString("utf8");
|
|
3272
3558
|
}
|
|
3273
|
-
/**
|
|
3274
|
-
* Attempt to decrypt a legacy Fernet-format token.
|
|
3275
|
-
*
|
|
3276
|
-
* Fernet format: Version (1) || Timestamp (8) || IV (16) || Ciphertext (var) || HMAC (32)
|
|
3277
|
-
* All base64url-encoded.
|
|
3278
|
-
*
|
|
3279
|
-
* We try to use the `fernet` npm package if available, otherwise throw.
|
|
3280
|
-
*/
|
|
3281
3559
|
_decryptLegacyFernet(ciphertext) {
|
|
3282
3560
|
let fernet;
|
|
3283
3561
|
try {
|
|
@@ -3305,8 +3583,6 @@ var init_crypto = __esm({
|
|
|
3305
3583
|
CryptoEngine = _CryptoEngine;
|
|
3306
3584
|
}
|
|
3307
3585
|
});
|
|
3308
|
-
|
|
3309
|
-
// src/telemetry/audit_logger.ts
|
|
3310
3586
|
function _getLogLevel() {
|
|
3311
3587
|
const env3 = config.MASK_LOG_LEVEL;
|
|
3312
3588
|
return env3 in LOG_LEVELS ? env3 : "info";
|
|
@@ -3340,16 +3616,15 @@ function getLogger(name) {
|
|
|
3340
3616
|
error: (...args) => _log("error", ...args)
|
|
3341
3617
|
};
|
|
3342
3618
|
}
|
|
3343
|
-
function _makeEvent(action, token, dataType, agent = "", tool = "", extra = null) {
|
|
3619
|
+
function _makeEvent(action, token, dataType, agent = "", tool = "", extra = null, instanceId = "") {
|
|
3344
3620
|
const event = {
|
|
3345
3621
|
ts: Date.now() / 1e3,
|
|
3346
3622
|
action,
|
|
3347
|
-
// "encode" | "decode" | "expired" | "error"
|
|
3348
3623
|
token,
|
|
3349
3624
|
data_type: dataType,
|
|
3350
|
-
// "email" | "phone" | "ssn" | "opaque"
|
|
3351
3625
|
agent,
|
|
3352
|
-
tool
|
|
3626
|
+
tool,
|
|
3627
|
+
instance_id: instanceId
|
|
3353
3628
|
};
|
|
3354
3629
|
if (extra) {
|
|
3355
3630
|
Object.assign(event, _deepMask(extra));
|
|
@@ -3359,7 +3634,7 @@ function _makeEvent(action, token, dataType, agent = "", tool = "", extra = null
|
|
|
3359
3634
|
function _deepMask(obj) {
|
|
3360
3635
|
if (obj === null || obj === void 0) return obj;
|
|
3361
3636
|
if (typeof obj === "string") {
|
|
3362
|
-
return
|
|
3637
|
+
return isUnambiguouslySafeToken(obj) ? obj : "[REDACTED]";
|
|
3363
3638
|
}
|
|
3364
3639
|
if (typeof obj !== "object") return obj;
|
|
3365
3640
|
if (Array.isArray(obj)) {
|
|
@@ -3393,6 +3668,10 @@ var init_audit_logger = __esm({
|
|
|
3393
3668
|
this._shutdownRegistered = false;
|
|
3394
3669
|
this._maxBufferSize = config.MASK_AUDIT_MAX_BUFFER_SIZE;
|
|
3395
3670
|
this._strictMode = config.MASK_AUDIT_LOG_STRICT;
|
|
3671
|
+
const rawKey = process.env.MASK_MASTER_KEY || process.env.MASK_ENCRYPTION_KEY || "";
|
|
3672
|
+
this._signingKey = cryptoNode.createHash("sha256").update(rawKey).digest();
|
|
3673
|
+
this._instanceId = cryptoNode.randomUUID();
|
|
3674
|
+
this._prevSig = cryptoNode.createHmac("sha256", this._signingKey).update(this._instanceId, "utf-8").digest("hex");
|
|
3396
3675
|
}
|
|
3397
3676
|
static getInstance() {
|
|
3398
3677
|
if (this._instance === null) {
|
|
@@ -3400,16 +3679,46 @@ var init_audit_logger = __esm({
|
|
|
3400
3679
|
}
|
|
3401
3680
|
return this._instance;
|
|
3402
3681
|
}
|
|
3682
|
+
_getOverflowPath() {
|
|
3683
|
+
const d6 = process.env.MASK_SECURE_AUDIT_LOG_DIR || __require("os").tmpdir();
|
|
3684
|
+
return path2.join(d6, `mask_audit_overflow_${this._instanceId}.ndjson`);
|
|
3685
|
+
}
|
|
3686
|
+
_writeOverflow(event) {
|
|
3687
|
+
try {
|
|
3688
|
+
fs.appendFileSync(this._getOverflowPath(), JSON.stringify(event) + "\n", "utf-8");
|
|
3689
|
+
} catch {
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3692
|
+
_consumeOverflow(events) {
|
|
3693
|
+
const overflowPath = this._getOverflowPath();
|
|
3694
|
+
if (!fs.existsSync(overflowPath)) return;
|
|
3695
|
+
const processingPath = overflowPath + ".processing";
|
|
3696
|
+
try {
|
|
3697
|
+
fs.renameSync(overflowPath, processingPath);
|
|
3698
|
+
} catch {
|
|
3699
|
+
return;
|
|
3700
|
+
}
|
|
3701
|
+
try {
|
|
3702
|
+
const content = fs.readFileSync(processingPath, "utf-8");
|
|
3703
|
+
for (const line of content.split("\n")) {
|
|
3704
|
+
if (line.trim()) events.push(JSON.parse(line));
|
|
3705
|
+
}
|
|
3706
|
+
fs.unlinkSync(processingPath);
|
|
3707
|
+
} catch (e6) {
|
|
3708
|
+
_logger.error(`Failed to consume overflow: ${e6}`);
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3403
3711
|
log(action, token, dataType = "opaque", agent = "", tool = "", extra = {}) {
|
|
3404
|
-
const event = _makeEvent(action, token, dataType, agent, tool, extra);
|
|
3712
|
+
const event = _makeEvent(action, token, dataType, agent, tool, extra, this._instanceId);
|
|
3405
3713
|
if (this._buffer.length >= this._maxBufferSize) {
|
|
3406
3714
|
if (!this._bufferFullWarned) {
|
|
3407
3715
|
_logger.warn(
|
|
3408
|
-
`AuditLogger buffer full (max=${this._maxBufferSize}).
|
|
3716
|
+
`AuditLogger buffer full (max=${this._maxBufferSize}). Spooling to disk overflow to prevent OOM.`
|
|
3409
3717
|
);
|
|
3410
3718
|
this._bufferFullWarned = true;
|
|
3411
3719
|
}
|
|
3412
|
-
this.
|
|
3720
|
+
this._writeOverflow(event);
|
|
3721
|
+
return;
|
|
3413
3722
|
}
|
|
3414
3723
|
this._buffer.push(event);
|
|
3415
3724
|
}
|
|
@@ -3439,27 +3748,84 @@ var init_audit_logger = __esm({
|
|
|
3439
3748
|
await this._flush();
|
|
3440
3749
|
}
|
|
3441
3750
|
async _flush() {
|
|
3442
|
-
if (this._isFlushing
|
|
3751
|
+
if (this._isFlushing) return;
|
|
3443
3752
|
this._isFlushing = true;
|
|
3444
3753
|
try {
|
|
3445
3754
|
const events = [...this._buffer];
|
|
3446
3755
|
this._buffer = [];
|
|
3447
3756
|
this._bufferFullWarned = false;
|
|
3757
|
+
this._consumeOverflow(events);
|
|
3758
|
+
if (events.length === 0) return;
|
|
3759
|
+
const secureLogDir = process.env.MASK_SECURE_AUDIT_LOG_DIR || "";
|
|
3760
|
+
let secureStream = null;
|
|
3761
|
+
if (secureLogDir) {
|
|
3762
|
+
fs.mkdirSync(secureLogDir, { recursive: true });
|
|
3763
|
+
const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3764
|
+
const filePath = path2.join(secureLogDir, `mask-audit-${dateStr}.ndjson`);
|
|
3765
|
+
try {
|
|
3766
|
+
secureStream = fs.createWriteStream(filePath, { flags: "a" });
|
|
3767
|
+
} catch {
|
|
3768
|
+
}
|
|
3769
|
+
}
|
|
3448
3770
|
for (const evt of events) {
|
|
3449
|
-
const
|
|
3450
|
-
|
|
3771
|
+
const body = JSON.stringify(evt, (_, v7) => typeof v7 === "bigint" ? v7.toString() : v7);
|
|
3772
|
+
const sigInput = Buffer.from(this._prevSig + body, "utf-8");
|
|
3773
|
+
const sig = cryptoNode.createHmac("sha256", this._signingKey).update(sigInput).digest("hex");
|
|
3774
|
+
const signedLine = JSON.stringify({
|
|
3775
|
+
...evt,
|
|
3776
|
+
prev_sig: this._prevSig,
|
|
3777
|
+
sig
|
|
3778
|
+
}, (_, v7) => typeof v7 === "bigint" ? v7.toString() : v7);
|
|
3779
|
+
this._prevSig = sig;
|
|
3780
|
+
console.info(signedLine);
|
|
3781
|
+
if (secureStream) {
|
|
3782
|
+
secureStream.write(signedLine + "\n");
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
if (secureStream) {
|
|
3786
|
+
secureStream.end();
|
|
3451
3787
|
}
|
|
3452
3788
|
} finally {
|
|
3453
3789
|
this._isFlushing = false;
|
|
3454
3790
|
}
|
|
3455
3791
|
}
|
|
3456
|
-
/** Synchronous flush for use in signal handlers where async is unreliable.
|
|
3792
|
+
/** Synchronous flush for use in signal handlers where async is unreliable.
|
|
3793
|
+
*
|
|
3794
|
+
* Computes HMAC signatures to maintain chain integrity and writes to the
|
|
3795
|
+
* secure ndjson audit file (MASK_SECURE_AUDIT_LOG_DIR) if configured,
|
|
3796
|
+
* ensuring SOC 2 tamper-evidence guarantees hold through process shutdown.
|
|
3797
|
+
*/
|
|
3457
3798
|
_flushSync() {
|
|
3458
3799
|
if (this._buffer.length === 0) return;
|
|
3459
3800
|
const events = [...this._buffer];
|
|
3460
3801
|
this._buffer = [];
|
|
3802
|
+
const secureLogDir = process.env.MASK_SECURE_AUDIT_LOG_DIR || "";
|
|
3803
|
+
let secureFilePath = null;
|
|
3804
|
+
if (secureLogDir) {
|
|
3805
|
+
try {
|
|
3806
|
+
fs.mkdirSync(secureLogDir, { recursive: true });
|
|
3807
|
+
const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
3808
|
+
secureFilePath = path2.join(secureLogDir, `mask-audit-${dateStr}.ndjson`);
|
|
3809
|
+
} catch {
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3461
3812
|
for (const evt of events) {
|
|
3462
|
-
|
|
3813
|
+
const body = JSON.stringify(evt, (_, v7) => typeof v7 === "bigint" ? v7.toString() : v7);
|
|
3814
|
+
const sigInput = Buffer.from(this._prevSig + body, "utf-8");
|
|
3815
|
+
const sig = cryptoNode.createHmac("sha256", this._signingKey).update(sigInput).digest("hex");
|
|
3816
|
+
const signedLine = JSON.stringify({
|
|
3817
|
+
...evt,
|
|
3818
|
+
prev_sig: this._prevSig,
|
|
3819
|
+
sig
|
|
3820
|
+
}, (_, v7) => typeof v7 === "bigint" ? v7.toString() : v7);
|
|
3821
|
+
this._prevSig = sig;
|
|
3822
|
+
process.stdout.write(signedLine + "\n");
|
|
3823
|
+
if (secureFilePath) {
|
|
3824
|
+
try {
|
|
3825
|
+
fs.appendFileSync(secureFilePath, signedLine + "\n", { encoding: "utf-8" });
|
|
3826
|
+
} catch {
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3463
3829
|
}
|
|
3464
3830
|
}
|
|
3465
3831
|
};
|
|
@@ -3511,7 +3877,7 @@ var init_search = __esm({
|
|
|
3511
3877
|
static async getBucketIndex(bucketVal) {
|
|
3512
3878
|
const engine = await getCryptoEngine();
|
|
3513
3879
|
const secret = await engine.getIndexSecret();
|
|
3514
|
-
return
|
|
3880
|
+
return cryptoNode.createHmac("sha256", secret).update(bucketVal).digest("hex");
|
|
3515
3881
|
}
|
|
3516
3882
|
};
|
|
3517
3883
|
}
|
|
@@ -15657,9 +16023,9 @@ var init_createPaginator = __esm({
|
|
|
15657
16023
|
command = withCommand(command) ?? command;
|
|
15658
16024
|
return await client.send(command, ...args);
|
|
15659
16025
|
};
|
|
15660
|
-
get = (fromObject,
|
|
16026
|
+
get = (fromObject, path4) => {
|
|
15661
16027
|
let cursor = fromObject;
|
|
15662
|
-
const pathComponents =
|
|
16028
|
+
const pathComponents = path4.split(".");
|
|
15663
16029
|
for (const step of pathComponents) {
|
|
15664
16030
|
if (!cursor || typeof cursor !== "object") {
|
|
15665
16031
|
return void 0;
|
|
@@ -16270,12 +16636,12 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
16270
16636
|
const password = request2.password ?? "";
|
|
16271
16637
|
auth = `${username}:${password}`;
|
|
16272
16638
|
}
|
|
16273
|
-
let
|
|
16639
|
+
let path4 = request2.path;
|
|
16274
16640
|
if (queryString) {
|
|
16275
|
-
|
|
16641
|
+
path4 += `?${queryString}`;
|
|
16276
16642
|
}
|
|
16277
16643
|
if (request2.fragment) {
|
|
16278
|
-
|
|
16644
|
+
path4 += `#${request2.fragment}`;
|
|
16279
16645
|
}
|
|
16280
16646
|
let hostname = request2.hostname ?? "";
|
|
16281
16647
|
if (hostname[0] === "[" && hostname.endsWith("]")) {
|
|
@@ -16287,7 +16653,7 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf
|
|
|
16287
16653
|
headers: request2.headers,
|
|
16288
16654
|
host: hostname,
|
|
16289
16655
|
method: request2.method,
|
|
16290
|
-
path:
|
|
16656
|
+
path: path4,
|
|
16291
16657
|
port: request2.port,
|
|
16292
16658
|
agent,
|
|
16293
16659
|
auth
|
|
@@ -16594,16 +16960,16 @@ var init_node_http2_handler = __esm({
|
|
|
16594
16960
|
reject(err2);
|
|
16595
16961
|
};
|
|
16596
16962
|
const queryString = buildQueryString(query || {});
|
|
16597
|
-
let
|
|
16963
|
+
let path4 = request2.path;
|
|
16598
16964
|
if (queryString) {
|
|
16599
|
-
|
|
16965
|
+
path4 += `?${queryString}`;
|
|
16600
16966
|
}
|
|
16601
16967
|
if (request2.fragment) {
|
|
16602
|
-
|
|
16968
|
+
path4 += `#${request2.fragment}`;
|
|
16603
16969
|
}
|
|
16604
16970
|
const req = session.request({
|
|
16605
16971
|
...request2.headers,
|
|
16606
|
-
[constants.HTTP2_HEADER_PATH]:
|
|
16972
|
+
[constants.HTTP2_HEADER_PATH]: path4,
|
|
16607
16973
|
[constants.HTTP2_HEADER_METHOD]: method
|
|
16608
16974
|
});
|
|
16609
16975
|
session.ref();
|
|
@@ -18052,10 +18418,10 @@ var init_date_utils = __esm({
|
|
|
18052
18418
|
};
|
|
18053
18419
|
}
|
|
18054
18420
|
});
|
|
18055
|
-
var
|
|
18421
|
+
var randomUUID2;
|
|
18056
18422
|
var init_randomUUID = __esm({
|
|
18057
18423
|
"node_modules/@smithy/uuid/dist-es/randomUUID.js"() {
|
|
18058
|
-
|
|
18424
|
+
randomUUID2 = cryptoNode__default.randomUUID.bind(cryptoNode__default);
|
|
18059
18425
|
}
|
|
18060
18426
|
});
|
|
18061
18427
|
|
|
@@ -18066,8 +18432,8 @@ var init_v4 = __esm({
|
|
|
18066
18432
|
init_randomUUID();
|
|
18067
18433
|
decimalToHex = Array.from({ length: 256 }, (_, i6) => i6.toString(16).padStart(2, "0"));
|
|
18068
18434
|
v4 = () => {
|
|
18069
|
-
if (
|
|
18070
|
-
return
|
|
18435
|
+
if (randomUUID2) {
|
|
18436
|
+
return randomUUID2();
|
|
18071
18437
|
}
|
|
18072
18438
|
const rnds = new Uint8Array(16);
|
|
18073
18439
|
crypto.getRandomValues(rnds);
|
|
@@ -18805,11 +19171,11 @@ var init_HttpBindingProtocol = __esm({
|
|
|
18805
19171
|
const opTraits = translateTraits(operationSchema.traits);
|
|
18806
19172
|
if (opTraits.http) {
|
|
18807
19173
|
request2.method = opTraits.http[0];
|
|
18808
|
-
const [
|
|
19174
|
+
const [path4, search] = opTraits.http[1].split("?");
|
|
18809
19175
|
if (request2.path == "/") {
|
|
18810
|
-
request2.path =
|
|
19176
|
+
request2.path = path4;
|
|
18811
19177
|
} else {
|
|
18812
|
-
request2.path +=
|
|
19178
|
+
request2.path += path4;
|
|
18813
19179
|
}
|
|
18814
19180
|
const traitSearchParams = new URLSearchParams(search ?? "");
|
|
18815
19181
|
Object.assign(query, Object.fromEntries(traitSearchParams));
|
|
@@ -19842,18 +20208,18 @@ var getAttrPathList;
|
|
|
19842
20208
|
var init_getAttrPathList = __esm({
|
|
19843
20209
|
"node_modules/@smithy/util-endpoints/dist-es/lib/getAttrPathList.js"() {
|
|
19844
20210
|
init_types2();
|
|
19845
|
-
getAttrPathList = (
|
|
19846
|
-
const parts =
|
|
20211
|
+
getAttrPathList = (path4) => {
|
|
20212
|
+
const parts = path4.split(".");
|
|
19847
20213
|
const pathList = [];
|
|
19848
20214
|
for (const part of parts) {
|
|
19849
20215
|
const squareBracketIndex = part.indexOf("[");
|
|
19850
20216
|
if (squareBracketIndex !== -1) {
|
|
19851
20217
|
if (part.indexOf("]") !== part.length - 1) {
|
|
19852
|
-
throw new EndpointError(`Path: '${
|
|
20218
|
+
throw new EndpointError(`Path: '${path4}' does not end with ']'`);
|
|
19853
20219
|
}
|
|
19854
20220
|
const arrayIndex = part.slice(squareBracketIndex + 1, -1);
|
|
19855
20221
|
if (Number.isNaN(parseInt(arrayIndex))) {
|
|
19856
|
-
throw new EndpointError(`Invalid array index: '${arrayIndex}' in path: '${
|
|
20222
|
+
throw new EndpointError(`Invalid array index: '${arrayIndex}' in path: '${path4}'`);
|
|
19857
20223
|
}
|
|
19858
20224
|
if (squareBracketIndex !== 0) {
|
|
19859
20225
|
pathList.push(part.slice(0, squareBracketIndex));
|
|
@@ -19874,9 +20240,9 @@ var init_getAttr = __esm({
|
|
|
19874
20240
|
"node_modules/@smithy/util-endpoints/dist-es/lib/getAttr.js"() {
|
|
19875
20241
|
init_types2();
|
|
19876
20242
|
init_getAttrPathList();
|
|
19877
|
-
getAttr = (value,
|
|
20243
|
+
getAttr = (value, path4) => getAttrPathList(path4).reduce((acc, index) => {
|
|
19878
20244
|
if (typeof acc !== "object") {
|
|
19879
|
-
throw new EndpointError(`Index '${index}' in '${
|
|
20245
|
+
throw new EndpointError(`Index '${index}' in '${path4}' not found in '${JSON.stringify(value)}'`);
|
|
19880
20246
|
} else if (Array.isArray(acc)) {
|
|
19881
20247
|
return acc[parseInt(index)];
|
|
19882
20248
|
}
|
|
@@ -19918,8 +20284,8 @@ var init_parseURL = __esm({
|
|
|
19918
20284
|
return value;
|
|
19919
20285
|
}
|
|
19920
20286
|
if (typeof value === "object" && "hostname" in value) {
|
|
19921
|
-
const { hostname: hostname2, port, protocol: protocol2 = "", path:
|
|
19922
|
-
const url = new URL(`${protocol2}//${hostname2}${port ? `:${port}` : ""}${
|
|
20287
|
+
const { hostname: hostname2, port, protocol: protocol2 = "", path: path4 = "", query = {} } = value;
|
|
20288
|
+
const url = new URL(`${protocol2}//${hostname2}${port ? `:${port}` : ""}${path4}`);
|
|
19923
20289
|
url.search = Object.entries(query).map(([k6, v7]) => `${k6}=${v7}`).join("&");
|
|
19924
20290
|
return url;
|
|
19925
20291
|
}
|
|
@@ -21674,10 +22040,10 @@ ${longDate}
|
|
|
21674
22040
|
${credentialScope}
|
|
21675
22041
|
${toHex(hashedRequest)}`;
|
|
21676
22042
|
}
|
|
21677
|
-
getCanonicalPath({ path:
|
|
22043
|
+
getCanonicalPath({ path: path4 }) {
|
|
21678
22044
|
if (this.uriEscapePath) {
|
|
21679
22045
|
const normalizedPathSegments = [];
|
|
21680
|
-
for (const pathSegment of
|
|
22046
|
+
for (const pathSegment of path4.split("/")) {
|
|
21681
22047
|
if (pathSegment?.length === 0)
|
|
21682
22048
|
continue;
|
|
21683
22049
|
if (pathSegment === ".")
|
|
@@ -21688,11 +22054,11 @@ ${toHex(hashedRequest)}`;
|
|
|
21688
22054
|
normalizedPathSegments.push(pathSegment);
|
|
21689
22055
|
}
|
|
21690
22056
|
}
|
|
21691
|
-
const normalizedPath = `${
|
|
22057
|
+
const normalizedPath = `${path4?.startsWith("/") ? "/" : ""}${normalizedPathSegments.join("/")}${normalizedPathSegments.length > 0 && path4?.endsWith("/") ? "/" : ""}`;
|
|
21692
22058
|
const doubleEncoded = escapeUri(normalizedPath);
|
|
21693
22059
|
return doubleEncoded.replace(/%2F/g, "/");
|
|
21694
22060
|
}
|
|
21695
|
-
return
|
|
22061
|
+
return path4;
|
|
21696
22062
|
}
|
|
21697
22063
|
validateResolvedCredentials(credentials) {
|
|
21698
22064
|
if (typeof credentials !== "object" || typeof credentials.accessKeyId !== "string" || typeof credentials.secretAccessKey !== "string") {
|
|
@@ -27687,8 +28053,8 @@ var init_createConfigValueProvider = __esm({
|
|
|
27687
28053
|
return endpoint.url.href;
|
|
27688
28054
|
}
|
|
27689
28055
|
if ("hostname" in endpoint) {
|
|
27690
|
-
const { protocol, hostname, port, path:
|
|
27691
|
-
return `${protocol}//${hostname}${port ? ":" + port : ""}${
|
|
28056
|
+
const { protocol, hostname, port, path: path4 } = endpoint;
|
|
28057
|
+
return `${protocol}//${hostname}${port ? ":" + port : ""}${path4}`;
|
|
27692
28058
|
}
|
|
27693
28059
|
}
|
|
27694
28060
|
return endpoint;
|
|
@@ -27904,14 +28270,14 @@ var init_readFile = __esm({
|
|
|
27904
28270
|
"node_modules/@smithy/shared-ini-file-loader/dist-es/readFile.js"() {
|
|
27905
28271
|
filePromises = {};
|
|
27906
28272
|
fileIntercept = {};
|
|
27907
|
-
readFile2 = (
|
|
27908
|
-
if (fileIntercept[
|
|
27909
|
-
return fileIntercept[
|
|
28273
|
+
readFile2 = (path4, options) => {
|
|
28274
|
+
if (fileIntercept[path4] !== void 0) {
|
|
28275
|
+
return fileIntercept[path4];
|
|
27910
28276
|
}
|
|
27911
|
-
if (!filePromises[
|
|
27912
|
-
filePromises[
|
|
28277
|
+
if (!filePromises[path4] || options?.ignoreCache) {
|
|
28278
|
+
filePromises[path4] = readFile(path4, "utf8");
|
|
27913
28279
|
}
|
|
27914
|
-
return filePromises[
|
|
28280
|
+
return filePromises[path4];
|
|
27915
28281
|
};
|
|
27916
28282
|
}
|
|
27917
28283
|
});
|
|
@@ -28020,8 +28386,8 @@ var init_externalDataInterceptor = __esm({
|
|
|
28020
28386
|
getFileRecord() {
|
|
28021
28387
|
return fileIntercept;
|
|
28022
28388
|
},
|
|
28023
|
-
interceptFile(
|
|
28024
|
-
fileIntercept[
|
|
28389
|
+
interceptFile(path4, contents) {
|
|
28390
|
+
fileIntercept[path4] = Promise.resolve(contents);
|
|
28025
28391
|
},
|
|
28026
28392
|
getTokenRecord() {
|
|
28027
28393
|
return tokenIntercept;
|
|
@@ -33819,7 +34185,7 @@ Set AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
|
|
|
33819
34185
|
if (token) {
|
|
33820
34186
|
request2.headers.Authorization = token;
|
|
33821
34187
|
} else if (tokenFile) {
|
|
33822
|
-
request2.headers.Authorization = (await
|
|
34188
|
+
request2.headers.Authorization = (await fs2.readFile(tokenFile)).toString();
|
|
33823
34189
|
}
|
|
33824
34190
|
try {
|
|
33825
34191
|
const result = await requestHandler.handle(request2);
|
|
@@ -43291,9 +43657,28 @@ function _getFailStrategy() {
|
|
|
43291
43657
|
function _hashPlaintext(plaintext, secret) {
|
|
43292
43658
|
const trimmed = plaintext.trim();
|
|
43293
43659
|
if (secret) {
|
|
43294
|
-
return
|
|
43660
|
+
return cryptoNode.createHmac("sha256", secret).update(trimmed, "utf-8").digest("hex");
|
|
43661
|
+
}
|
|
43662
|
+
return cryptoNode.createHash("sha256").update(trimmed, "utf-8").digest("hex");
|
|
43663
|
+
}
|
|
43664
|
+
function _vaultKey(token) {
|
|
43665
|
+
return `mask:${config.MASK_TENANT_ID}:${token}`;
|
|
43666
|
+
}
|
|
43667
|
+
function _vaultRevKey(ptHash) {
|
|
43668
|
+
return `mask-rev:${config.MASK_TENANT_ID}:${ptHash}`;
|
|
43669
|
+
}
|
|
43670
|
+
function _vaultHashKey(token) {
|
|
43671
|
+
return `mask-hash:${config.MASK_TENANT_ID}:${token}`;
|
|
43672
|
+
}
|
|
43673
|
+
function _unwrapPayload(raw) {
|
|
43674
|
+
if (raw && raw.startsWith("{")) {
|
|
43675
|
+
try {
|
|
43676
|
+
const obj = JSON.parse(raw);
|
|
43677
|
+
if (obj.ct) return obj.ct;
|
|
43678
|
+
} catch {
|
|
43679
|
+
}
|
|
43295
43680
|
}
|
|
43296
|
-
return
|
|
43681
|
+
return raw;
|
|
43297
43682
|
}
|
|
43298
43683
|
function getVault() {
|
|
43299
43684
|
if (_vaultInstance === null) {
|
|
@@ -43334,10 +43719,17 @@ async function encode(rawText, options = {}) {
|
|
|
43334
43719
|
return existingToken;
|
|
43335
43720
|
}
|
|
43336
43721
|
}
|
|
43337
|
-
const token = await
|
|
43722
|
+
const token = await generateDPToken(text, options.entityType || "UNKNOWN");
|
|
43338
43723
|
const ciphertext = cryptoEngine.encrypt(text);
|
|
43724
|
+
const existingCiphertext = await vault.retrieve(token);
|
|
43725
|
+
if (existingCiphertext !== null) {
|
|
43726
|
+
const existingHash = await vault.getPtHashForToken(token);
|
|
43727
|
+
if (existingHash && existingHash !== ptHash) {
|
|
43728
|
+
throw new TokenCollisionError(token, existingHash, ptHash);
|
|
43729
|
+
}
|
|
43730
|
+
}
|
|
43339
43731
|
const ttl = options.ttl || DEFAULT_TTL;
|
|
43340
|
-
await vault.store(token, ciphertext, ttl, ptHash);
|
|
43732
|
+
await vault.store(token, ciphertext, ttl, ptHash, options.metadata || null);
|
|
43341
43733
|
if (options.searchBuckets && options.searchBuckets.length > 0) {
|
|
43342
43734
|
for (const bType of options.searchBuckets) {
|
|
43343
43735
|
let bucketVal;
|
|
@@ -43359,8 +43751,8 @@ async function decode(token) {
|
|
|
43359
43751
|
throw new DecodeError("Token not found or expired");
|
|
43360
43752
|
}
|
|
43361
43753
|
try {
|
|
43362
|
-
const
|
|
43363
|
-
const result =
|
|
43754
|
+
const crypto7 = await getCryptoEngineAsync();
|
|
43755
|
+
const result = crypto7.decrypt(ciphertext);
|
|
43364
43756
|
getAuditLogger().log("decode", token);
|
|
43365
43757
|
return result;
|
|
43366
43758
|
} catch (e6) {
|
|
@@ -43412,14 +43804,15 @@ var init_vault = __esm({
|
|
|
43412
43804
|
MemoryVault = class extends BaseVault {
|
|
43413
43805
|
constructor() {
|
|
43414
43806
|
super();
|
|
43807
|
+
this._cleanupTimer = null;
|
|
43415
43808
|
this._store = /* @__PURE__ */ new Map();
|
|
43416
43809
|
this._reverseStore = /* @__PURE__ */ new Map();
|
|
43810
|
+
this._cleanupTimer = setInterval(() => this._cleanup(), 6e4);
|
|
43811
|
+
if (this._cleanupTimer && typeof this._cleanupTimer.unref === "function") {
|
|
43812
|
+
this._cleanupTimer.unref();
|
|
43813
|
+
}
|
|
43417
43814
|
}
|
|
43418
43815
|
_cleanup() {
|
|
43419
|
-
const cleanupFreq = config.MASK_VAULT_CLEANUP_FREQUENCY;
|
|
43420
|
-
if (Math.random() > cleanupFreq) {
|
|
43421
|
-
return;
|
|
43422
|
-
}
|
|
43423
43816
|
const now = Date.now() / 1e3;
|
|
43424
43817
|
for (const [token, entry] of this._store.entries()) {
|
|
43425
43818
|
if (now > entry.expiry) {
|
|
@@ -43430,27 +43823,41 @@ var init_vault = __esm({
|
|
|
43430
43823
|
}
|
|
43431
43824
|
}
|
|
43432
43825
|
}
|
|
43433
|
-
async store(token,
|
|
43434
|
-
this.
|
|
43826
|
+
async store(token, ciphertext, ttlSeconds, ptHash = null, metadata = null) {
|
|
43827
|
+
if (!this._store.has(token) && this._store.size >= config.MASK_VAULT_MAX_MEMORY_KEYS) {
|
|
43828
|
+
const firstKey = this._store.keys().next().value;
|
|
43829
|
+
if (firstKey !== void 0) {
|
|
43830
|
+
const oldEntry = this._store.get(firstKey);
|
|
43831
|
+
this._store.delete(firstKey);
|
|
43832
|
+
if (oldEntry?.ptHash && this._reverseStore.get(oldEntry.ptHash) === firstKey) {
|
|
43833
|
+
this._reverseStore.delete(oldEntry.ptHash);
|
|
43834
|
+
}
|
|
43835
|
+
}
|
|
43836
|
+
}
|
|
43837
|
+
const existing = this._store.get(token);
|
|
43838
|
+
if (existing) this._store.delete(token);
|
|
43435
43839
|
this._store.set(token, {
|
|
43436
|
-
plaintext,
|
|
43840
|
+
plaintext: ciphertext,
|
|
43437
43841
|
expiry: Date.now() / 1e3 + ttlSeconds,
|
|
43438
|
-
ptHash
|
|
43842
|
+
ptHash,
|
|
43843
|
+
metadata: { ...existing?.metadata || {}, ...metadata || {} }
|
|
43439
43844
|
});
|
|
43440
43845
|
if (ptHash) {
|
|
43441
43846
|
this._reverseStore.set(ptHash, token);
|
|
43442
43847
|
}
|
|
43443
43848
|
}
|
|
43444
43849
|
async getTokenByPlaintextHash(ptHash) {
|
|
43445
|
-
this._cleanup();
|
|
43446
43850
|
const token = this._reverseStore.get(ptHash);
|
|
43447
43851
|
if (token && this._store.has(token)) {
|
|
43448
43852
|
return token;
|
|
43449
43853
|
}
|
|
43450
43854
|
return null;
|
|
43451
43855
|
}
|
|
43856
|
+
async getPtHashForToken(token) {
|
|
43857
|
+
const entry = this._store.get(token);
|
|
43858
|
+
return entry?.ptHash ?? null;
|
|
43859
|
+
}
|
|
43452
43860
|
async retrieve(token) {
|
|
43453
|
-
this._cleanup();
|
|
43454
43861
|
const entry = this._store.get(token);
|
|
43455
43862
|
if (!entry) {
|
|
43456
43863
|
return null;
|
|
@@ -43506,13 +43913,14 @@ var init_vault = __esm({
|
|
|
43506
43913
|
throw new MaskVaultConnectionError(`Failed to connect to Redis: ${e6}`);
|
|
43507
43914
|
}
|
|
43508
43915
|
}
|
|
43509
|
-
async store(token, ciphertext, ttlSeconds, ptHash = null) {
|
|
43916
|
+
async store(token, ciphertext, ttlSeconds, ptHash = null, metadata = null) {
|
|
43510
43917
|
try {
|
|
43511
43918
|
const pipeline = this._client.pipeline();
|
|
43512
|
-
|
|
43919
|
+
const payload = metadata ? JSON.stringify({ ct: ciphertext, meta: metadata }) : ciphertext;
|
|
43920
|
+
pipeline.set(_vaultKey(token), payload, "EX", ttlSeconds);
|
|
43513
43921
|
if (ptHash) {
|
|
43514
|
-
pipeline.set(
|
|
43515
|
-
pipeline.set(
|
|
43922
|
+
pipeline.set(_vaultRevKey(ptHash), token, "EX", ttlSeconds);
|
|
43923
|
+
pipeline.set(_vaultHashKey(token), ptHash, "EX", ttlSeconds);
|
|
43516
43924
|
}
|
|
43517
43925
|
const results = await pipeline.exec();
|
|
43518
43926
|
if (results) {
|
|
@@ -43524,14 +43932,21 @@ var init_vault = __esm({
|
|
|
43524
43932
|
throw new MaskVaultConnectionError(`Redis error: ${e6}`);
|
|
43525
43933
|
}
|
|
43526
43934
|
}
|
|
43935
|
+
async getPtHashForToken(token) {
|
|
43936
|
+
try {
|
|
43937
|
+
return await this._client.get(_vaultHashKey(token));
|
|
43938
|
+
} catch {
|
|
43939
|
+
return null;
|
|
43940
|
+
}
|
|
43941
|
+
}
|
|
43527
43942
|
async getTokenByPlaintextHash(ptHash) {
|
|
43528
43943
|
try {
|
|
43529
|
-
const token = await this._client.get(
|
|
43944
|
+
const token = await this._client.get(_vaultRevKey(ptHash));
|
|
43530
43945
|
if (token) {
|
|
43531
|
-
if (await this._client.exists(
|
|
43946
|
+
if (await this._client.exists(_vaultKey(token))) {
|
|
43532
43947
|
return token;
|
|
43533
43948
|
} else {
|
|
43534
|
-
await this._client.del(
|
|
43949
|
+
await this._client.del(_vaultRevKey(ptHash));
|
|
43535
43950
|
}
|
|
43536
43951
|
}
|
|
43537
43952
|
return null;
|
|
@@ -43544,7 +43959,8 @@ var init_vault = __esm({
|
|
|
43544
43959
|
}
|
|
43545
43960
|
async retrieve(token) {
|
|
43546
43961
|
try {
|
|
43547
|
-
|
|
43962
|
+
const raw = await this._client.get(_vaultKey(token));
|
|
43963
|
+
return raw ? _unwrapPayload(raw) : null;
|
|
43548
43964
|
} catch (e6) {
|
|
43549
43965
|
if (_getFailStrategy() === "closed") {
|
|
43550
43966
|
throw new MaskVaultConnectionError(`Redis read failed: ${e6}`);
|
|
@@ -43554,12 +43970,12 @@ var init_vault = __esm({
|
|
|
43554
43970
|
}
|
|
43555
43971
|
async delete(token) {
|
|
43556
43972
|
try {
|
|
43557
|
-
const ptHash = await this._client.get(
|
|
43973
|
+
const ptHash = await this._client.get(_vaultHashKey(token));
|
|
43558
43974
|
const pipeline = this._client.pipeline();
|
|
43559
|
-
pipeline.del(
|
|
43560
|
-
pipeline.del(
|
|
43975
|
+
pipeline.del(_vaultKey(token));
|
|
43976
|
+
pipeline.del(_vaultHashKey(token));
|
|
43561
43977
|
if (ptHash) {
|
|
43562
|
-
pipeline.del(
|
|
43978
|
+
pipeline.del(_vaultRevKey(ptHash));
|
|
43563
43979
|
}
|
|
43564
43980
|
await pipeline.exec();
|
|
43565
43981
|
} catch (e6) {
|
|
@@ -43598,39 +44014,26 @@ var init_vault = __esm({
|
|
|
43598
44014
|
this._client = DynamoDBDocument.from(baseClient);
|
|
43599
44015
|
console.info(`DynamoDBVault connected to table ${this._tableName} in ${this._region}`);
|
|
43600
44016
|
}
|
|
43601
|
-
async store(token, ciphertext, ttlSeconds, ptHash = null) {
|
|
44017
|
+
async store(token, ciphertext, ttlSeconds, ptHash = null, metadata = null) {
|
|
43602
44018
|
const { TransactWriteCommand, PutCommand } = __require("@aws-sdk/lib-dynamodb");
|
|
43603
44019
|
const now = Math.floor(Date.now() / 1e3);
|
|
43604
44020
|
const ttlVal = now + ttlSeconds;
|
|
43605
|
-
const
|
|
43606
|
-
token:
|
|
44021
|
+
const primaryItem = {
|
|
44022
|
+
token: _vaultKey(token),
|
|
43607
44023
|
ciphertext,
|
|
43608
|
-
ttl: ttlVal
|
|
43609
|
-
ptr_hash: ptHash || void 0
|
|
44024
|
+
ttl: ttlVal
|
|
43610
44025
|
};
|
|
44026
|
+
if (ptHash) primaryItem.ptr_hash = ptHash;
|
|
44027
|
+
if (metadata) primaryItem.meta_json = JSON.stringify(metadata);
|
|
43611
44028
|
if (ptHash) {
|
|
43612
44029
|
try {
|
|
43613
44030
|
await this._client.send(new TransactWriteCommand({
|
|
43614
44031
|
TransactItems: [
|
|
44032
|
+
{ Put: { TableName: this._tableName, Item: primaryItem } },
|
|
43615
44033
|
{
|
|
43616
44034
|
Put: {
|
|
43617
44035
|
TableName: this._tableName,
|
|
43618
|
-
Item: {
|
|
43619
|
-
token: `mask:${token}`,
|
|
43620
|
-
ciphertext,
|
|
43621
|
-
ttl: ttlVal,
|
|
43622
|
-
ptr_hash: ptHash
|
|
43623
|
-
}
|
|
43624
|
-
}
|
|
43625
|
-
},
|
|
43626
|
-
{
|
|
43627
|
-
Put: {
|
|
43628
|
-
TableName: this._tableName,
|
|
43629
|
-
Item: {
|
|
43630
|
-
token: `mask-rev:${ptHash}`,
|
|
43631
|
-
ciphertext: token,
|
|
43632
|
-
ttl: ttlVal
|
|
43633
|
-
}
|
|
44036
|
+
Item: { token: _vaultRevKey(ptHash), ciphertext: token, ttl: ttlVal }
|
|
43634
44037
|
}
|
|
43635
44038
|
}
|
|
43636
44039
|
]
|
|
@@ -43641,7 +44044,7 @@ var init_vault = __esm({
|
|
|
43641
44044
|
}
|
|
43642
44045
|
} else {
|
|
43643
44046
|
try {
|
|
43644
|
-
await this._client.send(new PutCommand({ TableName: this._tableName, Item:
|
|
44047
|
+
await this._client.send(new PutCommand({ TableName: this._tableName, Item: primaryItem }));
|
|
43645
44048
|
} catch (e6) {
|
|
43646
44049
|
throw new MaskVaultConnectionError(`DynamoDB individual write failed: ${e6}`);
|
|
43647
44050
|
}
|
|
@@ -43653,12 +44056,12 @@ var init_vault = __esm({
|
|
|
43653
44056
|
const now = Math.floor(Date.now() / 1e3);
|
|
43654
44057
|
const resp = await this._client.send(new GetCommand({
|
|
43655
44058
|
TableName: this._tableName,
|
|
43656
|
-
Key: { token:
|
|
44059
|
+
Key: { token: _vaultRevKey(ptHash) }
|
|
43657
44060
|
}));
|
|
43658
44061
|
const item = resp.Item;
|
|
43659
44062
|
if (!item) return null;
|
|
43660
44063
|
if (now > (item.ttl || 0)) {
|
|
43661
|
-
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token:
|
|
44064
|
+
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token: _vaultRevKey(ptHash) } }));
|
|
43662
44065
|
return null;
|
|
43663
44066
|
}
|
|
43664
44067
|
const token = item.ciphertext;
|
|
@@ -43674,16 +44077,16 @@ var init_vault = __esm({
|
|
|
43674
44077
|
const now = Math.floor(Date.now() / 1e3);
|
|
43675
44078
|
const resp = await this._client.send(new GetCommand({
|
|
43676
44079
|
TableName: this._tableName,
|
|
43677
|
-
Key: { token:
|
|
44080
|
+
Key: { token: _vaultKey(token) }
|
|
43678
44081
|
}));
|
|
43679
44082
|
const item = resp.Item;
|
|
43680
44083
|
if (!item) return null;
|
|
43681
44084
|
if (now > (item.ttl || 0)) {
|
|
43682
44085
|
const ptHash = item.ptr_hash;
|
|
43683
44086
|
if (ptHash) {
|
|
43684
|
-
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token:
|
|
44087
|
+
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token: _vaultRevKey(ptHash) } }));
|
|
43685
44088
|
}
|
|
43686
|
-
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token:
|
|
44089
|
+
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token: _vaultKey(token) } }));
|
|
43687
44090
|
return null;
|
|
43688
44091
|
}
|
|
43689
44092
|
return item.ciphertext;
|
|
@@ -43692,18 +44095,30 @@ var init_vault = __esm({
|
|
|
43692
44095
|
return null;
|
|
43693
44096
|
}
|
|
43694
44097
|
}
|
|
44098
|
+
async getPtHashForToken(token) {
|
|
44099
|
+
try {
|
|
44100
|
+
const { GetCommand } = __require("@aws-sdk/lib-dynamodb");
|
|
44101
|
+
const resp = await this._client.send(new GetCommand({
|
|
44102
|
+
TableName: this._tableName,
|
|
44103
|
+
Key: { token: _vaultKey(token) }
|
|
44104
|
+
}));
|
|
44105
|
+
return resp.Item?.ptr_hash ?? null;
|
|
44106
|
+
} catch {
|
|
44107
|
+
return null;
|
|
44108
|
+
}
|
|
44109
|
+
}
|
|
43695
44110
|
async delete(token) {
|
|
43696
44111
|
try {
|
|
43697
44112
|
const { GetCommand, DeleteCommand } = __require("@aws-sdk/lib-dynamodb");
|
|
43698
44113
|
const resp = await this._client.send(new GetCommand({
|
|
43699
44114
|
TableName: this._tableName,
|
|
43700
|
-
Key: { token:
|
|
44115
|
+
Key: { token: _vaultKey(token) }
|
|
43701
44116
|
}));
|
|
43702
44117
|
const item = resp.Item;
|
|
43703
44118
|
if (item && item.ptr_hash) {
|
|
43704
|
-
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token:
|
|
44119
|
+
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token: _vaultRevKey(item.ptr_hash) } }));
|
|
43705
44120
|
}
|
|
43706
|
-
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token:
|
|
44121
|
+
await this._client.send(new DeleteCommand({ TableName: this._tableName, Key: { token: _vaultKey(token) } }));
|
|
43707
44122
|
} catch (e6) {
|
|
43708
44123
|
if (_getFailStrategy() === "closed") throw new MaskVaultConnectionError(`DynamoDB delete failed: ${e6}`);
|
|
43709
44124
|
}
|
|
@@ -43722,20 +44137,29 @@ var init_vault = __esm({
|
|
|
43722
44137
|
throw new MaskVaultConnectionError(`Failed to connect to Memcached: ${e6}`);
|
|
43723
44138
|
}
|
|
43724
44139
|
}
|
|
43725
|
-
async store(token, ciphertext, ttlSeconds, ptHash = null) {
|
|
44140
|
+
async store(token, ciphertext, ttlSeconds, ptHash = null, metadata = null) {
|
|
43726
44141
|
try {
|
|
43727
|
-
|
|
44142
|
+
const payload = metadata ? JSON.stringify({ ct: ciphertext, meta: metadata }) : ciphertext;
|
|
44143
|
+
await this._client.set(_vaultKey(token), Buffer.from(payload), { expires: ttlSeconds });
|
|
43728
44144
|
if (ptHash) {
|
|
43729
|
-
await this._client.set(
|
|
43730
|
-
await this._client.set(
|
|
44145
|
+
await this._client.set(_vaultRevKey(ptHash), Buffer.from(token), { expires: ttlSeconds });
|
|
44146
|
+
await this._client.set(_vaultHashKey(token), Buffer.from(ptHash), { expires: ttlSeconds });
|
|
43731
44147
|
}
|
|
43732
44148
|
} catch (e6) {
|
|
43733
44149
|
throw new MaskVaultConnectionError(`Memcached error: ${e6}`);
|
|
43734
44150
|
}
|
|
43735
44151
|
}
|
|
44152
|
+
async getPtHashForToken(token) {
|
|
44153
|
+
try {
|
|
44154
|
+
const { value } = await this._client.get(_vaultHashKey(token));
|
|
44155
|
+
return value ? value.toString() : null;
|
|
44156
|
+
} catch {
|
|
44157
|
+
return null;
|
|
44158
|
+
}
|
|
44159
|
+
}
|
|
43736
44160
|
async getTokenByPlaintextHash(ptHash) {
|
|
43737
44161
|
try {
|
|
43738
|
-
const { value } = await this._client.get(
|
|
44162
|
+
const { value } = await this._client.get(_vaultRevKey(ptHash));
|
|
43739
44163
|
if (!value) return null;
|
|
43740
44164
|
const token = value.toString();
|
|
43741
44165
|
return await this.retrieve(token) !== null ? token : null;
|
|
@@ -43746,8 +44170,9 @@ var init_vault = __esm({
|
|
|
43746
44170
|
}
|
|
43747
44171
|
async retrieve(token) {
|
|
43748
44172
|
try {
|
|
43749
|
-
const { value } = await this._client.get(
|
|
43750
|
-
|
|
44173
|
+
const { value } = await this._client.get(_vaultKey(token));
|
|
44174
|
+
if (!value) return null;
|
|
44175
|
+
return _unwrapPayload(value.toString());
|
|
43751
44176
|
} catch (e6) {
|
|
43752
44177
|
if (_getFailStrategy() === "closed") throw new MaskVaultConnectionError(`Memcached read failed: ${e6}`);
|
|
43753
44178
|
return null;
|
|
@@ -43755,12 +44180,12 @@ var init_vault = __esm({
|
|
|
43755
44180
|
}
|
|
43756
44181
|
async delete(token) {
|
|
43757
44182
|
try {
|
|
43758
|
-
const { value } = await this._client.get(
|
|
44183
|
+
const { value } = await this._client.get(_vaultHashKey(token));
|
|
43759
44184
|
const ptHash = value ? value.toString() : null;
|
|
43760
|
-
await this._client.delete(
|
|
43761
|
-
await this._client.delete(
|
|
44185
|
+
await this._client.delete(_vaultKey(token));
|
|
44186
|
+
await this._client.delete(_vaultHashKey(token));
|
|
43762
44187
|
if (ptHash) {
|
|
43763
|
-
await this._client.delete(
|
|
44188
|
+
await this._client.delete(_vaultRevKey(ptHash));
|
|
43764
44189
|
}
|
|
43765
44190
|
} catch (e6) {
|
|
43766
44191
|
if (_getFailStrategy() === "closed") throw new MaskVaultConnectionError(`Memcached delete failed: ${e6}`);
|
|
@@ -53478,11 +53903,11 @@ var require_mime_types = __commonJS({
|
|
|
53478
53903
|
}
|
|
53479
53904
|
return exts[0];
|
|
53480
53905
|
}
|
|
53481
|
-
function lookup(
|
|
53482
|
-
if (!
|
|
53906
|
+
function lookup(path4) {
|
|
53907
|
+
if (!path4 || typeof path4 !== "string") {
|
|
53483
53908
|
return false;
|
|
53484
53909
|
}
|
|
53485
|
-
var extension2 = extname("x." +
|
|
53910
|
+
var extension2 = extname("x." + path4).toLowerCase().substr(1);
|
|
53486
53911
|
if (!extension2) {
|
|
53487
53912
|
return false;
|
|
53488
53913
|
}
|
|
@@ -54549,13 +54974,13 @@ var require_form_data = __commonJS({
|
|
|
54549
54974
|
"node_modules/form-data/lib/form_data.js"(exports2, module) {
|
|
54550
54975
|
var CombinedStream = require_combined_stream();
|
|
54551
54976
|
var util = __require("util");
|
|
54552
|
-
var
|
|
54977
|
+
var path4 = __require("path");
|
|
54553
54978
|
var http = __require("http");
|
|
54554
54979
|
var https = __require("https");
|
|
54555
54980
|
var parseUrl2 = __require("url").parse;
|
|
54556
|
-
var
|
|
54981
|
+
var fs4 = __require("fs");
|
|
54557
54982
|
var Stream = __require("stream").Stream;
|
|
54558
|
-
var
|
|
54983
|
+
var crypto7 = __require("crypto");
|
|
54559
54984
|
var mime = require_mime_types();
|
|
54560
54985
|
var asynckit = require_asynckit();
|
|
54561
54986
|
var setToStringTag = require_es_set_tostringtag();
|
|
@@ -54620,7 +55045,7 @@ var require_form_data = __commonJS({
|
|
|
54620
55045
|
if (value.end != void 0 && value.end != Infinity && value.start != void 0) {
|
|
54621
55046
|
callback(null, value.end + 1 - (value.start ? value.start : 0));
|
|
54622
55047
|
} else {
|
|
54623
|
-
|
|
55048
|
+
fs4.stat(value.path, function(err2, stat) {
|
|
54624
55049
|
if (err2) {
|
|
54625
55050
|
callback(err2);
|
|
54626
55051
|
return;
|
|
@@ -54677,11 +55102,11 @@ var require_form_data = __commonJS({
|
|
|
54677
55102
|
FormData2.prototype._getContentDisposition = function(value, options) {
|
|
54678
55103
|
var filename;
|
|
54679
55104
|
if (typeof options.filepath === "string") {
|
|
54680
|
-
filename =
|
|
55105
|
+
filename = path4.normalize(options.filepath).replace(/\\/g, "/");
|
|
54681
55106
|
} else if (options.filename || value && (value.name || value.path)) {
|
|
54682
|
-
filename =
|
|
55107
|
+
filename = path4.basename(options.filename || value && (value.name || value.path));
|
|
54683
55108
|
} else if (value && value.readable && hasOwn(value, "httpVersion")) {
|
|
54684
|
-
filename =
|
|
55109
|
+
filename = path4.basename(value.client._httpMessage.path || "");
|
|
54685
55110
|
}
|
|
54686
55111
|
if (filename) {
|
|
54687
55112
|
return 'filename="' + filename + '"';
|
|
@@ -54761,7 +55186,7 @@ var require_form_data = __commonJS({
|
|
|
54761
55186
|
return Buffer.concat([dataBuffer, Buffer.from(this._lastBoundary())]);
|
|
54762
55187
|
};
|
|
54763
55188
|
FormData2.prototype._generateBoundary = function() {
|
|
54764
|
-
this._boundary = "--------------------------" +
|
|
55189
|
+
this._boundary = "--------------------------" + crypto7.randomBytes(12).toString("hex");
|
|
54765
55190
|
};
|
|
54766
55191
|
FormData2.prototype.getLengthSync = function() {
|
|
54767
55192
|
var knownLength = this._overheadLength + this._valueLength;
|
|
@@ -55451,7 +55876,7 @@ var require_follow_redirects = __commonJS({
|
|
|
55451
55876
|
var require_axios = __commonJS({
|
|
55452
55877
|
"node_modules/axios/dist/node/axios.cjs"(exports2, module) {
|
|
55453
55878
|
var FormData$1 = require_form_data();
|
|
55454
|
-
var
|
|
55879
|
+
var crypto7 = __require("crypto");
|
|
55455
55880
|
var url = __require("url");
|
|
55456
55881
|
var proxyFromEnv = require_proxy_from_env();
|
|
55457
55882
|
var http = __require("http");
|
|
@@ -55466,7 +55891,7 @@ var require_axios = __commonJS({
|
|
|
55466
55891
|
return e6 && typeof e6 === "object" && "default" in e6 ? e6 : { "default": e6 };
|
|
55467
55892
|
}
|
|
55468
55893
|
var FormData__default = /* @__PURE__ */ _interopDefaultLegacy(FormData$1);
|
|
55469
|
-
var crypto__default = /* @__PURE__ */ _interopDefaultLegacy(
|
|
55894
|
+
var crypto__default = /* @__PURE__ */ _interopDefaultLegacy(crypto7);
|
|
55470
55895
|
var url__default = /* @__PURE__ */ _interopDefaultLegacy(url);
|
|
55471
55896
|
var proxyFromEnv__default = /* @__PURE__ */ _interopDefaultLegacy(proxyFromEnv);
|
|
55472
55897
|
var http__default = /* @__PURE__ */ _interopDefaultLegacy(http);
|
|
@@ -55985,9 +56410,9 @@ var require_axios = __commonJS({
|
|
|
55985
56410
|
function removeBrackets(key) {
|
|
55986
56411
|
return utils$1.endsWith(key, "[]") ? key.slice(0, -2) : key;
|
|
55987
56412
|
}
|
|
55988
|
-
function renderKey(
|
|
55989
|
-
if (!
|
|
55990
|
-
return
|
|
56413
|
+
function renderKey(path4, key, dots) {
|
|
56414
|
+
if (!path4) return key;
|
|
56415
|
+
return path4.concat(key).map(function each(token, i6) {
|
|
55991
56416
|
token = removeBrackets(token);
|
|
55992
56417
|
return !dots && i6 ? "[" + token + "]" : token;
|
|
55993
56418
|
}).join(dots ? "." : "");
|
|
@@ -56040,13 +56465,13 @@ var require_axios = __commonJS({
|
|
|
56040
56465
|
}
|
|
56041
56466
|
return value;
|
|
56042
56467
|
}
|
|
56043
|
-
function defaultVisitor(value, key,
|
|
56468
|
+
function defaultVisitor(value, key, path4) {
|
|
56044
56469
|
let arr = value;
|
|
56045
56470
|
if (utils$1.isReactNative(formData) && utils$1.isReactNativeBlob(value)) {
|
|
56046
|
-
formData.append(renderKey(
|
|
56471
|
+
formData.append(renderKey(path4, key, dots), convertValue(value));
|
|
56047
56472
|
return false;
|
|
56048
56473
|
}
|
|
56049
|
-
if (value && !
|
|
56474
|
+
if (value && !path4 && typeof value === "object") {
|
|
56050
56475
|
if (utils$1.endsWith(key, "{}")) {
|
|
56051
56476
|
key = metaTokens ? key : key.slice(0, -2);
|
|
56052
56477
|
value = JSON.stringify(value);
|
|
@@ -56065,7 +56490,7 @@ var require_axios = __commonJS({
|
|
|
56065
56490
|
if (isVisitable(value)) {
|
|
56066
56491
|
return true;
|
|
56067
56492
|
}
|
|
56068
|
-
formData.append(renderKey(
|
|
56493
|
+
formData.append(renderKey(path4, key, dots), convertValue(value));
|
|
56069
56494
|
return false;
|
|
56070
56495
|
}
|
|
56071
56496
|
const stack = [];
|
|
@@ -56074,16 +56499,16 @@ var require_axios = __commonJS({
|
|
|
56074
56499
|
convertValue,
|
|
56075
56500
|
isVisitable
|
|
56076
56501
|
});
|
|
56077
|
-
function build(value,
|
|
56502
|
+
function build(value, path4) {
|
|
56078
56503
|
if (utils$1.isUndefined(value)) return;
|
|
56079
56504
|
if (stack.indexOf(value) !== -1) {
|
|
56080
|
-
throw Error("Circular reference detected in " +
|
|
56505
|
+
throw Error("Circular reference detected in " + path4.join("."));
|
|
56081
56506
|
}
|
|
56082
56507
|
stack.push(value);
|
|
56083
56508
|
utils$1.forEach(value, function each(el, key) {
|
|
56084
|
-
const result = !(utils$1.isUndefined(el) || el === null) && visitor.call(formData, el, utils$1.isString(key) ? key.trim() : key,
|
|
56509
|
+
const result = !(utils$1.isUndefined(el) || el === null) && visitor.call(formData, el, utils$1.isString(key) ? key.trim() : key, path4, exposedHelpers);
|
|
56085
56510
|
if (result === true) {
|
|
56086
|
-
build(el,
|
|
56511
|
+
build(el, path4 ? path4.concat(key) : [key]);
|
|
56087
56512
|
}
|
|
56088
56513
|
});
|
|
56089
56514
|
stack.pop();
|
|
@@ -56271,7 +56696,7 @@ var require_axios = __commonJS({
|
|
|
56271
56696
|
};
|
|
56272
56697
|
function toURLEncodedForm(data, options) {
|
|
56273
56698
|
return toFormData(data, new platform2.classes.URLSearchParams(), {
|
|
56274
|
-
visitor: function(value, key,
|
|
56699
|
+
visitor: function(value, key, path4, helpers) {
|
|
56275
56700
|
if (platform2.isNode && utils$1.isBuffer(value)) {
|
|
56276
56701
|
this.append(key, value.toString("base64"));
|
|
56277
56702
|
return false;
|
|
@@ -56299,11 +56724,11 @@ var require_axios = __commonJS({
|
|
|
56299
56724
|
return obj;
|
|
56300
56725
|
}
|
|
56301
56726
|
function formDataToJSON(formData) {
|
|
56302
|
-
function buildPath(
|
|
56303
|
-
let name =
|
|
56727
|
+
function buildPath(path4, value, target, index) {
|
|
56728
|
+
let name = path4[index++];
|
|
56304
56729
|
if (name === "__proto__") return true;
|
|
56305
56730
|
const isNumericKey = Number.isFinite(+name);
|
|
56306
|
-
const isLast = index >=
|
|
56731
|
+
const isLast = index >= path4.length;
|
|
56307
56732
|
name = !name && utils$1.isArray(target) ? target.length : name;
|
|
56308
56733
|
if (isLast) {
|
|
56309
56734
|
if (utils$1.hasOwnProp(target, name)) {
|
|
@@ -56316,7 +56741,7 @@ var require_axios = __commonJS({
|
|
|
56316
56741
|
if (!target[name] || !utils$1.isObject(target[name])) {
|
|
56317
56742
|
target[name] = [];
|
|
56318
56743
|
}
|
|
56319
|
-
const result = buildPath(
|
|
56744
|
+
const result = buildPath(path4, value, target[name], index);
|
|
56320
56745
|
if (result && utils$1.isArray(target[name])) {
|
|
56321
56746
|
target[name] = arrayToObject(target[name]);
|
|
56322
56747
|
}
|
|
@@ -57627,9 +58052,9 @@ var require_axios = __commonJS({
|
|
|
57627
58052
|
auth = urlUsername + ":" + urlPassword;
|
|
57628
58053
|
}
|
|
57629
58054
|
auth && headers.delete("authorization");
|
|
57630
|
-
let
|
|
58055
|
+
let path4;
|
|
57631
58056
|
try {
|
|
57632
|
-
|
|
58057
|
+
path4 = buildURL(
|
|
57633
58058
|
parsed.pathname + parsed.search,
|
|
57634
58059
|
config2.params,
|
|
57635
58060
|
config2.paramsSerializer
|
|
@@ -57647,7 +58072,7 @@ var require_axios = __commonJS({
|
|
|
57647
58072
|
false
|
|
57648
58073
|
);
|
|
57649
58074
|
const options = {
|
|
57650
|
-
path:
|
|
58075
|
+
path: path4,
|
|
57651
58076
|
method,
|
|
57652
58077
|
headers: headers.toJSON(),
|
|
57653
58078
|
agents: { http: config2.httpAgent, https: config2.httpsAgent },
|
|
@@ -57892,14 +58317,14 @@ var require_axios = __commonJS({
|
|
|
57892
58317
|
var cookies = platform2.hasStandardBrowserEnv ? (
|
|
57893
58318
|
// Standard browser envs support document.cookie
|
|
57894
58319
|
{
|
|
57895
|
-
write(name, value, expires,
|
|
58320
|
+
write(name, value, expires, path4, domain, secure, sameSite) {
|
|
57896
58321
|
if (typeof document === "undefined") return;
|
|
57897
58322
|
const cookie = [`${name}=${encodeURIComponent(value)}`];
|
|
57898
58323
|
if (utils$1.isNumber(expires)) {
|
|
57899
58324
|
cookie.push(`expires=${new Date(expires).toUTCString()}`);
|
|
57900
58325
|
}
|
|
57901
|
-
if (utils$1.isString(
|
|
57902
|
-
cookie.push(`path=${
|
|
58326
|
+
if (utils$1.isString(path4)) {
|
|
58327
|
+
cookie.push(`path=${path4}`);
|
|
57903
58328
|
}
|
|
57904
58329
|
if (utils$1.isString(domain)) {
|
|
57905
58330
|
cookie.push(`domain=${domain}`);
|
|
@@ -59245,7 +59670,7 @@ var init_transformers_scanner = __esm({
|
|
|
59245
59670
|
);
|
|
59246
59671
|
}
|
|
59247
59672
|
if (!this._pool) {
|
|
59248
|
-
const workerPath =
|
|
59673
|
+
const workerPath = path2.resolve(__dirname, "nlp_worker.js");
|
|
59249
59674
|
const maxThreads = Math.max(1, Math.min(os.cpus().length - 1, 4));
|
|
59250
59675
|
this._pool = new Piscina({
|
|
59251
59676
|
filename: workerPath,
|
|
@@ -59842,12 +60267,12 @@ var MaskClient = class _MaskClient {
|
|
|
59842
60267
|
*/
|
|
59843
60268
|
static async create(options = {}) {
|
|
59844
60269
|
const vault = options.vault || getVault();
|
|
59845
|
-
const
|
|
60270
|
+
const crypto7 = options.crypto || await getCryptoEngineAsync();
|
|
59846
60271
|
const scanner = options.scanner || getScanner();
|
|
59847
60272
|
const auditLogger = options.auditLogger || getAuditLogger();
|
|
59848
60273
|
return new _MaskClient({
|
|
59849
60274
|
vault,
|
|
59850
|
-
crypto:
|
|
60275
|
+
crypto: crypto7,
|
|
59851
60276
|
scanner,
|
|
59852
60277
|
auditLogger,
|
|
59853
60278
|
ttl: options.ttl
|