@logtape/redaction
Version:
Redact sensitive data from log messages
75 lines (73 loc) • 2.41 kB
JavaScript
//#region src/pattern.ts
/**
* A redaction pattern for email addresses.
* @since 0.10.0
*/
const EMAIL_ADDRESS_PATTERN = {
pattern: /[\p{L}0-9.!#$%&'*+/=?^_`{|}~-]+@[\p{L}0-9](?:[\p{L}0-9-]{0,61}[\p{L}0-9])?(?:\.[\p{L}0-9](?:[\p{L}0-9-]{0,61}[\p{L}0-9])?)+/gu,
replacement: "REDACTED@EMAIL.ADDRESS"
};
/**
* A redaction pattern for credit card numbers (including American Express).
* @since 0.10.0
*/
const CREDIT_CARD_NUMBER_PATTERN = {
pattern: /(?:\d{4}-){3}\d{4}|(?:\d{4}-){2}\d{6}/g,
replacement: "XXXX-XXXX-XXXX-XXXX"
};
/**
* A redaction pattern for U.S. Social Security numbers.
* @since 0.10.0
*/
const US_SSN_PATTERN = {
pattern: /\d{3}-\d{2}-\d{4}/g,
replacement: "XXX-XX-XXXX"
};
/**
* A redaction pattern for South Korean resident registration numbers
* (住民登錄番號).
* @since 0.10.0
*/
const KR_RRN_PATTERN = {
pattern: /\d{6}-\d{7}/g,
replacement: "XXXXXX-XXXXXXX"
};
/**
* A redaction pattern for JSON Web Tokens (JWT).
* @since 0.10.0
*/
const JWT_PATTERN = {
pattern: /eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*/g,
replacement: "[JWT REDACTED]"
};
function redactByPattern(formatter, patterns) {
for (const { pattern } of patterns) if (!pattern.global) throw new TypeError(`Pattern ${pattern} does not have the global flag set.`);
function replaceString(str) {
for (const p of patterns) str = typeof p.replacement === "string" ? str.replaceAll(p.pattern, p.replacement) : str.replaceAll(p.pattern, p.replacement);
return str;
}
function replaceObject(object) {
if (typeof object === "string") return replaceString(object);
else if (Array.isArray(object)) return object.map(replaceObject);
else if (typeof object === "object" && object !== null) {
if (Object.getPrototypeOf(object) === Object.prototype || Object.getPrototypeOf(object) === null) {
const redacted = {};
for (const key in object) redacted[key] = replaceObject(object[key]);
return redacted;
}
}
return object;
}
return (record) => {
const output = formatter(record);
if (typeof output === "string") return replaceString(output);
return output.map(replaceObject);
};
}
//#endregion
exports.CREDIT_CARD_NUMBER_PATTERN = CREDIT_CARD_NUMBER_PATTERN;
exports.EMAIL_ADDRESS_PATTERN = EMAIL_ADDRESS_PATTERN;
exports.JWT_PATTERN = JWT_PATTERN;
exports.KR_RRN_PATTERN = KR_RRN_PATTERN;
exports.US_SSN_PATTERN = US_SSN_PATTERN;
exports.redactByPattern = redactByPattern;