From d26764b07b70ca80d80a62378d67ec0560febdb5 Mon Sep 17 00:00:00 2001 From: Esteban Ordano Date: Fri, 24 Oct 2014 14:21:34 -0300 Subject: [PATCH] Add key/value storage differentiated by email --- plugins/emailstore.js | 31 +++++++++++++++++++------------ test/test.EmailStore.js | 27 +++++++++++++++++---------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/plugins/emailstore.js b/plugins/emailstore.js index bd8212d..18bd0a8 100644 --- a/plugins/emailstore.js +++ b/plugins/emailstore.js @@ -80,11 +80,16 @@ emailPlugin.errors = { }; var NAMESPACE = 'credentials-store-'; +var SEPARATOR = '#'; var VALIDATION_NAMESPACE = 'validation-code-'; var MAP_EMAIL_TO_SECRET = 'map-email-'; var EMAIL_NAMESPACE = 'validated-email-'; var MAX_ALLOWED_STORAGE = 1024 * 100 /* no more than 100 kb */; +var makeKey = function(email, key) { + return NAMESPACE + email + SEPARATOR + key; +} + /** * Initializes the plugin * @@ -189,11 +194,12 @@ emailPlugin.savePassphrase = function(email, passphrase, callback) { /** * @param {string} email + * @param {string} key * @param {string} record * @param {Function(err)} callback */ -emailPlugin.saveEncryptedData = function(email, record, callback) { - emailPlugin.db.put(NAMESPACE + email, record, callback); +emailPlugin.saveEncryptedData = function(email, key, record, callback) { + emailPlugin.db.put(makeKey(email, key), record, callback); }; emailPlugin.createVerificationSecretAndSendEmail = function (email, callback) { @@ -233,17 +239,18 @@ emailPlugin.post = function (request, response) { }).on('end', function () { var params = querystring.parse(queryData); var email = params.email; + var key = params.key; var secret = params.secret; var record = params.record; - if (!email || !secret || !record) { + if (!email || !secret || !record || !key) { return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); } - emailPlugin.processPost(request, response, email, secret, record); + emailPlugin.processPost(request, response, email, key, secret, record); }); }; -emailPlugin.processPost = function(request, response, email, secret, record) { +emailPlugin.processPost = function(request, response, email, key, secret, record) { async.series([ /** * Try to fetch this user's email. If it exists, check the secret is the same. @@ -277,7 +284,7 @@ emailPlugin.processPost = function(request, response, email, secret, record) { * Save the encrypted private key in the storage. */ function (callback) { - emailPlugin.saveEncryptedData(email, record, function(err) { + emailPlugin.saveEncryptedData(email, key, record, function(err) { if (err) { return callback({code: 500, message: err}); } @@ -328,22 +335,21 @@ emailPlugin.createVerificationSecret = function (email, callback) { }); }; - /** * @param {string} email * @param {Function(err)} callback */ -emailPlugin.retrieveByEmail = function(email, callback) { - emailPlugin.db.get(NAMESPACE + email, callback); +emailPlugin.retrieveByEmailAndKey = function(email, key, callback) { + emailPlugin.db.get(makeKey(email, key), callback); }; -emailPlugin.retrieveDataByEmailAndPassphrase = function(email, passphrase, callback) { +emailPlugin.retrieveDataByEmailAndPassphrase = function(email, key, passphrase, callback) { emailPlugin.checkPassphrase(email, passphrase, function(err, matches) { if (err) { return callback(err); } if (matches) { - return emailPlugin.retrieveByEmail(email, callback); + return emailPlugin.retrieveByEmailAndKey(email, key, callback); } else { return callback(emailPlugin.errors.INVALID_CODE); } @@ -361,12 +367,13 @@ emailPlugin.retrieveDataByEmailAndPassphrase = function(email, passphrase, callb */ emailPlugin.get = function (request, response) { var email = request.param('email'); + var key = request.param('key'); var secret = request.param('secret'); if (!secret) { return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); } - emailPlugin.retrieveDataByEmailAndPassphrase(email, secret, function (err, value) { + emailPlugin.retrieveDataByEmailAndPassphrase(email, key, secret, function (err, value) { if (err) { if (err.notFound) { return emailPlugin.returnError(emailPlugin.errors.NOT_FOUND, response); diff --git a/test/test.EmailStore.js b/test/test.EmailStore.js index 850c0d9..7f78e60 100644 --- a/test/test.EmailStore.js +++ b/test/test.EmailStore.js @@ -9,7 +9,7 @@ var chai = require('chai'), logger.transports.console.level = 'warn'; -describe('emailstore test', function() { +describe.only('emailstore test', function() { var globalConfig = require('../config/config'); @@ -52,9 +52,11 @@ describe('emailstore test', function() { var emailParam = 'email'; var secretParam = 'secret'; + var keyParam = 'key'; var recordParam = 'record'; beforeEach(function() { - var data = 'email=' + emailParam + '&secret=' + secretParam + '&record=' + recordParam; + var data = ('email=' + emailParam + '&secret=' + secretParam + + '&record=' + recordParam + '&key=' + keyParam); request.on.onFirstCall().callsArgWith(1, data); request.on.onFirstCall().returnsThis(); request.on.onSecondCall().callsArg(1); @@ -67,7 +69,7 @@ describe('emailstore test', function() { plugin.savePassphrase = sinon.stub(); plugin.savePassphrase.onFirstCall().callsArg(2); plugin.saveEncryptedData = sinon.stub(); - plugin.saveEncryptedData.onFirstCall().callsArg(2); + plugin.saveEncryptedData.onFirstCall().callsArg(3); plugin.createVerificationSecretAndSendEmail = sinon.stub(); plugin.createVerificationSecretAndSendEmail.onFirstCall().callsArg(1); response.send.onFirstCall().returnsThis(); @@ -78,7 +80,8 @@ describe('emailstore test', function() { assert(plugin.savePassphrase.firstCall.args[0] === emailParam); assert(plugin.savePassphrase.firstCall.args[1] === secretParam); assert(plugin.saveEncryptedData.firstCall.args[0] === emailParam); - assert(plugin.saveEncryptedData.firstCall.args[1] === recordParam); + assert(plugin.saveEncryptedData.firstCall.args[1] === keyParam); + assert(plugin.saveEncryptedData.firstCall.args[2] === recordParam); assert(plugin.createVerificationSecretAndSendEmail.firstCall.args[0] === emailParam); }); @@ -88,7 +91,7 @@ describe('emailstore test', function() { plugin.checkPassphrase = sinon.stub(); plugin.checkPassphrase.onFirstCall().callsArgWith(2, null, true); plugin.saveEncryptedData = sinon.stub(); - plugin.saveEncryptedData.onFirstCall().callsArg(2); + plugin.saveEncryptedData.onFirstCall().callsArg(3); plugin.createVerificationSecretAndSendEmail = sinon.stub(); plugin.createVerificationSecretAndSendEmail.onFirstCall().callsArg(1); response.send.onFirstCall().returnsThis(); @@ -99,7 +102,8 @@ describe('emailstore test', function() { assert(plugin.checkPassphrase.firstCall.args[0] === emailParam); assert(plugin.checkPassphrase.firstCall.args[1] === secretParam); assert(plugin.saveEncryptedData.firstCall.args[0] === emailParam); - assert(plugin.saveEncryptedData.firstCall.args[1] === recordParam); + assert(plugin.saveEncryptedData.firstCall.args[1] === keyParam); + assert(plugin.saveEncryptedData.firstCall.args[2] === recordParam); assert(plugin.createVerificationSecretAndSendEmail.firstCall.args[0] === emailParam); }); }); @@ -144,17 +148,20 @@ describe('emailstore test', function() { it('should validate the secret and return the data', function() { request.param.onFirstCall().returns('email'); - request.param.onSecondCall().returns('secret'); + request.param.onSecondCall().returns('key'); + request.param.onThirdCall().returns('secret'); plugin.retrieveDataByEmailAndPassphrase = sinon.stub(); - plugin.retrieveDataByEmailAndPassphrase.onFirstCall().callsArgWith(2, null, 'encrypted'); + plugin.retrieveDataByEmailAndPassphrase.onFirstCall().callsArgWith(3, null, 'encrypted'); response.send.onFirstCall().returnsThis(); plugin.get(request, response); assert(request.param.firstCall.args[0] === 'email'); - assert(request.param.secondCall.args[0] === 'secret'); + assert(request.param.secondCall.args[0] === 'key'); + assert(request.param.thirdCall.args[0] === 'secret'); assert(plugin.retrieveDataByEmailAndPassphrase.firstCall.args[0] === 'email'); - assert(plugin.retrieveDataByEmailAndPassphrase.firstCall.args[1] === 'secret'); + assert(plugin.retrieveDataByEmailAndPassphrase.firstCall.args[1] === 'key'); + assert(plugin.retrieveDataByEmailAndPassphrase.firstCall.args[2] === 'secret'); assert(response.send.firstCall.args[0] === 'encrypted'); assert(response.end.calledOnce); });