Redact URL encoded file paths in stack traces
This commit is contained in:
parent
f2c9ccae90
commit
b0da7d965e
2 changed files with 53 additions and 18 deletions
|
@ -7,22 +7,46 @@ const { compose } = require('lodash/fp');
|
||||||
const { escapeRegExp } = require('lodash');
|
const { escapeRegExp } = require('lodash');
|
||||||
|
|
||||||
|
|
||||||
|
const APP_ROOT_PATH = path.join(__dirname, '..', '..', '..');
|
||||||
const PHONE_NUMBER_PATTERN = /\+\d{7,12}(\d{3})/g;
|
const PHONE_NUMBER_PATTERN = /\+\d{7,12}(\d{3})/g;
|
||||||
const GROUP_ID_PATTERN = /(group\()([^)]+)(\))/g;
|
const GROUP_ID_PATTERN = /(group\()([^)]+)(\))/g;
|
||||||
|
const REDACTION_PLACEHOLDER = '[REDACTED]';
|
||||||
|
|
||||||
const APP_ROOT_PATH = path.join(__dirname, '..', '..', '..');
|
|
||||||
const APP_ROOT_PATH_PATTERN = (() => {
|
// _redactPath :: Path -> String -> String
|
||||||
|
exports._redactPath = (filePath) => {
|
||||||
|
if (!is.string(filePath)) {
|
||||||
|
throw new TypeError('"filePath" must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
const filePathPattern = exports._pathToRegExp(filePath);
|
||||||
|
|
||||||
|
return (text) => {
|
||||||
|
if (!is.string(text)) {
|
||||||
|
throw new TypeError('"text" must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is.regExp(filePathPattern)) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.replace(filePathPattern, REDACTION_PLACEHOLDER);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// _pathToRegExp :: Path -> Maybe RegExp
|
||||||
|
exports._pathToRegExp = (filePath) => {
|
||||||
try {
|
try {
|
||||||
// Safe `String::replaceAll`:
|
// Safe `String::replaceAll`:
|
||||||
// https://github.com/lodash/lodash/issues/1084#issuecomment-86698786
|
// https://github.com/lodash/lodash/issues/1084#issuecomment-86698786
|
||||||
return new RegExp(escapeRegExp(APP_ROOT_PATH), 'g');
|
const urlEncodedAppRootPath = escapeRegExp(encodeURI(filePath));
|
||||||
|
return new RegExp(`${escapeRegExp(filePath)}|${urlEncodedAppRootPath}`, 'g');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
})();
|
};
|
||||||
|
|
||||||
const REDACTION_PLACEHOLDER = '[REDACTED]';
|
|
||||||
|
|
||||||
|
// Public API
|
||||||
// redactPhoneNumbers :: String -> String
|
// redactPhoneNumbers :: String -> String
|
||||||
exports.redactPhoneNumbers = (text) => {
|
exports.redactPhoneNumbers = (text) => {
|
||||||
if (!is.string(text)) {
|
if (!is.string(text)) {
|
||||||
|
@ -46,17 +70,7 @@ exports.redactGroupIds = (text) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
// redactSensitivePaths :: String -> String
|
// redactSensitivePaths :: String -> String
|
||||||
exports.redactSensitivePaths = (text) => {
|
exports.redactSensitivePaths = exports._redactPath(APP_ROOT_PATH);
|
||||||
if (!is.string(text)) {
|
|
||||||
throw new TypeError('"text" must be a string');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is.regExp(APP_ROOT_PATH_PATTERN)) {
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
return text.replace(APP_ROOT_PATH_PATTERN, REDACTION_PLACEHOLDER);
|
|
||||||
};
|
|
||||||
|
|
||||||
// redactAll :: String -> String
|
// redactAll :: String -> String
|
||||||
exports.redactAll = compose(
|
exports.redactAll = compose(
|
||||||
|
|
|
@ -34,11 +34,12 @@ describe('Privacy', () => {
|
||||||
|
|
||||||
describe('redactAll', () => {
|
describe('redactAll', () => {
|
||||||
it('should redact all sensitive information', () => {
|
it('should redact all sensitive information', () => {
|
||||||
|
const encodedAppRootPath = APP_ROOT_PATH.replace(/ /g, '%20');
|
||||||
const text = 'This is a log line with sensitive information:\n' +
|
const text = 'This is a log line with sensitive information:\n' +
|
||||||
`path1 ${APP_ROOT_PATH}/main.js\n` +
|
`path1 ${APP_ROOT_PATH}/main.js\n` +
|
||||||
'phone1 +12223334455 ipsum\n' +
|
'phone1 +12223334455 ipsum\n' +
|
||||||
'group1 group(123456789) doloret\n' +
|
'group1 group(123456789) doloret\n' +
|
||||||
`path2 file:///${APP_ROOT_PATH}/js/background.js.` +
|
`path2 file:///${encodedAppRootPath}/js/background.js.` +
|
||||||
'phone2 +13334445566 lorem\n' +
|
'phone2 +13334445566 lorem\n' +
|
||||||
'group2 group(abcdefghij) doloret\n';
|
'group2 group(abcdefghij) doloret\n';
|
||||||
|
|
||||||
|
@ -53,4 +54,24 @@ describe('Privacy', () => {
|
||||||
assert.equal(actual, expected);
|
assert.equal(actual, expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('_redactPath', () => {
|
||||||
|
it('should redact URL-encoded paths', () => {
|
||||||
|
const testPath = '/Users/meow/Library/Application Support/Signal Beta';
|
||||||
|
const encodedTestPath = encodeURI(testPath);
|
||||||
|
const text = 'This is a log line with sensitive information:\n' +
|
||||||
|
`path1 ${testPath}/main.js\n` +
|
||||||
|
'phone1 +12223334455 ipsum\n' +
|
||||||
|
'group1 group(123456789) doloret\n' +
|
||||||
|
`path2 file:///${encodedTestPath}/js/background.js.`;
|
||||||
|
|
||||||
|
const actual = Privacy._redactPath(testPath)(text);
|
||||||
|
const expected = 'This is a log line with sensitive information:\n' +
|
||||||
|
'path1 [REDACTED]/main.js\n' +
|
||||||
|
'phone1 +12223334455 ipsum\n' +
|
||||||
|
'group1 group(123456789) doloret\n' +
|
||||||
|
'path2 file:///[REDACTED]/js/background.js.';
|
||||||
|
assert.equal(actual, expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue