Extract Privacy
module
Centralizes how we redact sensitive information.
This commit is contained in:
parent
0c317c5498
commit
49e0850fb2
4 changed files with 60 additions and 42 deletions
|
@ -8,10 +8,9 @@ const _ = require('lodash');
|
||||||
|
|
||||||
const debuglogs = require('./modules/debuglogs');
|
const debuglogs = require('./modules/debuglogs');
|
||||||
const Errors = require('./modules/types/errors');
|
const Errors = require('./modules/types/errors');
|
||||||
|
const Privacy = require('./modules/privacy');
|
||||||
|
|
||||||
const ipc = electron.ipcRenderer;
|
const ipc = electron.ipcRenderer;
|
||||||
const PHONE_REGEX = /\+\d{7,12}(\d{3})/g;
|
|
||||||
const GROUP_REGEX = /(group\()([^)]+)(\))/g;
|
|
||||||
|
|
||||||
// Default Bunyan levels: https://github.com/trentm/node-bunyan#levels
|
// Default Bunyan levels: https://github.com/trentm/node-bunyan#levels
|
||||||
// To make it easier to visually scan logs, we make all levels the same length
|
// To make it easier to visually scan logs, we make all levels the same length
|
||||||
|
@ -25,20 +24,7 @@ const LEVELS = {
|
||||||
10: 'trace',
|
10: 'trace',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Backwards-compatible logging, simple strings and no level (defaulted to INFO)
|
// Backwards-compatible logging, simple strings and no level (defaulted to INFO)
|
||||||
|
|
||||||
function redactPhone(text) {
|
|
||||||
return text.replace(PHONE_REGEX, '+[REDACTED]$1');
|
|
||||||
}
|
|
||||||
|
|
||||||
function redactGroup(text) {
|
|
||||||
return text.replace(
|
|
||||||
GROUP_REGEX,
|
|
||||||
(match, before, id, after) => `${before}[REDACTED]${id.slice(-3)}${after}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function now() {
|
function now() {
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
return date.toJSON();
|
return date.toJSON();
|
||||||
|
@ -61,8 +47,8 @@ function log(...args) {
|
||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
|
|
||||||
const toSend = redactAll(str.join(' '));
|
const logText = Privacy.redactAll(str.join(' '));
|
||||||
ipc.send('log-info', toSend);
|
ipc.send('log-info', logText);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.console) {
|
if (window.console) {
|
||||||
|
@ -96,11 +82,7 @@ function formatLine(entry) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function format(entries) {
|
function format(entries) {
|
||||||
return redactAll(entries.map(formatLine).join('\n')));
|
return Privacy.redactAll(entries.map(formatLine).join('\n'));
|
||||||
}
|
|
||||||
|
|
||||||
function redactAll(string) {
|
|
||||||
return Errors.redactSensitivePaths(redactGroup(redactPhone(string)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetch() {
|
function fetch() {
|
||||||
|
|
53
js/modules/privacy.js
Normal file
53
js/modules/privacy.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/* eslint-env node */
|
||||||
|
|
||||||
|
const Path = require('path');
|
||||||
|
|
||||||
|
const isString = require('lodash/isString');
|
||||||
|
const compose = require('lodash/fp/compose');
|
||||||
|
|
||||||
|
|
||||||
|
const PHONE_NUMBER_PATTERN = /\+\d{7,12}(\d{3})/g;
|
||||||
|
const GROUP_ID_PATTERN = /(group\()([^)]+)(\))/g;
|
||||||
|
|
||||||
|
const APP_ROOT_PATH = Path.join(__dirname, '..', '..', '..');
|
||||||
|
const APP_ROOT_PATH_PATTERN = new RegExp(APP_ROOT_PATH, 'g');
|
||||||
|
|
||||||
|
const REDACTION_PLACEHOLDER = '[REDACTED]';
|
||||||
|
|
||||||
|
// redactPhoneNumbers :: String -> String
|
||||||
|
exports.redactPhoneNumbers = (text) => {
|
||||||
|
if (!isString(text)) {
|
||||||
|
throw new TypeError('`text` must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.replace(PHONE_NUMBER_PATTERN, `+${REDACTION_PLACEHOLDER}$1`);
|
||||||
|
};
|
||||||
|
|
||||||
|
// redactGroupIds :: String -> String
|
||||||
|
exports.redactGroupIds = (text) => {
|
||||||
|
if (!isString(text)) {
|
||||||
|
throw new TypeError('`text` must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.replace(
|
||||||
|
GROUP_ID_PATTERN,
|
||||||
|
(match, before, id, after) =>
|
||||||
|
`${before}${REDACTION_PLACEHOLDER}${id.slice(-3)}${after}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// redactSensitivePaths :: String -> String
|
||||||
|
exports.redactSensitivePaths = (text) => {
|
||||||
|
if (!isString(text)) {
|
||||||
|
throw new TypeError('`text` must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.replace(APP_ROOT_PATH_PATTERN, REDACTION_PLACEHOLDER);
|
||||||
|
};
|
||||||
|
|
||||||
|
// redactAll :: String -> String
|
||||||
|
exports.redactAll = compose(
|
||||||
|
exports.redactSensitivePaths,
|
||||||
|
exports.redactGroupIds,
|
||||||
|
exports.redactPhoneNumbers
|
||||||
|
);
|
|
@ -1,26 +1,9 @@
|
||||||
/* eslint-env node */
|
|
||||||
|
|
||||||
const Path = require('path');
|
|
||||||
|
|
||||||
const ensureError = require('ensure-error');
|
const ensureError = require('ensure-error');
|
||||||
const isString = require('lodash/isString');
|
|
||||||
|
|
||||||
|
const Privacy = require('../privacy');
|
||||||
const APP_ROOT_PATH = Path.join(__dirname, '..', '..', '..');
|
|
||||||
const APP_ROOT_PATH_PATTERN = new RegExp(APP_ROOT_PATH, 'g');
|
|
||||||
|
|
||||||
// toLogFormat :: Error -> String
|
// toLogFormat :: Error -> String
|
||||||
exports.toLogFormat = (error) => {
|
exports.toLogFormat = (error) => {
|
||||||
const normalizedError = ensureError(error);
|
const normalizedError = ensureError(error);
|
||||||
const stackWithRedactedPaths = exports.redactSensitivePaths(normalizedError.stack);
|
return Privacy.redactAll(normalizedError.stack);
|
||||||
return stackWithRedactedPaths;
|
|
||||||
};
|
|
||||||
|
|
||||||
// redactSensitivePaths :: String -> String
|
|
||||||
exports.redactSensitivePaths = (logLine) => {
|
|
||||||
if (!isString(logLine)) {
|
|
||||||
return logLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
return logLine.replace(APP_ROOT_PATH_PATTERN, '<REDACTED_PATH>');
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,7 +27,7 @@ describe('Errors', () => {
|
||||||
);
|
);
|
||||||
assert.include(
|
assert.include(
|
||||||
formattedStack,
|
formattedStack,
|
||||||
'<REDACTED_PATH>',
|
'[REDACTED]',
|
||||||
'Formatted stack has redactions'
|
'Formatted stack has redactions'
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue