Skip to content

Commit

Permalink
fix(privacy): don't log email addresses and password hashes (#239)
Browse files Browse the repository at this point in the history
What does this PR do / solve?
-----------------------------

A user kindly reported that in order to better protect privacy of user-identifiable data in case of data leak, we should prevent the logging of email addresses and md5 hashes.

Overview of changes
-------------------

- update `request.logToConsole()` to scramble/anonymise values of `email` and `md5` fields
- call the same method in appropriate places where user data is logged
- remove a useless log that contains user data

How to test this PR?
--------------------

1. run the server locally with `docker-compose up`
2. open http://localhost:8080/login in a browser
3. type an email address and password (even fake)
4. the value of your email address and md5 should not be disclosed in the stdout logs of `docker-compose up`:

```
=== Sun, 27 Oct 2019 11:21:10 GMT POST /login (login.handleRequest) {"action":"login","email":"a*********@gmail.com","md5":"<MD5_HASH>"}
fetching user  { email: 'a*********@gmail.com' } ...
```
  • Loading branch information
adrienjoly committed Oct 27, 2019
1 parent 8485ba1 commit aa187e0
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 32 deletions.
9 changes: 3 additions & 6 deletions app/controllers/api/login.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
/**
* login controller
* authentify users, with IE support
* @author adrienjoly, whyd
* login controller, to authenticate users
*/
var config = require('../../models/config.js');
var emailModel = require('../../models/email.js');
Expand Down Expand Up @@ -91,7 +89,6 @@ exports.handleRequest = function(request, form, response, ignorePassword) {
}
});
} else if (form.email) {
console.log('email=', form.email);
form.email = emailModel.normalize(form.email);

userModel[form.email.indexOf('@') > -1 ? 'fetchByEmail' : 'fetchByHandle'](
Expand All @@ -118,11 +115,11 @@ exports.handleRequest = function(request, form, response, ignorePassword) {
userModel.update(dbUser._id, {
$set: {
fbId: form.fbUid,
fbTok: form.fbTok // accesstoken provided on last facebook login
fbTok: form.fbTok // access token provided on last facebook login
}
});
renderRedirect(form.redirect || '/', dbUser);
return; // prevent default reponse (renderForm)
return; // prevent default response (renderForm)
} else if (form.action != 'logout') {
form.wrongPassword = 1;
form.error = 'Your password seems wrong... Try again!';
Expand Down
3 changes: 2 additions & 1 deletion app/models/emailSendgrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
**/

var https = require('https');
var snip = require('./../snip.js');
//var email = require("emailjs/email");

var querystring = require('querystring');
Expand All @@ -30,7 +31,7 @@ exports.email = function(
userName,
callback
) {
console.log('email', emailAddr, subject);
console.log('email', snip.formatEmail(emailAddr), subject);
/*
var message = email.message.create({
text: textContent,
Expand Down
52 changes: 30 additions & 22 deletions app/models/logging.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
var http = require('http');
var querystring = require('querystring');
var errorTemplate = require('../templates/error.js');
const snip = require('../snip.js');

const genReqLogLine = ({ head, method, path, params, suffix }) =>
!process.appParams.color
? [
head,
method,
path[0] + (path.length > 1 ? '?' + path.slice(1).join('?') : ''),
suffix,
params
]
: [
head.grey,
method.cyan,
path[0].green +
(path.length > 1 ? '?' + path.slice(1).join('?') : '').yellow,
suffix.white,
params.grey
];

http.IncomingMessage.prototype.logToConsole = function(suffix, params) {
var head = '=== ' + new Date().toUTCString(),
path = this.url.split('?'); /*[0]*/
params = params ? JSON.stringify(params) : '';
suffix = suffix ? '(' + suffix + ')' : '';
// output with colors
console.log(
head.grey,
this.method.cyan,
path[0].green +
(path.length > 1 ? '?' + path.slice(1).join('?') : '').yellow,
suffix.white,
params.grey
); // -> stdout
...genReqLogLine({
head: '=== ' + new Date().toUTCString(),
method: this.method,
path: this.url.split('?'),
params:
typeof params === 'object'
? JSON.stringify(snip.formatPrivateFields(params))
: '',
suffix: suffix ? '(' + suffix + ')' : ''
})
);
};

if (!process.appParams.color)
http.IncomingMessage.prototype.logToConsole = function(suffix, params) {
var head = '=== ' + new Date().toUTCString(),
path = this.url; /*.split("?")[0]*/
params = params ? JSON.stringify(params) : '';
suffix = suffix ? '(' + suffix + ')' : '';
// output without colors
console.log(head, this.method, path, suffix, params);
};

var config = require('./config.js');
var mongodb = require('./mongodb.js');
var loggingTemplate = require('../templates/logging.js');
Expand Down
2 changes: 1 addition & 1 deletion app/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ function processUsers(list) {
}

function fetch(q, handler) {
console.log('fetching user ', q, '...');
snip.console.log('fetching user ', q, '...');
if (q._id && typeof q._id == 'string') q._id = ObjectId(q._id);
mongodb.collections['user'].findOne(q, function(err, user) {
if (user) {
Expand Down
27 changes: 27 additions & 0 deletions app/snip.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,33 @@ var querystring = require('querystring');

var firstWeek = new Date('Monday January 3, 2011 08:00'); // week #1 = 1st of january 2010

// privacy helper: anonymise email address
exports.formatEmail = function(emailAddr) {
if (typeof emailAddr !== 'string' || emailAddr.length < 1)
return '<invalid_email>';
const [name, domain] = emailAddr.split('@');
return name
.substring(0, 1)
.concat('*********@')
.concat(domain);
};

exports.formatPrivateFields = obj => {
if (typeof obj !== 'object') return obj;
const res = { ...obj };
if (typeof obj.email === 'string') res.email = exports.formatEmail(obj.email);
if (typeof obj.md5 === 'string') res.md5 = '<MD5_HASH>';
return res;
};

// privacy-enforcing console.log helper
exports.console = {
log(...args) {
const filteredArgs = args.map(exports.formatPrivateFields);
console.log(...filteredArgs);
}
};

exports.getWeekNumber = function(date) {
return date && Math.floor(1 + (date - firstWeek) / 1000 / 60 / 60 / 24 / 7);
};
Expand Down
4 changes: 2 additions & 2 deletions docs/INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ Docker makes it easy and safe to install and start the two servers required for
1. Install [Docker Client](https://www.docker.com/community-edition) and start it
2. [Install Git](https://www.atlassian.com/git/tutorials/install-git) if you don't have it already
3. Clone openwhyd's repository: `git clone https://github.com/openwhyd/openwhyd.git`, then `cd openwhyd`
4. Build and launch Docker processes: `docker-compose up`
4. Build and launch Docker processes: `docker-compose up --build`
5. Open [http://localhost:8080](http://localhost:8080) in your web browser => you should see Openwhyd's home page! 🎉
6. When you're done, shutdown the Docker processes by pressing the `Ctrl-C` key combination in the shell instance where you had run `docker-compose up` (step 4).

Whenever you want to update your local clone of Openwhyd's repository to the latest version, run `git pull` from the `openwhyd` folder where you had cloned the repository (step 3).

Whenever you want to start the Docker processes after shutting them down (step 7), run `docker-compose up` again from the `openwhyd` folder where you had cloned the repository (step 3).
Whenever you want to start the Docker processes after shutting them down (step 7), run `docker-compose up --build` again from the `openwhyd` folder where you had cloned the repository (step 3).

Whenever you just want to restart Openwhyd while the Docker processes are still running, run `docker-compose restart web` from a shell terminal.

Expand Down

0 comments on commit aa187e0

Please sign in to comment.