Skip to content

Instantly share code, notes, and snippets.

@iOnline247
Last active August 31, 2024 02:48
Show Gist options
  • Save iOnline247/45ea7b2ff328ca797d6fab9f8cbed843 to your computer and use it in GitHub Desktop.
Save iOnline247/45ea7b2ff328ca797d6fab9f8cbed843 to your computer and use it in GitHub Desktop.
Data masking perf for objects that are logged.
const WARMUP_LOOPS = 100000;
//#region Utils
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string
}
function createUserObj() {
return {
id: 123,
email: "user@example.com",
password: "secret",
here: {
email: "nope-topLevel",
ssn: "123-45-6789",
},
nestedObj: {
here: {
email: "nope-nested",
ssn: "123-45-6789",
},
},
arrOfObjs: [
{
email: "nope1",
ssn: "111-11-1111",
},
{
email: "nope2",
ssn: "222-22-2222",
},
],
};
}
const sanitizedFields = ["email", "password", "ssn"];
function dataMasker(mask = "*".repeat(8), sensitiveFields = sanitizedFields) {
return function createProxyObject(obj) {
return new Proxy(obj, {
get(target, prop) {
if (sensitiveFields.includes(prop)) {
return mask;
}
const value = target[prop];
if (value && typeof value === "object") {
return createProxyObject(value);
}
return value;
},
});
};
}
class User {
address;
id;
password;
ssn;
constructor(id, address, password, ssn) {
this.address = address;
this.id = id;
this.password = password;
this.ssn = ssn;
}
}
//#endregion Utils
const maskSensitiveObject = dataMasker();
function proxyObjMasking(shouldLog = false) {
const user = maskSensitiveObject(createUserObj());
user.id **= 2;
const resultObj = JSON.stringify(user);
if (shouldLog) {
console.log("proxyObjMasking\n");
console.log(resultObj);
console.log("");
}
}
function knownObjMasking(shouldLog) {
const user = createUserObj();
user.id **= 2;
user.email = "*".repeat(8);
user.password = "*".repeat(8);
user.here.email = "*".repeat(8);
user.here.ssn = "*".repeat(8);
user.nestedObj.here.email = "*".repeat(8);
user.nestedObj.here.ssn = "*".repeat(8);
user.arrOfObjs[0].email = "*".repeat(8);
user.arrOfObjs[0].ssn = "*".repeat(8);
user.arrOfObjs[1].email = "*".repeat(8);
user.arrOfObjs[1].ssn = "*".repeat(8);
const resultObj = JSON.stringify(user);
if (shouldLog) {
console.log("knownObjMasking\n");
console.log(resultObj);
}
}
function regexObjMasking(shouldLog) {
const user = createUserObj();
user.id **= 2;
let resultJson = JSON.stringify(user);
for (const field of sanitizedFields) {
resultJson = resultJson.replace(
new RegExp(`"(${escapeRegExp(field)})":"[^"]+"`, "g"),
`$1:"${"*".repeat(8)}"`,
);
}
if (shouldLog) {
console.log("regexObjMasking\n");
console.log(resultJson);
}
}
function classObjMasking(shouldLog) {
const user = maskSensitiveObject(
new User(123, "sensitive-but-not-masked", "password", "123-45-6789"),
);
user.id **= 2;
const resultJson = JSON.stringify(user);
if (shouldLog) {
console.log("classObjMasking\n");
console.log(resultJson);
}
}
for (let i = 0; i < WARMUP_LOOPS; i++) {
proxyObjMasking();
knownObjMasking();
regexObjMasking();
classObjMasking();
}
//#region Start Tests
//#region ProxyObjMasking
console.log(`\n${"*".repeat(25)}`);
const startProxyObjMasking = process.hrtime();
proxyObjMasking(true);
const endProxyObjMasking = process.hrtime(startProxyObjMasking);
console.log(
`\n\nExecution time: ${endProxyObjMasking[0]} seconds and ${endProxyObjMasking[1] / 1e6} milliseconds`,
);
console.log(`\n${"*".repeat(25)}\n`);
//#endregion ProxyObjMasking
//#region Regex Parsing
console.log(`\n${"*".repeat(25)}`);
const startRegexObjMasking = process.hrtime();
regexObjMasking(true);
const endRegexObjMasking = process.hrtime(startRegexObjMasking);
console.log(
`\n\nExecution time: ${endRegexObjMasking[0]} seconds and ${endRegexObjMasking[1] / 1e6} milliseconds`,
);
console.log(`\n${"*".repeat(25)}\n`);
//#endregion Regex Parsing
//#region JSON Parsing
console.log(`\n${"*".repeat(25)}`);
const startKnownObjMasking = process.hrtime();
knownObjMasking(true);
const endKnownObjMasking = process.hrtime(startKnownObjMasking);
console.log(
`\n\nExecution time: ${endKnownObjMasking[0]} seconds and ${endKnownObjMasking[1] / 1e6} milliseconds`,
);
console.log(`\n${"*".repeat(25)}\n`);
//#endregion JSON Parsing
//#region ClassObjMasking
console.log(`\n${"*".repeat(25)}`);
const startClassObjMasking = process.hrtime();
classObjMasking(true);
const endClassObjMasking = process.hrtime(startClassObjMasking);
console.log(
`\n\nExecution time: ${endClassObjMasking[0]} seconds and ${endClassObjMasking[1] / 1e6} milliseconds`,
);
console.log(`\n${"*".repeat(25)}\n`);
//#endregion ClassObjMasking
//#endregion Start Tests
//#region Overwritten Proxy Property
console.log(`${"*".repeat(25)}\n`);
const user = maskSensitiveObject(createUserObj());
user.here = { email: "nope", nestedObj: {} };
user.here.nestedObj.email = "nope";
user.here.nestedObj.password = "password";
user.arrOfObjs.push({
email: "nope",
password: "remove-me",
nestedObj: { ssn: "do-not-log" },
});
console.log(`Overwritten Proxy Property\n\n${JSON.stringify(user)}`);
console.log(`\n${"*".repeat(25)}\n`);
console.log(`${"*".repeat(25)}\n`);
const emptyObj = maskSensitiveObject(Object.create(null));
emptyObj.email = "nope";
emptyObj.password = "";
emptyObj.here = { email: "nope", nestedObj: {} };
emptyObj.arrOfObjs = [{ nestedObj: { password: "nope", ssn: "remove" } }];
emptyObj.arrOfObjs.push({
email: "nope",
password: "",
nestedObj: { ssn: "do-not-log" },
});
console.log(`No Prototype Object\n\n${JSON.stringify(emptyObj)}`);
console.log(`\n${"*".repeat(25)}\n`);
//#endregion Overwritten Proxy Property
//#region Obtain sensitive values from object
const rawValues = Object.getOwnPropertyDescriptors(emptyObj);
console.log(JSON.stringify(rawValues));
//#endregion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment