diff --git a/js/modules/types/errors.js b/js/modules/types/errors.js new file mode 100644 index 000000000..7754bb15c --- /dev/null +++ b/js/modules/types/errors.js @@ -0,0 +1,17 @@ +/* eslint-env node */ + +const Path = require('path'); + +const toError = require('ensure-error'); + + +const APP_ROOT_PATH = Path.join(__dirname, '..', '..', '..'); +const APP_ROOT_PATH_PATTERN = new RegExp(APP_ROOT_PATH, 'g'); + +// toLogFormat :: Error -> String +exports.toLogFormat = (error) => { + const normalizedError = toError(error); + const stackWithoutPrivatePaths = + normalizedError.stack.replace(APP_ROOT_PATH_PATTERN, ''); + return stackWithoutPrivatePaths; +}; diff --git a/test/modules/types/errors_test.js b/test/modules/types/errors_test.js new file mode 100644 index 000000000..74a9f4e51 --- /dev/null +++ b/test/modules/types/errors_test.js @@ -0,0 +1,39 @@ +const Path = require('path'); + +const { assert } = require('chai'); + +const Errors = require('../../../js/modules/types/errors'); + + +const APP_ROOT_PATH = Path.join(__dirname, '..', '..', '..'); + +describe('Errors', () => { + describe('toLogFormat', () => { + it('should redact sensitive paths in stack trace', () => { + try { + throw new Error('boom'); + } catch (error) { + assert.include( + error.stack, + APP_ROOT_PATH, + 'Unformatted stack has sensitive paths' + ); + + const formattedStack = Errors.toLogFormat(error); + assert.notInclude( + formattedStack, + APP_ROOT_PATH, + 'Formatted stack does not have sensitive paths' + ); + assert.include( + formattedStack, + '', + 'Formatted stack has redactions' + ); + return; + } + // eslint-disable-next-line no-unreachable + assert.fail('Expected error to be thrown.'); + }); + }); +});