Skip to content

Commit

Permalink
fix(logger): filter out sensitive data, use serializers
Browse files Browse the repository at this point in the history
  • Loading branch information
serge1peshcoff committed May 23, 2020
1 parent 0d1adf5 commit b4dd5c5
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 50 deletions.
41 changes: 0 additions & 41 deletions lib/helpers.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,6 @@
const crypto = require('crypto');
const { Sequelize } = require('./sequelize');

// A helper to flatten the nested object. Copypasted from Google.
function flattenObject(obj, prefix = '') {
return Object.keys(obj).reduce((acc, k) => {
const pre = prefix.length ? prefix + '.' : '';
if (typeof obj[k] === 'object' && obj[k] !== null && Object.prototype.toString.call(obj[k]) !== '[object Date]') {
Object.assign(acc, flattenObject(obj[k], pre + k));
} else {
acc[pre + k] = obj[k];
}

return acc;
}, {});
}

/* eslint-disable */
function unflattenObject(data) {
const result = {};

for (const i in data) {
const keys = i.split('.');
keys.reduce((r, e, j) => {
return r[e] || (r[e] = isNaN(Number(keys[j + 1])) ? (keys.length - 1 == j ? data[i] : {}) : []);
}, result);
}
return result;
}
/* eslint-enable */

function filterFields(body, fieldsToFilter) {
const flatten = flattenObject(body);
for (const field in flatten) {
if (fieldsToFilter.some((filterField) => field === filterField)) {
flatten[field] = '[FILTERED]';
}
}

return unflattenObject(flatten);
}

// A helper to traverse indirect circles (so if a person is a member
// of a circle which is a child circle, it should return both of the circles.)
Expand Down Expand Up @@ -206,9 +168,6 @@ function getRandomBytes(length) {
}

module.exports = {
filterFields,
flattenObject,
unflattenObject,
isNumber,
traverseIndirectCircles,
getPagination,
Expand Down
48 changes: 46 additions & 2 deletions lib/logger.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,55 @@
const bunyan = require('bunyan');

const config = require('../config');
const configFile = require('../config');
const packageInfo = require('../package');

const logger = bunyan.createLogger({
name: packageInfo.name,
level: config.logger.silent ? bunyan.FATAL + 1 : config.logger.level
level: configFile.logger.silent ? bunyan.FATAL + 1 : configFile.logger.level
});

// A helper to flatten the nested object. Copypasted from Google.
function flattenObject(obj, prefix = '') {
return Object.keys(obj).reduce((acc, k) => {
const pre = prefix.length ? prefix + '.' : '';
if (typeof obj[k] === 'object' && obj[k] !== null && Object.prototype.toString.call(obj[k]) !== '[object Date]') {
Object.assign(acc, flattenObject(obj[k], pre + k));
} else {
acc[pre + k] = obj[k];
}

return acc;
}, {});
}

/* eslint-disable */
function unflattenObject(data) {
const result = {};

for (const i in data) {
const keys = i.split('.');
keys.reduce((r, e, j) => {
return r[e] || (r[e] = isNaN(Number(keys[j + 1])) ? (keys.length - 1 == j ? data[i] : {}) : []);
}, result);
}
return result;
}
/* eslint-enable */

const filterFields = (body) => {
const flatten = flattenObject(body);
for (const field in flatten) {
if (configFile.filter_fields.some((filterField) => field === filterField)) {
flatten[field] = '*'.repeat(flatten[field].length);
}
}

return unflattenObject(flatten);
};

logger.addSerializers({
body: (body) => filterFields(body),
config: (config) => filterFields(config)
});

module.exports = logger;
13 changes: 11 additions & 2 deletions lib/morgan.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
const morgan = require('morgan');
const _ = require('lodash');

const log = require('./logger');

module.exports = morgan((tokens, req, res) => {
const user = req.user
? _.pick(req.user, ['id', 'username', 'first_name', 'last_name', 'email'])
: undefined;

const body = _.isEmpty(req.body)
? undefined
: req.body;

log.info({
method: tokens.method(req, res),
url: tokens.url(req, res),
status: tokens.status(req, res),
length: tokens.res(req, res, 'content-length'),
'response-time': tokens['response-time'](req, res),
user: req.user,
body: req.body
user,
body
}, 'Request processed');
});
7 changes: 2 additions & 5 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const bodyParser = require('body-parser');
const boolParser = require('express-query-boolean');

const morgan = require('./morgan');
const helpers = require('./helpers');
const db = require('./sequelize');
const log = require('./logger');
const config = require('../config');
Expand Down Expand Up @@ -185,12 +184,10 @@ server.use(middlewares.errorHandler);
let app;
async function startServer() {
return new Promise((res, rej) => {
log.info({
config: helpers.filterFields(config, config.filter_fields)
}, 'Starting server with the following config');
log.info({ config }, 'Starting server with the following config');
const localApp = server.listen(config.port, async () => {
app = localApp;
log.info({ host: 'http://localhost: + config.port' }, 'Up and running, listening');
log.info({ host: 'http://localhost:' + config.port }, 'Up and running, listening');
await db.authenticate();
log.info('DB connection is successful.');

Expand Down

0 comments on commit b4dd5c5

Please sign in to comment.