mask-privacy 3.5.1 → 4.0.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 +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +374 -50
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +368 -44
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/config.ts +5 -0
- package/src/core/dlp/registry.ts +7 -1
- package/src/core/fpe.ts +176 -28
- package/src/core/fpe_utils.ts +18 -8
- package/src/core/scanner.ts +2 -1
- package/src/core/span.ts +3 -0
- package/src/core/synthesisLibrary.ts +41 -0
- package/src/telemetry/audit_logger.ts +3 -1
- package/tests/bijective_fpe.test.ts +103 -0
package/dist/index.d.mts
CHANGED
|
@@ -69,6 +69,8 @@ interface Span {
|
|
|
69
69
|
confidence: number;
|
|
70
70
|
method: string;
|
|
71
71
|
language?: string;
|
|
72
|
+
ruleId?: string;
|
|
73
|
+
complianceScope?: ReadonlySet<string>;
|
|
72
74
|
maskedValue?: string;
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -371,6 +373,8 @@ interface PatternDescriptor {
|
|
|
371
373
|
validatorTag: string | null;
|
|
372
374
|
isHighEntropy: boolean;
|
|
373
375
|
supportedLocales: string[];
|
|
376
|
+
ruleId: string;
|
|
377
|
+
complianceScope: ReadonlySet<string>;
|
|
374
378
|
}
|
|
375
379
|
/**
|
|
376
380
|
* Immutable catalogue of sensitive-data regex signatures.
|
package/dist/index.d.ts
CHANGED
|
@@ -69,6 +69,8 @@ interface Span {
|
|
|
69
69
|
confidence: number;
|
|
70
70
|
method: string;
|
|
71
71
|
language?: string;
|
|
72
|
+
ruleId?: string;
|
|
73
|
+
complianceScope?: ReadonlySet<string>;
|
|
72
74
|
maskedValue?: string;
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -371,6 +373,8 @@ interface PatternDescriptor {
|
|
|
371
373
|
validatorTag: string | null;
|
|
372
374
|
isHighEntropy: boolean;
|
|
373
375
|
supportedLocales: string[];
|
|
376
|
+
ruleId: string;
|
|
377
|
+
complianceScope: ReadonlySet<string>;
|
|
374
378
|
}
|
|
375
379
|
/**
|
|
376
380
|
* Immutable catalogue of sensitive-data regex signatures.
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var process2 = require('process');
|
|
4
4
|
var path = require('path');
|
|
5
5
|
var os = require('os');
|
|
6
|
-
var
|
|
6
|
+
var crypto2 = require('crypto');
|
|
7
7
|
var buffer = require('buffer');
|
|
8
8
|
var stream = require('stream');
|
|
9
9
|
var https = require('https');
|
|
@@ -38,7 +38,7 @@ function _interopNamespace(e) {
|
|
|
38
38
|
var process2__namespace = /*#__PURE__*/_interopNamespace(process2);
|
|
39
39
|
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
40
40
|
var os__namespace = /*#__PURE__*/_interopNamespace(os);
|
|
41
|
-
var
|
|
41
|
+
var crypto2__namespace = /*#__PURE__*/_interopNamespace(crypto2);
|
|
42
42
|
var http2__default = /*#__PURE__*/_interopDefault(http2);
|
|
43
43
|
var fs__default = /*#__PURE__*/_interopDefault(fs$1);
|
|
44
44
|
|
|
@@ -114,6 +114,16 @@ var init_config = __esm({
|
|
|
114
114
|
get MASK_LOG_LEVEL() {
|
|
115
115
|
return (process2__namespace.env.MASK_LOG_LEVEL || "info").toLowerCase();
|
|
116
116
|
},
|
|
117
|
+
// --- COMPLIANCE & PRIVACY (Bijective) ---
|
|
118
|
+
get MASK_TENANT_ID() {
|
|
119
|
+
return process2__namespace.env.MASK_TENANT_ID || "global-default-tenant";
|
|
120
|
+
},
|
|
121
|
+
get MASK_SALT_ROTATION() {
|
|
122
|
+
return (process2__namespace.env.MASK_SALT_ROTATION || "NONE").toUpperCase();
|
|
123
|
+
},
|
|
124
|
+
get MASK_BIJECTIVE_MODE() {
|
|
125
|
+
return getEnvBool("MASK_BIJECTIVE_MODE", true);
|
|
126
|
+
},
|
|
117
127
|
// --- SECURITY & CRYPTOGRAPHY ---
|
|
118
128
|
get MASK_ENCRYPTION_KEY() {
|
|
119
129
|
return process2__namespace.env.MASK_ENCRYPTION_KEY || null;
|
|
@@ -252,6 +262,216 @@ var init_exceptions = __esm({
|
|
|
252
262
|
}
|
|
253
263
|
});
|
|
254
264
|
|
|
265
|
+
// src/core/synthesisLibrary.ts
|
|
266
|
+
var FIRST_NAMES, CONNECTORS, SURNAME_ROOTS, SURNAME_SUFFIXES, SYLLABLES;
|
|
267
|
+
var init_synthesisLibrary = __esm({
|
|
268
|
+
"src/core/synthesisLibrary.ts"() {
|
|
269
|
+
FIRST_NAMES = [
|
|
270
|
+
"James",
|
|
271
|
+
"Mary",
|
|
272
|
+
"Robert",
|
|
273
|
+
"Patricia",
|
|
274
|
+
"John",
|
|
275
|
+
"Jennifer",
|
|
276
|
+
"Michael",
|
|
277
|
+
"Linda",
|
|
278
|
+
"David",
|
|
279
|
+
"Elizabeth",
|
|
280
|
+
"William",
|
|
281
|
+
"Barbara",
|
|
282
|
+
"Richard",
|
|
283
|
+
"Susan",
|
|
284
|
+
"Joseph",
|
|
285
|
+
"Jessica"
|
|
286
|
+
];
|
|
287
|
+
while (FIRST_NAMES.length < 2048) {
|
|
288
|
+
FIRST_NAMES.push(`NameEx_${FIRST_NAMES.length}`);
|
|
289
|
+
}
|
|
290
|
+
CONNECTORS = [
|
|
291
|
+
"of",
|
|
292
|
+
"from",
|
|
293
|
+
"van",
|
|
294
|
+
"del",
|
|
295
|
+
"di",
|
|
296
|
+
"von",
|
|
297
|
+
"le",
|
|
298
|
+
"la",
|
|
299
|
+
"de",
|
|
300
|
+
"el",
|
|
301
|
+
"the",
|
|
302
|
+
"near",
|
|
303
|
+
"at",
|
|
304
|
+
"by",
|
|
305
|
+
"under",
|
|
306
|
+
"over",
|
|
307
|
+
"across",
|
|
308
|
+
"beyond",
|
|
309
|
+
"within",
|
|
310
|
+
"without",
|
|
311
|
+
"and",
|
|
312
|
+
"with",
|
|
313
|
+
"aka",
|
|
314
|
+
"alias",
|
|
315
|
+
"formally",
|
|
316
|
+
"lately",
|
|
317
|
+
"born",
|
|
318
|
+
"styled",
|
|
319
|
+
"known",
|
|
320
|
+
"called",
|
|
321
|
+
"st",
|
|
322
|
+
"al",
|
|
323
|
+
"bin",
|
|
324
|
+
"ibn",
|
|
325
|
+
"abu",
|
|
326
|
+
"ben",
|
|
327
|
+
"bar",
|
|
328
|
+
"fitz",
|
|
329
|
+
"mac",
|
|
330
|
+
"mc",
|
|
331
|
+
"o",
|
|
332
|
+
"da",
|
|
333
|
+
"dos",
|
|
334
|
+
"das",
|
|
335
|
+
"do",
|
|
336
|
+
"du",
|
|
337
|
+
"della",
|
|
338
|
+
"degli",
|
|
339
|
+
"dei",
|
|
340
|
+
"delle",
|
|
341
|
+
"sur",
|
|
342
|
+
"ter",
|
|
343
|
+
"ten",
|
|
344
|
+
"zu",
|
|
345
|
+
"zum",
|
|
346
|
+
"zur",
|
|
347
|
+
"auf",
|
|
348
|
+
"an",
|
|
349
|
+
"der",
|
|
350
|
+
"die",
|
|
351
|
+
"das",
|
|
352
|
+
"pro",
|
|
353
|
+
"anti",
|
|
354
|
+
"ex",
|
|
355
|
+
"quasi"
|
|
356
|
+
];
|
|
357
|
+
SURNAME_ROOTS = [
|
|
358
|
+
"Silver",
|
|
359
|
+
"Gold",
|
|
360
|
+
"Iron",
|
|
361
|
+
"Stone",
|
|
362
|
+
"Rock",
|
|
363
|
+
"Wood",
|
|
364
|
+
"Leaf",
|
|
365
|
+
"Rain",
|
|
366
|
+
"Snow",
|
|
367
|
+
"Wind",
|
|
368
|
+
"Storm",
|
|
369
|
+
"Cloud",
|
|
370
|
+
"Sun",
|
|
371
|
+
"Moon",
|
|
372
|
+
"Star",
|
|
373
|
+
"Sky",
|
|
374
|
+
"Sea",
|
|
375
|
+
"Lake",
|
|
376
|
+
"River",
|
|
377
|
+
"Brook",
|
|
378
|
+
"Hill",
|
|
379
|
+
"Mount",
|
|
380
|
+
"Vale",
|
|
381
|
+
"Glen",
|
|
382
|
+
"Dale",
|
|
383
|
+
"Field",
|
|
384
|
+
"Meadow",
|
|
385
|
+
"Forest",
|
|
386
|
+
"Grove",
|
|
387
|
+
"Wild"
|
|
388
|
+
];
|
|
389
|
+
while (SURNAME_ROOTS.length < 4096) {
|
|
390
|
+
SURNAME_ROOTS.push(`RootEx_${SURNAME_ROOTS.length}`);
|
|
391
|
+
}
|
|
392
|
+
SURNAME_SUFFIXES = [
|
|
393
|
+
"son",
|
|
394
|
+
"man",
|
|
395
|
+
"field",
|
|
396
|
+
"wood",
|
|
397
|
+
"berg",
|
|
398
|
+
"stein",
|
|
399
|
+
"ov",
|
|
400
|
+
"ova",
|
|
401
|
+
"ski",
|
|
402
|
+
"ska",
|
|
403
|
+
"ez",
|
|
404
|
+
"ez",
|
|
405
|
+
"ia",
|
|
406
|
+
"ic",
|
|
407
|
+
"os",
|
|
408
|
+
"as",
|
|
409
|
+
"is",
|
|
410
|
+
"us",
|
|
411
|
+
"er",
|
|
412
|
+
"en",
|
|
413
|
+
"ard",
|
|
414
|
+
"ier",
|
|
415
|
+
"eau",
|
|
416
|
+
"oux",
|
|
417
|
+
"ly",
|
|
418
|
+
"ley",
|
|
419
|
+
"ton",
|
|
420
|
+
"don",
|
|
421
|
+
"ham",
|
|
422
|
+
"ford",
|
|
423
|
+
"wick",
|
|
424
|
+
"shire",
|
|
425
|
+
"land",
|
|
426
|
+
"way",
|
|
427
|
+
"side",
|
|
428
|
+
"gate",
|
|
429
|
+
"bridge",
|
|
430
|
+
"well",
|
|
431
|
+
"pool",
|
|
432
|
+
"cliff",
|
|
433
|
+
"bank",
|
|
434
|
+
"shore",
|
|
435
|
+
"hart",
|
|
436
|
+
"foot",
|
|
437
|
+
"head",
|
|
438
|
+
"more",
|
|
439
|
+
"less",
|
|
440
|
+
"ness",
|
|
441
|
+
"ship",
|
|
442
|
+
"ward"
|
|
443
|
+
];
|
|
444
|
+
while (SURNAME_SUFFIXES.length < 512) {
|
|
445
|
+
SURNAME_SUFFIXES.push(`SuffixEx_${SURNAME_SUFFIXES.length}`);
|
|
446
|
+
}
|
|
447
|
+
SYLLABLES = [
|
|
448
|
+
"San",
|
|
449
|
+
"Ver",
|
|
450
|
+
"Dina",
|
|
451
|
+
"Lon",
|
|
452
|
+
"Don",
|
|
453
|
+
"Chi",
|
|
454
|
+
"Ca",
|
|
455
|
+
"Go",
|
|
456
|
+
"New",
|
|
457
|
+
"York",
|
|
458
|
+
"Los",
|
|
459
|
+
"An",
|
|
460
|
+
"Ge",
|
|
461
|
+
"Les",
|
|
462
|
+
"Pa",
|
|
463
|
+
"Ris",
|
|
464
|
+
"Ber",
|
|
465
|
+
"Lin",
|
|
466
|
+
"Mad",
|
|
467
|
+
"Rid"
|
|
468
|
+
];
|
|
469
|
+
while (SYLLABLES.length < 1e3) {
|
|
470
|
+
SYLLABLES.push(`Syl_${SYLLABLES.length}`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
|
|
255
475
|
// src/core/fpe_utils.ts
|
|
256
476
|
function looksLikeToken(value) {
|
|
257
477
|
if (typeof value !== "string") return false;
|
|
@@ -286,13 +506,20 @@ function looksLikeToken(value) {
|
|
|
286
506
|
if (v7.startsWith("[TKN-") && v7.endsWith("]")) {
|
|
287
507
|
return true;
|
|
288
508
|
}
|
|
509
|
+
if (v7.includes("-") && v7.length >= 6) {
|
|
510
|
+
const parts = v7.split("-");
|
|
511
|
+
const tag = parts[parts.length - 1];
|
|
512
|
+
if (tag.length === 4 && /^\d+$/.test(tag)) {
|
|
513
|
+
return true;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
289
516
|
return false;
|
|
290
517
|
}
|
|
291
518
|
var TOKEN_PATTERN;
|
|
292
519
|
var init_fpe_utils = __esm({
|
|
293
520
|
"src/core/fpe_utils.ts"() {
|
|
294
521
|
TOKEN_PATTERN = new RegExp(
|
|
295
|
-
"tkn-[a-f0-9]{8,64}@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}|\\+[1-9]\\d{0,3}-555-\\d{7}|000-00-\\d{4}|4000-0000-0000-\\d{4}|000000\\d{3}|000\\d{5}[A-Z]|[A-Z]{2}00[A-F0-9]{4,16}|<(?:PER|LOC|ORG):[^>]+>|\\[TKN-[a-f0-9]{8,64}
|
|
522
|
+
"tkn-[a-f0-9]{8,64}@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,}|\\+[1-9]\\d{0,3}-555-\\d{7}|000-00-\\d{4}|4000-0000-0000-\\d{4}|000000\\d{3}|000\\d{5}[A-Z]|[A-Z]{2}00[A-F0-9]{4,16}|<(?:PER|LOC|ORG):[^>]+>|\\b[A-Z][a-zA-Z, ]+-[0-9]{3,4}\\b|\\\\[TKN-[a-f0-9]{8,64}\\\\]",
|
|
296
523
|
// Opaque
|
|
297
524
|
"g"
|
|
298
525
|
);
|
|
@@ -307,7 +534,7 @@ async function _getMasterKey() {
|
|
|
307
534
|
}
|
|
308
535
|
if (!raw) {
|
|
309
536
|
if (config.MASK_DEV_MODE) {
|
|
310
|
-
raw =
|
|
537
|
+
raw = crypto2__namespace.randomBytes(32).toString("hex");
|
|
311
538
|
process.env.MASK_MASTER_KEY = raw;
|
|
312
539
|
} else {
|
|
313
540
|
throw new exports.MaskSecurityError(
|
|
@@ -324,27 +551,64 @@ function resetMasterKey() {
|
|
|
324
551
|
}
|
|
325
552
|
async function _hmacHex(plaintext, n6 = 8) {
|
|
326
553
|
const masterKey = await _getMasterKey();
|
|
327
|
-
const digest =
|
|
554
|
+
const digest = crypto2__namespace.createHmac("sha256", masterKey).update(plaintext, "utf-8").digest("hex");
|
|
328
555
|
return digest.slice(0, n6);
|
|
329
556
|
}
|
|
330
|
-
async function
|
|
557
|
+
async function _hmacInt(plaintext) {
|
|
331
558
|
const masterKey = await _getMasterKey();
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
for (let i6 =
|
|
335
|
-
|
|
336
|
-
result.push((parseInt(ch, 16) % 10).toString());
|
|
337
|
-
if (result.length === n6) break;
|
|
559
|
+
const raw = crypto2__namespace.createHmac("sha256", masterKey).update(plaintext, "utf-8").digest();
|
|
560
|
+
let result = 0n;
|
|
561
|
+
for (let i6 = 0; i6 < 16; i6++) {
|
|
562
|
+
result = result << 8n | BigInt(raw[i6]);
|
|
338
563
|
}
|
|
339
|
-
|
|
340
|
-
|
|
564
|
+
return result;
|
|
565
|
+
}
|
|
566
|
+
async function _hmacDigits(plaintext, n6, offset = 0) {
|
|
567
|
+
const salted = offset ? `${plaintext}::${offset}` : plaintext;
|
|
568
|
+
const seed = await _hmacInt(salted);
|
|
569
|
+
const modulus = 10n ** BigInt(n6);
|
|
570
|
+
return (seed % modulus).toString().padStart(n6, "0");
|
|
571
|
+
}
|
|
572
|
+
async function _getBijectiveTweak() {
|
|
573
|
+
const masterKey = await _getMasterKey();
|
|
574
|
+
let base = config.MASK_TENANT_ID;
|
|
575
|
+
if (config.MASK_SALT_ROTATION !== "NONE") {
|
|
576
|
+
const now = /* @__PURE__ */ new Date();
|
|
577
|
+
if (config.MASK_SALT_ROTATION === "MONTHLY") {
|
|
578
|
+
base += `-${now.getUTCFullYear()}-${now.getUTCMonth() + 1}`;
|
|
579
|
+
} else if (config.MASK_SALT_ROTATION === "YEARLY") {
|
|
580
|
+
base += `-${now.getUTCFullYear()}`;
|
|
581
|
+
}
|
|
341
582
|
}
|
|
342
|
-
return
|
|
583
|
+
return crypto2__namespace.createHmac("sha256", masterKey).update(base, "utf-8").digest();
|
|
343
584
|
}
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
const
|
|
347
|
-
|
|
585
|
+
function _renderBijectivePerson(bits) {
|
|
586
|
+
const firstIdx = Number(bits & 0x7FFn);
|
|
587
|
+
const connIdx = Number(bits >> 11n & 0x3Fn);
|
|
588
|
+
const rootIdx = Number(bits >> 17n & 0xFFFn);
|
|
589
|
+
const suffixIdx = Number(bits >> 29n & 0x1FFn);
|
|
590
|
+
const tag = Number(bits >> 38n & 0x3FFFn);
|
|
591
|
+
const formatIdx = Number(bits >> 52n & 0xFn);
|
|
592
|
+
const first = FIRST_NAMES[firstIdx % FIRST_NAMES.length];
|
|
593
|
+
const conn = CONNECTORS[connIdx % CONNECTORS.length];
|
|
594
|
+
const root = SURNAME_ROOTS[rootIdx % SURNAME_ROOTS.length];
|
|
595
|
+
const suffix = SURNAME_SUFFIXES[suffixIdx % SURNAME_SUFFIXES.length];
|
|
596
|
+
const surname = `${root}${suffix}`;
|
|
597
|
+
const numeric = tag % 1e4;
|
|
598
|
+
const paddedNumeric = numeric.toString().padStart(4, "0");
|
|
599
|
+
if (formatIdx === 0) return `${first} ${conn} ${surname}-${paddedNumeric}`;
|
|
600
|
+
if (formatIdx === 1) return `${surname}, ${first}-${paddedNumeric}`;
|
|
601
|
+
if (formatIdx === 2) return `${first[0]}. ${surname}-${paddedNumeric}`;
|
|
602
|
+
if (formatIdx === 3) return `${first} ${surname}-${paddedNumeric}`;
|
|
603
|
+
return `${first} ${surname}-${paddedNumeric}`;
|
|
604
|
+
}
|
|
605
|
+
function _renderBijectiveLocation(bits) {
|
|
606
|
+
const s1 = Number(bits & 0x3FFn);
|
|
607
|
+
const s22 = Number(bits >> 10n & 0x3FFn);
|
|
608
|
+
const s32 = Number(bits >> 20n & 0x3FFn);
|
|
609
|
+
const tag = Number(bits >> 30n & 0xFFFn);
|
|
610
|
+
const city = `${SYLLABLES[s1 % 1e3]}${SYLLABLES[s22 % 1e3].toLowerCase()}${SYLLABLES[s32 % 1e3].toLowerCase()}`;
|
|
611
|
+
return `${city}-${tag.toString().padStart(3, "0")}`;
|
|
348
612
|
}
|
|
349
613
|
function _computeLuhnDigit(partialNum) {
|
|
350
614
|
const digits = partialNum.split("").map(Number);
|
|
@@ -407,26 +671,41 @@ async function generateFPEToken(rawText, entityType = "UNKNOWN") {
|
|
|
407
671
|
return digits + _computeEsIdCheck(parseInt(digits, 10));
|
|
408
672
|
}
|
|
409
673
|
if (type === "PERSON" || type === "PERSON_NAME") {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
674
|
+
if (config.MASK_BIJECTIVE_MODE) {
|
|
675
|
+
const canonical = text.toLowerCase().trim();
|
|
676
|
+
const hash = crypto2__namespace.createHash("sha256").update(canonical, "utf-8").digest();
|
|
677
|
+
const inputInt = hash.readBigUInt64BE(0);
|
|
678
|
+
const masterKey = await _getMasterKey();
|
|
679
|
+
const engine = new FF1(masterKey.slice(0, 16), await _getBijectiveTweak());
|
|
680
|
+
const cipher = engine.encrypt(inputInt);
|
|
681
|
+
return _renderBijectivePerson(cipher);
|
|
682
|
+
}
|
|
683
|
+
return `[TKN-PERSON-${await _hmacHex(text)}]`;
|
|
413
684
|
}
|
|
414
685
|
if (type === "LOCATION" || type === "PHYS_ADDRESS") {
|
|
415
|
-
|
|
416
|
-
|
|
686
|
+
if (config.MASK_BIJECTIVE_MODE) {
|
|
687
|
+
const canonical = text.toLowerCase().trim();
|
|
688
|
+
const hash = crypto2__namespace.createHash("sha256").update(canonical, "utf-8").digest();
|
|
689
|
+
const inputInt = hash.readBigUInt64BE(0);
|
|
690
|
+
const masterKey = await _getMasterKey();
|
|
691
|
+
const engine = new FF1(masterKey.slice(0, 16), await _getBijectiveTweak());
|
|
692
|
+
const cipher = engine.encrypt(inputInt);
|
|
693
|
+
return _renderBijectiveLocation(cipher);
|
|
694
|
+
}
|
|
695
|
+
return `[TKN-LOC-${await _hmacHex(text)}]`;
|
|
417
696
|
}
|
|
418
697
|
if (type === "ORGANIZATION") {
|
|
419
|
-
|
|
420
|
-
return `<ORG:${c6}_Inc>`;
|
|
698
|
+
return `[TKN-ORG-${await _hmacHex(text)}]`;
|
|
421
699
|
}
|
|
422
700
|
return `[TKN-${await _hmacHex(text)}]`;
|
|
423
701
|
}
|
|
424
|
-
var _masterKey, _EMAIL_RE, _PHONE_RE, _SSN_RE, _CC_RE, _ROUTING_RE, _ES_ID_RE, _IBAN_RE,
|
|
702
|
+
var _masterKey, _EMAIL_RE, _PHONE_RE, _SSN_RE, _CC_RE, _ROUTING_RE, _ES_ID_RE, _IBAN_RE, FF1;
|
|
425
703
|
var init_fpe = __esm({
|
|
426
704
|
"src/core/fpe.ts"() {
|
|
427
705
|
init_config();
|
|
428
706
|
init_key_provider();
|
|
429
707
|
init_exceptions();
|
|
708
|
+
init_synthesisLibrary();
|
|
430
709
|
init_fpe_utils();
|
|
431
710
|
_masterKey = null;
|
|
432
711
|
_EMAIL_RE = /^[^@\s]+@[^@\s]+\.[^@\s]+$/;
|
|
@@ -436,9 +715,49 @@ var init_fpe = __esm({
|
|
|
436
715
|
_ROUTING_RE = /^\d{9}$/;
|
|
437
716
|
_ES_ID_RE = /^(?:\d{8}[A-Z]|[XYZ]\d{7}[A-Z])$/;
|
|
438
717
|
_IBAN_RE = /^[A-Z]{2}\d{2}[A-Z0-9]{4,30}$/;
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
718
|
+
FF1 = class {
|
|
719
|
+
/** NIST SP 800-38G FF1 implementation (simplified for 64-bit domains). */
|
|
720
|
+
constructor(key, tweak) {
|
|
721
|
+
this.key = key;
|
|
722
|
+
this.tweak = tweak;
|
|
723
|
+
}
|
|
724
|
+
encrypt(n6) {
|
|
725
|
+
let A3 = n6 >> 32n;
|
|
726
|
+
let B3 = n6 & 0xFFFFFFFFn;
|
|
727
|
+
const radix = 2n ** 32n;
|
|
728
|
+
for (let i6 = 0; i6 < 10; i6++) {
|
|
729
|
+
const tweakInfoBuffer = Buffer.alloc(8);
|
|
730
|
+
tweakInfoBuffer.writeUInt32BE(i6, 0);
|
|
731
|
+
tweakInfoBuffer.writeUInt32BE(Number(B3), 4);
|
|
732
|
+
const tweakInfoCombined = Buffer.concat([this.tweak, tweakInfoBuffer]);
|
|
733
|
+
const h6 = crypto2__namespace.createHmac("sha256", this.key).update(tweakInfoCombined).digest();
|
|
734
|
+
const roundVal = BigInt(h6.readUInt32BE(0));
|
|
735
|
+
const Anext = B3;
|
|
736
|
+
const Bnext = (A3 + roundVal) % radix;
|
|
737
|
+
A3 = Anext;
|
|
738
|
+
B3 = Bnext;
|
|
739
|
+
}
|
|
740
|
+
return A3 << 32n | B3;
|
|
741
|
+
}
|
|
742
|
+
decrypt(n6) {
|
|
743
|
+
let A3 = n6 >> 32n;
|
|
744
|
+
let B3 = n6 & 0xFFFFFFFFn;
|
|
745
|
+
const radix = 2n ** 32n;
|
|
746
|
+
for (let i6 = 9; i6 >= 0; i6--) {
|
|
747
|
+
const tweakInfoBuffer = Buffer.alloc(8);
|
|
748
|
+
tweakInfoBuffer.writeUInt32BE(i6, 0);
|
|
749
|
+
tweakInfoBuffer.writeUInt32BE(Number(A3), 4);
|
|
750
|
+
const tweakInfoCombined = Buffer.concat([this.tweak, tweakInfoBuffer]);
|
|
751
|
+
const h6 = crypto2__namespace.createHmac("sha256", this.key).update(tweakInfoCombined).digest();
|
|
752
|
+
const roundVal = BigInt(h6.readUInt32BE(0));
|
|
753
|
+
const Bprev = A3;
|
|
754
|
+
const Aprev = (B3 - roundVal + radix) % radix;
|
|
755
|
+
A3 = Aprev;
|
|
756
|
+
B3 = Bprev;
|
|
757
|
+
}
|
|
758
|
+
return A3 << 32n | B3;
|
|
759
|
+
}
|
|
760
|
+
};
|
|
442
761
|
}
|
|
443
762
|
});
|
|
444
763
|
|
|
@@ -2906,7 +3225,7 @@ var init_crypto = __esm({
|
|
|
2906
3225
|
let key;
|
|
2907
3226
|
if (!keyFromProvider) {
|
|
2908
3227
|
if (config.MASK_DEV_MODE) {
|
|
2909
|
-
key =
|
|
3228
|
+
key = crypto2__namespace.randomBytes(32).toString("base64");
|
|
2910
3229
|
process.env.MASK_ENCRYPTION_KEY = key;
|
|
2911
3230
|
console.warn(
|
|
2912
3231
|
"MASK_DEV_MODE is enabled. Using a generated throwaway key. DO NOT USE THIS IN PRODUCTION \u2014 tokens will be lost on restart."
|
|
@@ -2919,10 +3238,10 @@ var init_crypto = __esm({
|
|
|
2919
3238
|
} else {
|
|
2920
3239
|
key = keyFromProvider;
|
|
2921
3240
|
}
|
|
2922
|
-
this._aesKey =
|
|
3241
|
+
this._aesKey = crypto2__namespace.createHash("sha256").update(key).digest();
|
|
2923
3242
|
const masterKey = await provider.getMasterKey() || key;
|
|
2924
3243
|
const salt = config.MASK_BLIND_INDEX_SALT;
|
|
2925
|
-
this._indexSecret =
|
|
3244
|
+
this._indexSecret = crypto2__namespace.createHmac("sha256", masterKey).update(salt).digest();
|
|
2926
3245
|
}
|
|
2927
3246
|
/** Return the secret used for HMAC-based blind indexing. */
|
|
2928
3247
|
async getIndexSecret() {
|
|
@@ -2935,8 +3254,8 @@ var init_crypto = __esm({
|
|
|
2935
3254
|
if (!this._aesKey) {
|
|
2936
3255
|
throw new Error("CryptoEngine not initialised. AES key missing.");
|
|
2937
3256
|
}
|
|
2938
|
-
const iv =
|
|
2939
|
-
const cipher =
|
|
3257
|
+
const iv = crypto2__namespace.randomBytes(GCM_IV_BYTES);
|
|
3258
|
+
const cipher = crypto2__namespace.createCipheriv(GCM_ALGORITHM, this._aesKey, iv);
|
|
2940
3259
|
const encrypted = Buffer.concat([
|
|
2941
3260
|
cipher.update(plaintext, "utf8"),
|
|
2942
3261
|
cipher.final()
|
|
@@ -2968,7 +3287,7 @@ var init_crypto = __esm({
|
|
|
2968
3287
|
const iv = combined.subarray(0, GCM_IV_BYTES);
|
|
2969
3288
|
const authTag = combined.subarray(GCM_IV_BYTES, GCM_IV_BYTES + GCM_AUTH_TAG_BYTES);
|
|
2970
3289
|
const encrypted = combined.subarray(GCM_IV_BYTES + GCM_AUTH_TAG_BYTES);
|
|
2971
|
-
const decipher =
|
|
3290
|
+
const decipher = crypto2__namespace.createDecipheriv(GCM_ALGORITHM, this._aesKey, iv);
|
|
2972
3291
|
decipher.setAuthTag(authTag);
|
|
2973
3292
|
const decrypted = Buffer.concat([
|
|
2974
3293
|
decipher.update(encrypted),
|
|
@@ -3152,7 +3471,8 @@ var init_audit_logger = __esm({
|
|
|
3152
3471
|
this._buffer = [];
|
|
3153
3472
|
this._bufferFullWarned = false;
|
|
3154
3473
|
for (const evt of events) {
|
|
3155
|
-
|
|
3474
|
+
const json = JSON.stringify(evt, (_, v7) => typeof v7 === "bigint" ? v7.toString() : v7);
|
|
3475
|
+
console.info(json);
|
|
3156
3476
|
}
|
|
3157
3477
|
} finally {
|
|
3158
3478
|
this._isFlushing = false;
|
|
@@ -3216,7 +3536,7 @@ var init_search = __esm({
|
|
|
3216
3536
|
static async getBucketIndex(bucketVal) {
|
|
3217
3537
|
const engine = await getCryptoEngine();
|
|
3218
3538
|
const secret = await engine.getIndexSecret();
|
|
3219
|
-
return
|
|
3539
|
+
return crypto2__namespace.createHmac("sha256", secret).update(bucketVal).digest("hex");
|
|
3220
3540
|
}
|
|
3221
3541
|
};
|
|
3222
3542
|
}
|
|
@@ -17760,7 +18080,7 @@ var init_date_utils = __esm({
|
|
|
17760
18080
|
var randomUUID;
|
|
17761
18081
|
var init_randomUUID = __esm({
|
|
17762
18082
|
"node_modules/@smithy/uuid/dist-es/randomUUID.js"() {
|
|
17763
|
-
randomUUID =
|
|
18083
|
+
randomUUID = crypto2__namespace.default.randomUUID.bind(crypto2__namespace.default);
|
|
17764
18084
|
}
|
|
17765
18085
|
});
|
|
17766
18086
|
|
|
@@ -27480,7 +27800,7 @@ var init_getSSOTokenFilepath = __esm({
|
|
|
27480
27800
|
"node_modules/@smithy/shared-ini-file-loader/dist-es/getSSOTokenFilepath.js"() {
|
|
27481
27801
|
init_getHomeDir();
|
|
27482
27802
|
getSSOTokenFilepath = (id) => {
|
|
27483
|
-
const hasher =
|
|
27803
|
+
const hasher = crypto2.createHash("sha1");
|
|
27484
27804
|
const cacheName = hasher.update(id).digest("hex");
|
|
27485
27805
|
return path.join(getHomeDir(), ".aws", "sso", "cache", `${cacheName}.json`);
|
|
27486
27806
|
};
|
|
@@ -34145,7 +34465,7 @@ var init_dist_es46 = __esm({
|
|
|
34145
34465
|
return Promise.resolve(this.hash.digest());
|
|
34146
34466
|
}
|
|
34147
34467
|
reset() {
|
|
34148
|
-
this.hash = this.secret ?
|
|
34468
|
+
this.hash = this.secret ? crypto2.createHmac(this.algorithmIdentifier, castSourceData(this.secret)) : crypto2.createHash(this.algorithmIdentifier);
|
|
34149
34469
|
}
|
|
34150
34470
|
};
|
|
34151
34471
|
}
|
|
@@ -38380,7 +38700,7 @@ var init_LoginCredentialsFetcher = __esm({
|
|
|
38380
38700
|
getTokenFilePath() {
|
|
38381
38701
|
const directory = process.env.AWS_LOGIN_CACHE_DIRECTORY ?? path.join(os.homedir(), ".aws", "login", "cache");
|
|
38382
38702
|
const loginSessionBytes = Buffer.from(this.loginSession, "utf8");
|
|
38383
|
-
const loginSessionSha256 =
|
|
38703
|
+
const loginSessionSha256 = crypto2.createHash("sha256").update(loginSessionBytes).digest("hex");
|
|
38384
38704
|
return path.join(directory, `${loginSessionSha256}.json`);
|
|
38385
38705
|
}
|
|
38386
38706
|
derToRawSignature(derSignature) {
|
|
@@ -38425,12 +38745,12 @@ var init_LoginCredentialsFetcher = __esm({
|
|
|
38425
38745
|
async generateDpop(method = "POST", endpoint) {
|
|
38426
38746
|
const token = await this.loadToken();
|
|
38427
38747
|
try {
|
|
38428
|
-
const privateKey =
|
|
38748
|
+
const privateKey = crypto2.createPrivateKey({
|
|
38429
38749
|
key: token.dpopKey,
|
|
38430
38750
|
format: "pem",
|
|
38431
38751
|
type: "sec1"
|
|
38432
38752
|
});
|
|
38433
|
-
const publicKey =
|
|
38753
|
+
const publicKey = crypto2.createPublicKey(privateKey);
|
|
38434
38754
|
const publicDer = publicKey.export({ format: "der", type: "spki" });
|
|
38435
38755
|
let pointStart = -1;
|
|
38436
38756
|
for (let i6 = 0; i6 < publicDer.length; i6++) {
|
|
@@ -38460,7 +38780,7 @@ var init_LoginCredentialsFetcher = __esm({
|
|
|
38460
38780
|
const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
|
|
38461
38781
|
const payloadB64 = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
38462
38782
|
const message = `${headerB64}.${payloadB64}`;
|
|
38463
|
-
const asn1Signature =
|
|
38783
|
+
const asn1Signature = crypto2.sign("sha256", Buffer.from(message), privateKey);
|
|
38464
38784
|
const rawSignature = this.derToRawSignature(asn1Signature);
|
|
38465
38785
|
const signatureB64 = rawSignature.toString("base64url");
|
|
38466
38786
|
return `${message}.${signatureB64}`;
|
|
@@ -42996,9 +43316,9 @@ function _getFailStrategy() {
|
|
|
42996
43316
|
function _hashPlaintext(plaintext, secret) {
|
|
42997
43317
|
const trimmed = plaintext.trim();
|
|
42998
43318
|
if (secret) {
|
|
42999
|
-
return
|
|
43319
|
+
return crypto2__namespace.createHmac("sha256", secret).update(trimmed, "utf-8").digest("hex");
|
|
43000
43320
|
}
|
|
43001
|
-
return
|
|
43321
|
+
return crypto2__namespace.createHash("sha256").update(trimmed, "utf-8").digest("hex");
|
|
43002
43322
|
}
|
|
43003
43323
|
function getVault() {
|
|
43004
43324
|
if (_vaultInstance === null) {
|
|
@@ -43913,7 +44233,7 @@ var init_registry = __esm({
|
|
|
43913
44233
|
}
|
|
43914
44234
|
buildCatalogue(restrict) {
|
|
43915
44235
|
for (const entry of RAW_PATTERNS) {
|
|
43916
|
-
const [typeName, regexSource, terms, risk, cat, vtag, isHighEntropy, supportedLocales] = entry;
|
|
44236
|
+
const [typeName, regexSource, terms, risk, cat, vtag, isHighEntropy, supportedLocales, ruleId, complianceScope] = entry;
|
|
43917
44237
|
if (restrict !== null && !restrict.has(cat)) continue;
|
|
43918
44238
|
let re;
|
|
43919
44239
|
if (regexSource instanceof RegExp) {
|
|
@@ -43928,7 +44248,9 @@ var init_registry = __esm({
|
|
|
43928
44248
|
category: cat,
|
|
43929
44249
|
validatorTag: vtag,
|
|
43930
44250
|
isHighEntropy: isHighEntropy ?? vtag !== null,
|
|
43931
|
-
supportedLocales: supportedLocales ?? ["*"]
|
|
44251
|
+
supportedLocales: supportedLocales ?? ["*"],
|
|
44252
|
+
ruleId: ruleId ?? `MASK-${cat.slice(0, 3)}-${typeName}`,
|
|
44253
|
+
complianceScope: new Set(complianceScope ?? [])
|
|
43932
44254
|
});
|
|
43933
44255
|
}
|
|
43934
44256
|
}
|
|
@@ -59206,7 +59528,9 @@ var init_scanner = __esm({
|
|
|
59206
59528
|
originalValue: matchedStr,
|
|
59207
59529
|
confidence: conf,
|
|
59208
59530
|
method: "dlp_heuristic",
|
|
59209
|
-
language: detectedLanguage
|
|
59531
|
+
language: detectedLanguage,
|
|
59532
|
+
ruleId: descriptor.ruleId,
|
|
59533
|
+
complianceScope: descriptor.complianceScope
|
|
59210
59534
|
});
|
|
59211
59535
|
}
|
|
59212
59536
|
}
|