Privacy.ts: Additional safety for debug logs
Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
parent
da1777924b
commit
9c1b6ff01a
2 changed files with 132 additions and 9 deletions
|
@ -9,6 +9,110 @@ import { APP_ROOT_PATH } from '../../util/privacy';
|
||||||
Privacy.addSensitivePath('sensitive-path');
|
Privacy.addSensitivePath('sensitive-path');
|
||||||
|
|
||||||
describe('Privacy', () => {
|
describe('Privacy', () => {
|
||||||
|
describe('redactCardNumbers', () => {
|
||||||
|
it('should redact anything that looks like a credit card', () => {
|
||||||
|
const text =
|
||||||
|
'This is a log line with a card number 1234-1234-1234\n' +
|
||||||
|
'and another one 1234 1234 1234 1234 123';
|
||||||
|
|
||||||
|
const actual = Privacy.redactCardNumbers(text);
|
||||||
|
const expected =
|
||||||
|
'This is a log line with a card number [REDACTED]\n' +
|
||||||
|
'and another one [REDACTED]';
|
||||||
|
assert.equal(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redact weird credit card numbers', () => {
|
||||||
|
const text =
|
||||||
|
'12341234123\n' +
|
||||||
|
'123412341234\n' +
|
||||||
|
'1234123412341\n' +
|
||||||
|
'12341234123412\n' +
|
||||||
|
'123412341234123\n' +
|
||||||
|
'1234123412341234\n' +
|
||||||
|
'12341234123412341\n' +
|
||||||
|
'123412341234123412\n' +
|
||||||
|
'1234123412341234123\n' +
|
||||||
|
'12341234123412341234\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3-4\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3-4-1\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3-4-1-2\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3-4-1-2-3\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3-4-1-2-3-4\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3-4-1-2-3-4-1\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3-4-1-2-3-4-1-2\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3-4-1-2-3-4-1-2-3\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3-4-1-2-3-4-1-2-3-4\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4 1\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4 1 2\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4 1 2 3\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4\n' +
|
||||||
|
'1 2 3 a 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 a 2 3 4\n' +
|
||||||
|
'';
|
||||||
|
|
||||||
|
const actual = Privacy.redactCardNumbers(text);
|
||||||
|
const expected =
|
||||||
|
'12341234123\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]4\n' +
|
||||||
|
'1-2-3-4-1-2-3-4-1-2-3\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]-4\n' +
|
||||||
|
'1 2 3 4 1 2 3 4 1 2 3\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED]\n' +
|
||||||
|
'[REDACTED] 4\n' +
|
||||||
|
'1 2 3 a [REDACTED]\n' +
|
||||||
|
'[REDACTED] a 2 3 4\n' +
|
||||||
|
'';
|
||||||
|
assert.equal(actual, expected);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not redact things that are close to credit card numbers', () => {
|
||||||
|
const text = `
|
||||||
|
12--3412341234
|
||||||
|
1234123 412341234
|
||||||
|
1e23412341234
|
||||||
|
`;
|
||||||
|
|
||||||
|
const actual = Privacy.redactCardNumbers(text);
|
||||||
|
const expected = `
|
||||||
|
12--3412341234
|
||||||
|
1234123 412341234
|
||||||
|
1e23412341234
|
||||||
|
`;
|
||||||
|
assert.equal(actual, expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('redactPhoneNumbers', () => {
|
describe('redactPhoneNumbers', () => {
|
||||||
it('should redact all phone numbers', () => {
|
it('should redact all phone numbers', () => {
|
||||||
const text =
|
const text =
|
||||||
|
@ -143,6 +247,7 @@ describe('Privacy', () => {
|
||||||
'phone2 +13334445566 lorem\n' +
|
'phone2 +13334445566 lorem\n' +
|
||||||
'group2 group(abcdefghij) doloret\n' +
|
'group2 group(abcdefghij) doloret\n' +
|
||||||
'path3 sensitive-path/attachment.noindex\n' +
|
'path3 sensitive-path/attachment.noindex\n' +
|
||||||
|
'cc 1234 1234 1234 1234 and another 1234123412341234\n' +
|
||||||
'attachment://v2/ab/abcde?key=specialkey\n';
|
'attachment://v2/ab/abcde?key=specialkey\n';
|
||||||
|
|
||||||
const actual = Privacy.redactAll(text);
|
const actual = Privacy.redactAll(text);
|
||||||
|
@ -155,6 +260,7 @@ describe('Privacy', () => {
|
||||||
'phone2 +[REDACTED]566 lorem\n' +
|
'phone2 +[REDACTED]566 lorem\n' +
|
||||||
'group2 group([REDACTED]hij) doloret\n' +
|
'group2 group([REDACTED]hij) doloret\n' +
|
||||||
'path3 [REDACTED]/attachment.noindex\n' +
|
'path3 [REDACTED]/attachment.noindex\n' +
|
||||||
|
'cc [REDACTED] and another [REDACTED]\n' +
|
||||||
'attachment://v2/ab/abcde?key=[REDACTED]\n';
|
'attachment://v2/ab/abcde?key=[REDACTED]\n';
|
||||||
assert.equal(actual, expected);
|
assert.equal(actual, expected);
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,6 +24,7 @@ const CALL_LINK_ROOT_KEY_PATTERN =
|
||||||
/([A-Z]{4})-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}/gi;
|
/([A-Z]{4})-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}-[A-Z]{4}/gi;
|
||||||
const ATTACHMENT_URL_KEY_PATTERN = /(attachment:\/\/[^\s]+key=)([^\s]+)/gi;
|
const ATTACHMENT_URL_KEY_PATTERN = /(attachment:\/\/[^\s]+key=)([^\s]+)/gi;
|
||||||
const REDACTION_PLACEHOLDER = '[REDACTED]';
|
const REDACTION_PLACEHOLDER = '[REDACTED]';
|
||||||
|
const CARD_NUMBER_PATTERN = /(\d[- ]?){11,18}\d/g;
|
||||||
|
|
||||||
export type RedactFunction = (value: string) => string;
|
export type RedactFunction = (value: string) => string;
|
||||||
|
|
||||||
|
@ -110,6 +111,17 @@ export const _pathToRegExp = (filePath: string): RegExp | undefined => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Public API
|
// Public API
|
||||||
|
|
||||||
|
// As part of supporting credit card donations, we also want to include an extra safety
|
||||||
|
// layer to prevent CC #s from being logged even if a bug occurs in the payment interface.
|
||||||
|
export const redactCardNumbers = (text: string): string => {
|
||||||
|
if (!isString(text)) {
|
||||||
|
throw new TypeError("'text' must be a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.replace(CARD_NUMBER_PATTERN, '[REDACTED]');
|
||||||
|
};
|
||||||
|
|
||||||
export const redactPhoneNumbers = (text: string): string => {
|
export const redactPhoneNumbers = (text: string): string => {
|
||||||
if (!isString(text)) {
|
if (!isString(text)) {
|
||||||
throw new TypeError("'text' must be a string");
|
throw new TypeError("'text' must be a string");
|
||||||
|
@ -207,14 +219,19 @@ export const addSensitivePath = (filePath: string): void => {
|
||||||
|
|
||||||
addSensitivePath(APP_ROOT_PATH);
|
addSensitivePath(APP_ROOT_PATH);
|
||||||
|
|
||||||
export const redactAll: RedactFunction = compose(
|
export const redactAll: RedactFunction = text => {
|
||||||
(text: string) => redactSensitivePaths(text),
|
let result = text;
|
||||||
redactGroupIds,
|
|
||||||
redactPhoneNumbers,
|
result = redactAttachmentUrlKeys(result);
|
||||||
redactUuids,
|
result = redactCallLinkRoomIds(result);
|
||||||
redactCallLinkRoomIds,
|
result = redactCallLinkRootKeys(result);
|
||||||
redactCallLinkRootKeys,
|
result = redactCardNumbers(result);
|
||||||
redactAttachmentUrlKeys
|
result = redactGroupIds(result);
|
||||||
);
|
result = redactPhoneNumbers(result);
|
||||||
|
result = redactSensitivePaths(result);
|
||||||
|
result = redactUuids(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
const removeNewlines: RedactFunction = text => text.replace(/\r?\n|\r/g, '');
|
const removeNewlines: RedactFunction = text => text.replace(/\r?\n|\r/g, '');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue