Skip to content

Commit 272a1c6

Browse files
Jiaming Youmeta-codesync[bot]
authored andcommitted
Added PIIUtil.test.js
Summary: Added PIIUtil.test.js Differential Revision: D83921165 fbshipit-source-id: 88930f584d426b4cec836ce99a388fc82483d712
1 parent a976332 commit 272a1c6

3 files changed

Lines changed: 1335 additions & 0 deletions

File tree

nodejs/capi-param-builder/src/piiUtil/PIIUtil.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const { getNormalizedPhone } = require('./phoneUtil');
1212
const { getNormalizedDOB } = require('./dobUtil');
1313
const { getNormalizedGender } = require('./genderUtil');
1414
const { getNormalizedZipCode } = require('./zipCodeUtil');
15+
const { sha256_main } = require('./sha256_with_dependencies_new');
1516
const {
1617
getNormalizedName,
1718
getNormalizedCity,
@@ -20,6 +21,22 @@ const {
2021
getNormalizedExternalID
2122
} = require('./stringUtil');
2223

24+
const SHA_256_OR_MD5_REGEX = /^[A-Fa-f0-9]{64}$|^[A-Fa-f0-9]{32}$/;
25+
26+
function getNormalizedAndHashedPII(piiValue, dataType) {
27+
if (!piiValue || typeof piiValue !== 'string') {
28+
return null;
29+
}
30+
31+
if (SHA_256_OR_MD5_REGEX.test(piiValue)) {
32+
return piiValue.toLowerCase();
33+
} else {
34+
let x = sha256_main(getNormalizedPII(piiValue, dataType));
35+
console.log(x);
36+
return x;
37+
}
38+
}
39+
2340
function getNormalizedPII(piiValue, dataType) {
2441
if (
2542
!piiValue ||
@@ -61,4 +78,5 @@ function getNormalizedPII(piiValue, dataType) {
6178

6279
module.exports = {
6380
getNormalizedPII,
81+
getNormalizedAndHashedPII
6482
};
Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
/**
2+
* @lint-ignore-every LICENSELINT
3+
* @preserve-header
4+
*
5+
* Copyright (c) 2003, Christoph Bichlmeier
6+
* All rights reserved.
7+
*
8+
* Redistribution and use in source and binary forms, with or without
9+
* modification, are permitted provided that the following conditions
10+
* are met:
11+
* 1. Redistributions of source code must retain the above copyright
12+
* notice, this list of conditions and the following disclaimer.
13+
* 2. Redistributions in binary form must reproduce the above copyright
14+
* notice, this list of conditions and the following disclaimer in the
15+
* documentation and/or other materials provided with the distribution.
16+
* 3. Neither the name of the copyright holder nor the names of contributors
17+
* may be used to endorse or promote products derived from this software
18+
* without specific prior written permission.
19+
*
20+
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
21+
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
24+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27+
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29+
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30+
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
*
32+
*
33+
* str2rstr_utf8 is taken from:
34+
* "A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
35+
* Digest Algorithm, as defined in RFC 1321."
36+
* Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
37+
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
38+
* Distributed under the BSD License
39+
*
40+
* @flow strict
41+
* @format
42+
*/
43+
44+
/* eslint-disable id-length, no-magic-numbers, no-bitwise */
45+
46+
// Convert UTF-16 (this includes UTF-32 == pairs of UTF-16 chars)
47+
// into UTF-8. This must be done to get the right hash!
48+
'use strict';
49+
50+
// $FlowFixMe[missing-local-annot]
51+
function str2rstr(input) {
52+
let output = '';
53+
let x;
54+
let y;
55+
56+
for (let i = 0; i < input.length; i++) {
57+
/* Decode utf-16 surrogate pairs */
58+
x = input.charCodeAt(i);
59+
y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
60+
if (x >= 0xd800 && x <= 0xdbff && y >= 0xdc00 && y <= 0xdfff) {
61+
x = 0x10000 + ((x & 0x03ff) << 10) + (y & 0x03ff);
62+
i++;
63+
}
64+
65+
/* Encode output as utf-8 */
66+
if (x <= 0x7f) {
67+
output += String.fromCharCode(x);
68+
} else if (x <= 0x7ff) {
69+
output += String.fromCharCode(
70+
0xc0 | ((x >>> 6) & 0x1f),
71+
0x80 | (x & 0x3f)
72+
);
73+
} else if (x <= 0xffff) {
74+
output += String.fromCharCode(
75+
0xe0 | ((x >>> 12) & 0x0f),
76+
0x80 | ((x >>> 6) & 0x3f),
77+
0x80 | (x & 0x3f)
78+
);
79+
} else if (x <= 0x1fffff) {
80+
output += String.fromCharCode(
81+
0xf0 | ((x >>> 18) & 0x07),
82+
0x80 | ((x >>> 12) & 0x3f),
83+
0x80 | ((x >>> 6) & 0x3f),
84+
0x80 | (x & 0x3f)
85+
);
86+
}
87+
}
88+
89+
return output;
90+
}
91+
92+
/**
93+
* sha256
94+
*/
95+
96+
// $FlowFixMe[missing-local-annot]
97+
function rotateRight(n, x) {
98+
return (x >>> n) | (x << (32 - n));
99+
}
100+
101+
// $FlowFixMe[missing-local-annot]
102+
function choice(x, y, z) {
103+
return (x & y) ^ (~x & z);
104+
}
105+
106+
// $FlowFixMe[missing-local-annot]
107+
function majority(x, y, z) {
108+
return (x & y) ^ (x & z) ^ (y & z);
109+
}
110+
111+
// $FlowFixMe[missing-local-annot]
112+
function sha256_Sigma0(x) {
113+
return rotateRight(2, x) ^ rotateRight(13, x) ^ rotateRight(22, x);
114+
}
115+
116+
// $FlowFixMe[missing-local-annot]
117+
function sha256_Sigma1(x) {
118+
return rotateRight(6, x) ^ rotateRight(11, x) ^ rotateRight(25, x);
119+
}
120+
121+
// $FlowFixMe[missing-local-annot]
122+
function sha256_sigma0(x) {
123+
return rotateRight(7, x) ^ rotateRight(18, x) ^ (x >>> 3);
124+
}
125+
126+
// $FlowFixMe[missing-local-annot]
127+
function sha256_sigma1(x) {
128+
return rotateRight(17, x) ^ rotateRight(19, x) ^ (x >>> 10);
129+
}
130+
131+
// $FlowFixMe[missing-local-annot]
132+
function sha256_expand(W, j) {
133+
return (W[j & 0x0f] +=
134+
sha256_sigma1(W[(j + 14) & 0x0f]) +
135+
W[(j + 9) & 0x0f] +
136+
sha256_sigma0(W[(j + 1) & 0x0f]));
137+
}
138+
139+
const K256 = [
140+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
141+
0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
142+
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
143+
0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
144+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
145+
0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
146+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
147+
0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
148+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
149+
0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
150+
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
151+
];
152+
153+
// $FlowFixMe[underconstrained-implicit-instantiation]
154+
const ihash = new Array(8);
155+
// $FlowFixMe[underconstrained-implicit-instantiation]
156+
const count = new Array(2);
157+
// $FlowFixMe[underconstrained-implicit-instantiation]
158+
const buffer = new Array(64);
159+
// $FlowFixMe[underconstrained-implicit-instantiation]
160+
const W = new Array(16);
161+
const sha256_hex_digits = '0123456789abcdef';
162+
163+
// Add 32-bit integers with 16-bit operations (bug in some JS-interpreters:
164+
// overflow)
165+
// $FlowFixMe[missing-local-annot]
166+
function safe_add(x, y) {
167+
const lsw = (x & 0xffff) + (y & 0xffff);
168+
const msw = (x >> 16) + (y >> 16) + (lsw >> 16);
169+
return (msw << 16) | (lsw & 0xffff);
170+
}
171+
172+
// Initialise the SHA256 computation
173+
function sha256_init() {
174+
count[0] = count[1] = 0;
175+
ihash[0] = 0x6a09e667;
176+
ihash[1] = 0xbb67ae85;
177+
ihash[2] = 0x3c6ef372;
178+
ihash[3] = 0xa54ff53a;
179+
ihash[4] = 0x510e527f;
180+
ihash[5] = 0x9b05688c;
181+
ihash[6] = 0x1f83d9ab;
182+
ihash[7] = 0x5be0cd19;
183+
}
184+
185+
// Transform a 512-bit message block
186+
function sha256_transform() {
187+
let T1, T2, a, b, c, d, e, f, g, h;
188+
189+
// Initialize registers with the previous intermediate value
190+
[a, b, c, d, e, f, g, h] = ihash;
191+
192+
// make 32-bit words
193+
for (let i = 0; i < 16; i++) {
194+
W[i] =
195+
buffer[(i << 2) + 3] |
196+
(buffer[(i << 2) + 2] << 8) |
197+
(buffer[(i << 2) + 1] << 16) |
198+
(buffer[i << 2] << 24);
199+
}
200+
for (let j = 0; j < 64; j++) {
201+
T1 = h + sha256_Sigma1(e) + choice(e, f, g) + K256[j];
202+
if (j < 16) {
203+
T1 += W[j];
204+
} else {
205+
T1 += sha256_expand(W, j);
206+
}
207+
T2 = sha256_Sigma0(a) + majority(a, b, c);
208+
h = g;
209+
g = f;
210+
f = e;
211+
e = safe_add(d, T1);
212+
d = c;
213+
c = b;
214+
b = a;
215+
a = safe_add(T1, T2);
216+
}
217+
218+
// Compute the current intermediate hash value
219+
ihash[0] += a;
220+
ihash[1] += b;
221+
ihash[2] += c;
222+
ihash[3] += d;
223+
ihash[4] += e;
224+
ihash[5] += f;
225+
ihash[6] += g;
226+
ihash[7] += h;
227+
}
228+
229+
// Read the next chunk of data and update the SHA256 computation
230+
// $FlowFixMe[missing-local-annot]
231+
function sha256_update(data, inputLen) {
232+
let i;
233+
let index;
234+
let curpos = 0;
235+
236+
// Compute number of bytes mod 64
237+
index = (count[0] >> 3) & 0x3f;
238+
const remainder = inputLen & 0x3f;
239+
240+
// Update number of bits
241+
if ((count[0] += inputLen << 3) < inputLen << 3) {
242+
count[1]++;
243+
}
244+
count[1] += inputLen >> 29;
245+
246+
// Transform as many times as possible
247+
for (i = 0; i + 63 < inputLen; i += 64) {
248+
for (let j = index; j < 64; j++) {
249+
buffer[j] = data.charCodeAt(curpos++);
250+
}
251+
sha256_transform();
252+
index = 0;
253+
}
254+
255+
// Buffer remaining input
256+
for (let j = 0; j < remainder; j++) {
257+
buffer[j] = data.charCodeAt(curpos++);
258+
}
259+
}
260+
261+
// Finish the computation by operations such as padding
262+
function sha256_final() {
263+
let index = (count[0] >> 3) & 0x3f;
264+
buffer[index++] = 0x80;
265+
if (index <= 56) {
266+
for (let i = index; i < 56; i++) {
267+
buffer[i] = 0;
268+
}
269+
} else {
270+
for (let i = index; i < 64; i++) {
271+
buffer[i] = 0;
272+
}
273+
sha256_transform();
274+
for (let i = 0; i < 56; i++) {
275+
buffer[i] = 0;
276+
}
277+
}
278+
buffer[56] = (count[1] >>> 24) & 0xff;
279+
buffer[57] = (count[1] >>> 16) & 0xff;
280+
buffer[58] = (count[1] >>> 8) & 0xff;
281+
buffer[59] = count[1] & 0xff;
282+
buffer[60] = (count[0] >>> 24) & 0xff;
283+
buffer[61] = (count[0] >>> 16) & 0xff;
284+
buffer[62] = (count[0] >>> 8) & 0xff;
285+
buffer[63] = count[0] & 0xff;
286+
sha256_transform();
287+
}
288+
289+
// Get the internal hash as a hex string
290+
function sha256_encode_hex() {
291+
let output = '';
292+
for (let i = 0; i < 8; i++) {
293+
for (let j = 28; j >= 0; j -= 4) {
294+
output += sha256_hex_digits.charAt((ihash[i] >>> j) & 0x0f);
295+
}
296+
}
297+
return output;
298+
}
299+
300+
// $FlowFixMe[missing-local-annot]
301+
function sha256_encode_hex_buffer(localBuffer) {
302+
let index = 0;
303+
for (let i = 0; i < 8; i++) {
304+
for (let j = 28; j >= 0; j -= 4) {
305+
localBuffer[index++] = sha256_hex_digits.charCodeAt(
306+
(ihash[i] >>> j) & 0x0f
307+
);
308+
}
309+
}
310+
}
311+
312+
// Returns a hex string representing the SHA256 value of the given data
313+
// $FlowFixMe[missing-local-annot]
314+
function sha256_digest(data, localBuffer) {
315+
sha256_init();
316+
sha256_update(data, data.length);
317+
sha256_final();
318+
if (localBuffer) {
319+
sha256_encode_hex_buffer(localBuffer);
320+
} else {
321+
return sha256_encode_hex();
322+
}
323+
}
324+
325+
/**
326+
* Generates SHA-256 hash of string
327+
*
328+
* @param {String} msg String to be hashed
329+
* @param {Boolean} [utf8encode=true] Encode msg as UTF-8 before generating hash
330+
* @returns {String} Hash of msg as hex character string
331+
*/
332+
function sha256_main(msg, utf8encode = true, localBuffer) {
333+
if (msg === null || msg === undefined) {
334+
return null;
335+
}
336+
337+
let toProcess = msg;
338+
if (utf8encode) {
339+
toProcess = str2rstr(msg);
340+
}
341+
342+
return sha256_digest(toProcess, localBuffer);
343+
}
344+
345+
/*eslint-enable */
346+
347+
module.exports = { sha256_main };

0 commit comments

Comments
 (0)