mask-privacy 4.2.0 → 4.3.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.js +25 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +25 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/core/fpe.ts +48 -23
- package/src/core/fpe_utils.ts +4 -4
- package/tests/bijective_fpe.test.ts +2 -2
- package/tests/compliance_pci.test.ts +53 -0
- package/tests/fpe.test.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -714,7 +714,7 @@ function looksLikeToken(value) {
|
|
|
714
714
|
if (v7.includes("-") && v7.length >= 6) {
|
|
715
715
|
const parts = v7.split("-");
|
|
716
716
|
const tag = parts[parts.length - 1];
|
|
717
|
-
if (tag.length
|
|
717
|
+
if (tag.length >= 3 && tag.length <= 10 && /^\d+$/.test(tag)) {
|
|
718
718
|
return true;
|
|
719
719
|
}
|
|
720
720
|
}
|
|
@@ -734,14 +734,14 @@ function isUnambiguouslySafeToken(value) {
|
|
|
734
734
|
if (/^[A-Z]{2}00[A-F0-9]{4,16}$/.test(v7)) return true;
|
|
735
735
|
if (/^<(PER|LOC|ORG):[^>]+>$/.test(v7)) return true;
|
|
736
736
|
if (v7.startsWith("[TKN-") && v7.endsWith("]")) return true;
|
|
737
|
-
if (/^[A-Z][a-zA-Z, ]+-[0-9]{3,
|
|
737
|
+
if (/^[A-Z][a-zA-Z, ]+-[0-9]{3,10}$/.test(v7)) return true;
|
|
738
738
|
return false;
|
|
739
739
|
}
|
|
740
740
|
var TOKEN_PATTERN;
|
|
741
741
|
var init_fpe_utils = __esm({
|
|
742
742
|
"src/core/fpe_utils.ts"() {
|
|
743
743
|
TOKEN_PATTERN = new RegExp(
|
|
744
|
-
"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,
|
|
744
|
+
"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,10}\\b|\\[TKN-[^\\]]+\\]",
|
|
745
745
|
// Opaque
|
|
746
746
|
"g"
|
|
747
747
|
);
|
|
@@ -790,46 +790,46 @@ async function _getBijectiveTweak() {
|
|
|
790
790
|
async function _encryptBijectiveFF1(text) {
|
|
791
791
|
const canonical = text.toLowerCase().trim();
|
|
792
792
|
const hash = cryptoNode__namespace.createHash("sha256").update(canonical, "utf-8").digest();
|
|
793
|
-
const
|
|
794
|
-
const
|
|
793
|
+
const hash128 = hash.subarray(0, 16);
|
|
794
|
+
const inputInt = hash128.readBigUInt64BE(0) << 64n | hash128.readBigUInt64BE(8);
|
|
795
|
+
const inputStr = inputInt.toString().padStart(40, "0");
|
|
795
796
|
const aesKey = await _getAesKey();
|
|
796
797
|
const tweak = await _getBijectiveTweak();
|
|
797
798
|
const engine = new FF1(aesKey, tweak, 10);
|
|
798
799
|
const cipherStr = engine.encrypt(inputStr);
|
|
799
|
-
return BigInt(cipherStr)
|
|
800
|
+
return BigInt(cipherStr);
|
|
800
801
|
}
|
|
801
802
|
function _renderBijectivePerson(bits) {
|
|
802
803
|
const firstIdx = Number(bits & 0x7FFn);
|
|
803
804
|
const connIdx = Number(bits >> 11n & 0x3Fn);
|
|
804
805
|
const rootIdx = Number(bits >> 17n & 0xFFFn);
|
|
805
806
|
const suffixIdx = Number(bits >> 29n & 0x1FFn);
|
|
806
|
-
const tag =
|
|
807
|
-
const formatIdx = Number(bits >>
|
|
807
|
+
const tag = bits >> 38n & 0xFFFFFFFFFFn;
|
|
808
|
+
const formatIdx = Number(bits >> 78n & 0xFn);
|
|
808
809
|
const first = FIRST_NAMES[firstIdx % FIRST_NAMES.length];
|
|
809
810
|
const conn = CONNECTORS[connIdx % CONNECTORS.length];
|
|
810
811
|
const root = SURNAME_ROOTS[rootIdx % SURNAME_ROOTS.length];
|
|
811
812
|
const suffix = SURNAME_SUFFIXES[suffixIdx % SURNAME_SUFFIXES.length];
|
|
812
813
|
const surname = `${root}${suffix}`;
|
|
813
|
-
const numeric = tag %
|
|
814
|
-
const paddedNumeric = numeric.toString().padStart(
|
|
814
|
+
const numeric = Number(tag % 10000000000n);
|
|
815
|
+
const paddedNumeric = numeric.toString().padStart(10, "0");
|
|
815
816
|
if (formatIdx === 0) return `${first} ${conn} ${surname}-${paddedNumeric}`;
|
|
816
817
|
if (formatIdx === 1) return `${surname}, ${first}-${paddedNumeric}`;
|
|
817
818
|
if (formatIdx === 2) return `${first[0]}. ${surname}-${paddedNumeric}`;
|
|
818
|
-
if (formatIdx === 3) return `${first} ${surname}-${paddedNumeric}`;
|
|
819
819
|
return `${first} ${surname}-${paddedNumeric}`;
|
|
820
820
|
}
|
|
821
821
|
function _renderBijectiveLocation(bits) {
|
|
822
822
|
const s1 = Number(bits & 0x3FFn);
|
|
823
823
|
const s22 = Number(bits >> 10n & 0x3FFn);
|
|
824
824
|
const s32 = Number(bits >> 20n & 0x3FFn);
|
|
825
|
-
const tag =
|
|
825
|
+
const tag = bits >> 30n & 0xFFFFFFFFFFn;
|
|
826
826
|
const city = `${SYLLABLES[s1 % 1e3]}${SYLLABLES[s22 % 1e3].toLowerCase()}${SYLLABLES[s32 % 1e3].toLowerCase()}`;
|
|
827
|
-
return `${city}-${tag.toString().padStart(
|
|
827
|
+
return `${city}-${Number(tag % 10000000000n).toString().padStart(10, "0")}`;
|
|
828
828
|
}
|
|
829
|
-
function
|
|
830
|
-
const digits =
|
|
829
|
+
function _getLuhnSum(numStr) {
|
|
830
|
+
const digits = numStr.split("").map(Number);
|
|
831
831
|
let sum = 0;
|
|
832
|
-
let shouldDouble =
|
|
832
|
+
let shouldDouble = false;
|
|
833
833
|
for (let i6 = digits.length - 1; i6 >= 0; i6--) {
|
|
834
834
|
let digit = digits[i6];
|
|
835
835
|
if (shouldDouble) {
|
|
@@ -839,7 +839,7 @@ function _computeLuhnDigit(partialNum) {
|
|
|
839
839
|
sum += digit;
|
|
840
840
|
shouldDouble = !shouldDouble;
|
|
841
841
|
}
|
|
842
|
-
return
|
|
842
|
+
return sum;
|
|
843
843
|
}
|
|
844
844
|
function _computeEsIdCheck(num) {
|
|
845
845
|
return "TRWAGMYFPDXBNJZSQVHLCKE"[num % 23];
|
|
@@ -886,14 +886,15 @@ async function generateDPToken(rawText, entityType = "UNKNOWN") {
|
|
|
886
886
|
if (type === "CREDIT_CARD" || type === "CREDIT_CARD_NUMBER") {
|
|
887
887
|
const digits = _stripCcSeparators(text);
|
|
888
888
|
if (digits.length === 16) {
|
|
889
|
-
const
|
|
890
|
-
const
|
|
891
|
-
const
|
|
889
|
+
const prefix6 = digits.slice(0, 6);
|
|
890
|
+
const suffix4 = digits.slice(12, 16);
|
|
891
|
+
const middle5 = digits.slice(6, 11);
|
|
892
892
|
const engine = new FF1(await _getAesKey(), Buffer.from("CREDIT_CARD"), 10);
|
|
893
|
-
const
|
|
894
|
-
const
|
|
895
|
-
const
|
|
896
|
-
const
|
|
893
|
+
const encMiddle5 = engine.encrypt(middle5);
|
|
894
|
+
const draft = prefix6 + encMiddle5 + "0" + suffix4;
|
|
895
|
+
const sum = _getLuhnSum(draft);
|
|
896
|
+
const correction = (10 - sum % 10) % 10;
|
|
897
|
+
const full = prefix6 + encMiddle5 + correction.toString() + suffix4;
|
|
897
898
|
return `${full.slice(0, 4)}-${full.slice(4, 8)}-${full.slice(8, 12)}-${full.slice(12, 16)}`;
|
|
898
899
|
} else {
|
|
899
900
|
const fallbackDigits = digits.padEnd(16, "0").slice(0, 16);
|