core-mb 1.0.0 → 1.0.2
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/.github/workflows/node.js.yml +58 -0
- package/.nyc_output/0393f58b-d3a0-4d83-8010-334fc96e8c86.json +1 -0
- package/.nyc_output/0edf14d3-019a-4204-aae9-8d7d2491500b.json +1 -0
- package/.nyc_output/1db7cb73-4e51-46c0-96e8-3d1edd65f98c.json +1 -0
- package/.nyc_output/29ead10f-a723-4574-aeaf-5eff2ebcafac.json +1 -0
- package/.nyc_output/30473bab-10b9-4d55-8f30-42cbd631a50e.json +1 -0
- package/.nyc_output/4514ee29-1cb6-4243-abab-937ae44e87fe.json +1 -0
- package/.nyc_output/5268e9ea-7320-41e0-8dbf-37139a2b07e9.json +1 -0
- package/.nyc_output/581a75aa-21fc-470f-a998-ad9752b568ff.json +1 -0
- package/.nyc_output/6492905d-a035-44ac-b40d-84d04d64d3c2.json +1 -0
- package/.nyc_output/67ba5e3c-ca1d-4dbf-9155-6a154788cb55.json +1 -0
- package/.nyc_output/688e0703-cbfb-4f94-ac42-66472ac00a0c.json +1 -0
- package/.nyc_output/6c1e2427-a36b-407d-96d2-929a885e565d.json +1 -0
- package/.nyc_output/781a9e98-6dff-42dc-9bb2-126b65619cf3.json +1 -0
- package/.nyc_output/960ffee6-798c-4670-b1fa-39f6cebaa70b.json +1 -0
- package/.nyc_output/9661b441-490d-4793-881a-570493cf4d77.json +1 -0
- package/.nyc_output/9fe3622e-5b2a-42b2-a7ec-6f42c052afc9.json +1 -0
- package/.nyc_output/c37e92ff-6103-4b4b-be8e-2e23adc44ba1.json +1 -0
- package/.nyc_output/cfc973a7-b63b-4ed5-a568-019c4813486f.json +1 -0
- package/.nyc_output/d4490352-b4a2-45e0-beb3-a146203ce7a1.json +1 -0
- package/.nyc_output/da65eb21-2244-42c2-a24a-136a49caa10b.json +1 -0
- package/.nyc_output/e58bd293-d9b2-4a7a-bd45-b6f603743e81.json +1 -0
- package/.nyc_output/e5ef7a91-bcbd-46a0-848e-423e6aec9090.json +1 -0
- package/.nyc_output/f73cc576-f3eb-476a-bb88-9030aaaca351.json +1 -0
- package/.nyc_output/processinfo/0393f58b-d3a0-4d83-8010-334fc96e8c86.json +1 -0
- package/.nyc_output/processinfo/0edf14d3-019a-4204-aae9-8d7d2491500b.json +1 -0
- package/.nyc_output/processinfo/1db7cb73-4e51-46c0-96e8-3d1edd65f98c.json +1 -0
- package/.nyc_output/processinfo/29ead10f-a723-4574-aeaf-5eff2ebcafac.json +1 -0
- package/.nyc_output/processinfo/30473bab-10b9-4d55-8f30-42cbd631a50e.json +1 -0
- package/.nyc_output/processinfo/4514ee29-1cb6-4243-abab-937ae44e87fe.json +1 -0
- package/.nyc_output/processinfo/5268e9ea-7320-41e0-8dbf-37139a2b07e9.json +1 -0
- package/.nyc_output/processinfo/581a75aa-21fc-470f-a998-ad9752b568ff.json +1 -0
- package/.nyc_output/processinfo/6492905d-a035-44ac-b40d-84d04d64d3c2.json +1 -0
- package/.nyc_output/processinfo/67ba5e3c-ca1d-4dbf-9155-6a154788cb55.json +1 -0
- package/.nyc_output/processinfo/688e0703-cbfb-4f94-ac42-66472ac00a0c.json +1 -0
- package/.nyc_output/processinfo/6c1e2427-a36b-407d-96d2-929a885e565d.json +1 -0
- package/.nyc_output/processinfo/781a9e98-6dff-42dc-9bb2-126b65619cf3.json +1 -0
- package/.nyc_output/processinfo/960ffee6-798c-4670-b1fa-39f6cebaa70b.json +1 -0
- package/.nyc_output/processinfo/9661b441-490d-4793-881a-570493cf4d77.json +1 -0
- package/.nyc_output/processinfo/9fe3622e-5b2a-42b2-a7ec-6f42c052afc9.json +1 -0
- package/.nyc_output/processinfo/c37e92ff-6103-4b4b-be8e-2e23adc44ba1.json +1 -0
- package/.nyc_output/processinfo/cfc973a7-b63b-4ed5-a568-019c4813486f.json +1 -0
- package/.nyc_output/processinfo/d4490352-b4a2-45e0-beb3-a146203ce7a1.json +1 -0
- package/.nyc_output/processinfo/da65eb21-2244-42c2-a24a-136a49caa10b.json +1 -0
- package/.nyc_output/processinfo/e58bd293-d9b2-4a7a-bd45-b6f603743e81.json +1 -0
- package/.nyc_output/processinfo/e5ef7a91-bcbd-46a0-848e-423e6aec9090.json +1 -0
- package/.nyc_output/processinfo/f73cc576-f3eb-476a-bb88-9030aaaca351.json +1 -0
- package/.nyc_output/processinfo/index.json +1 -0
- package/README.md +12 -4
- package/__unitest__/phone.number.crypto.spec.ts +9 -9
- package/coverage/config.ts.html +178 -0
- package/coverage/index.html +31 -16
- package/coverage/lcov-report/config.ts.html +178 -0
- package/coverage/lcov-report/index.html +31 -16
- package/coverage/lcov-report/phone.number.helper.ts.html +1 -1
- package/coverage/lcov-report/security.helper.ts.html +19 -46
- package/coverage/lcov.info +58 -36
- package/coverage/phone.number.helper.ts.html +1 -1
- package/coverage/security.helper.ts.html +19 -46
- package/dist/config.d.ts +12 -0
- package/dist/config.js +24 -0
- package/dist/date.helper.d.ts +1 -0
- package/dist/date.helper.js +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/security.helper.d.ts +6 -2
- package/dist/security.helper.js +10 -14
- package/dist/validation.helper.d.ts +6 -0
- package/dist/validation.helper.js +32 -0
- package/jest.config.js +2 -1
- package/jest.setup.ts +8 -0
- package/package.json +6 -2
- package/src/config.ts +31 -0
- package/src/date.helper.ts +3 -0
- package/src/index.ts +1 -0
- package/src/security.helper.ts +9 -18
- package/src/validation.helper.ts +36 -0
- package/test-report.html +1 -1
- package/src/aes.helper.ts +0 -101
package/src/aes.helper.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import * as crypto from "crypto";
|
|
2
|
-
|
|
3
|
-
export type PhoneCipherRecord = {
|
|
4
|
-
// Base64 strings suitable for storage in text columns
|
|
5
|
-
ciphertext: string; // Encrypted phone number
|
|
6
|
-
iv: string; // Initialization Vector (nonce) for GCM (12 bytes recommended)
|
|
7
|
-
authTag: string; // Authentication tag returned by GCM (ensures integrity)
|
|
8
|
-
hmacIndex: string; // HMAC-SHA256(phoneNormalized) for search/dedup
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const aesKeyB64 = process.env.PHONE_AES_KEY;
|
|
12
|
-
const hmacKeyB64 = process.env.PHONE_HMAC_KEY;
|
|
13
|
-
|
|
14
|
-
if (!aesKeyB64 || !hmacKeyB64) {
|
|
15
|
-
throw new Error(
|
|
16
|
-
"PHONE_AES_KEY and PHONE_HMAC_KEY must be set (base64-encoded)."
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const aesKey = Buffer.from(aesKeyB64, "base64");
|
|
21
|
-
const hmacKey = Buffer.from(hmacKeyB64, "base64");
|
|
22
|
-
|
|
23
|
-
/** Normalize to a consistent representation (approx. E.164-like):
|
|
24
|
-
* - Keep leading '+' if present
|
|
25
|
-
* - Remove spaces, dashes, parentheses
|
|
26
|
-
* - Remove any non-digit characters except leading '+'
|
|
27
|
-
* - You can adapt to your locale/validation as needed
|
|
28
|
-
*/
|
|
29
|
-
function normalize(phoneRaw: string): string {
|
|
30
|
-
if (!phoneRaw) return "";
|
|
31
|
-
const trimmed = phoneRaw.trim();
|
|
32
|
-
const hasPlus = trimmed.startsWith("+");
|
|
33
|
-
const digitsOnly = trimmed.replace(/[^\d]/g, "");
|
|
34
|
-
return hasPlus ? `+${digitsOnly}` : digitsOnly; // store either "+855123..." or "0123..."
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/** Create an HMAC index for lookups without revealing the number.
|
|
38
|
-
* Store this alongside the encrypted data and index it in the DB.
|
|
39
|
-
*/
|
|
40
|
-
function hmacIndex(phoneRaw: string): string {
|
|
41
|
-
const normalized = normalize(phoneRaw);
|
|
42
|
-
const h = crypto.createHmac("sha256", hmacKey);
|
|
43
|
-
h.update(normalized, "utf8");
|
|
44
|
-
return h.digest("base64");
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Encrypt a phone number using AES-256-GCM.
|
|
48
|
-
* Returns base64-encoded ciphertext, iv and authTag suitable for storage.
|
|
49
|
-
*/
|
|
50
|
-
function encrypt(
|
|
51
|
-
phoneRaw: string
|
|
52
|
-
): Omit<PhoneCipherRecord, "hmacIndex"> & { hmacIndex: string } {
|
|
53
|
-
const normalized = normalize(phoneRaw);
|
|
54
|
-
|
|
55
|
-
// 12-byte IV is recommended for GCM
|
|
56
|
-
const iv = crypto.randomBytes(12);
|
|
57
|
-
|
|
58
|
-
const cipher = crypto.createCipheriv("aes-256-gcm", aesKey, iv);
|
|
59
|
-
|
|
60
|
-
// Optional: bind additional data (AAD), e.g., tenant ID to prevent cross-tenant swaps
|
|
61
|
-
// cipher.setAAD(Buffer.from(tenantId, 'utf8'));
|
|
62
|
-
|
|
63
|
-
const ciphertextBuf = Buffer.concat([
|
|
64
|
-
cipher.update(normalized, "utf8"),
|
|
65
|
-
cipher.final(),
|
|
66
|
-
]);
|
|
67
|
-
|
|
68
|
-
const authTag = cipher.getAuthTag();
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
ciphertext: ciphertextBuf.toString("base64"),
|
|
72
|
-
iv: iv.toString("base64"),
|
|
73
|
-
authTag: authTag.toString("base64"),
|
|
74
|
-
hmacIndex: hmacIndex(normalized),
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** Decrypt a previously stored record. Throws if tampered.
|
|
79
|
-
* Returns the normalized phone string.
|
|
80
|
-
*/
|
|
81
|
-
function decrypt(
|
|
82
|
-
record: Pick<PhoneCipherRecord, "ciphertext" | "iv" | "authTag">
|
|
83
|
-
): string {
|
|
84
|
-
const iv = Buffer.from(record.iv, "base64");
|
|
85
|
-
const authTag = Buffer.from(record.authTag, "base64");
|
|
86
|
-
const ciphertext = Buffer.from(record.ciphertext, "base64");
|
|
87
|
-
|
|
88
|
-
const decipher = crypto.createDecipheriv("aes-256-gcm", aesKey, iv);
|
|
89
|
-
|
|
90
|
-
// If you used setAAD on encrypt, you MUST set the same AAD here
|
|
91
|
-
// decipher.setAAD(Buffer.from(tenantId, 'utf8'));
|
|
92
|
-
|
|
93
|
-
decipher.setAuthTag(authTag);
|
|
94
|
-
|
|
95
|
-
const plaintext = Buffer.concat([
|
|
96
|
-
decipher.update(ciphertext),
|
|
97
|
-
decipher.final(),
|
|
98
|
-
]).toString("utf8");
|
|
99
|
-
|
|
100
|
-
return plaintext; // normalized phone
|
|
101
|
-
}
|