From 446ec49590eb5aa0cfa7936adbd2b2bbe2936e31 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Thu, 13 Nov 2014 11:39:17 -0300 Subject: [PATCH] refactor: authorize request --- plugins/emailstore.js | 204 ++++++++++++++++++++++------------------ test/test.EmailStore.js | 109 +++++++++++++++++---- 2 files changed, 205 insertions(+), 108 deletions(-) diff --git a/plugins/emailstore.js b/plugins/emailstore.js index b3d5db2..154ee3a 100644 --- a/plugins/emailstore.js +++ b/plugins/emailstore.js @@ -302,19 +302,6 @@ }); }; - emailPlugin.retrieveDataByEmailAndPassphrase = function(email, key, passphrase, callback) { - emailPlugin.checkPassphrase(email, passphrase, function(err, matches) { - if (err) { - return callback(err); - } - if (matches) { - return emailPlugin.retrieveByEmailAndKey(email, key, callback); - } else { - return callback(emailPlugin.errors.INVALID_CODE); - } - }); - }; - emailPlugin.deleteByEmailAndKey = function deleteByEmailAndKey(email, key, callback) { emailPlugin.db.del(valueKey(email, key), function(error) { if (error) { @@ -339,6 +326,7 @@ }; }; async.parallel([ + function(callback) { emailPlugin.db.del(emailToPassphrase(email), dismissNotFound(callback)); }, @@ -500,87 +488,111 @@ }); }; - function authorizedRequest(withKey, callback) { - return function(request, response) { - var credentialsResult = emailPlugin.getCredentialsFromRequest(request); - if (_.contains(emailPlugin.errors, credentialsResult)) { - return emailPlugin.returnError(credentialsResult, response); - } - var email = credentialsResult.email; - var passphrase = credentialsResult.passphrase; - var key; - if (withKey) { - key = request.param('key'); + emailPlugin.authorizeRequest = function(request, withKey, callback) { + var credentialsResult = emailPlugin.getCredentialsFromRequest(request); + if (_.contains(emailPlugin.errors, credentialsResult)) { + return callback(credentialsResult); + } + + var email = credentialsResult.email; + var passphrase = credentialsResult.passphrase; + var key; + if (withKey) { + key = request.param('key'); + } + + if (!passphrase || !email || (withKey && !key)) { + return callback(emailPlugin.errors.MISSING_PARAMETER); + } + + emailPlugin.checkPassphrase(email, passphrase, function(err, matches) { + if (err) { + return callback(err); } - if (!passphrase || !email || (withKey && !key)) { - return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); + if (!matches) { + return callback(emailPlugin.errors.INVALID_CODE); } - return callback(email, passphrase, key, request, response); - }; - } + + return callback(null, email, key); + }); + }; + + emailPlugin.authorizeRequestWithoutKey = function(request, callback) { + emailPlugin.authorizeRequest(request, false, callback); + }; + + emailPlugin.authorizeRequestWithKey = function(request, callback) { + emailPlugin.authorizeRequest(request, true, callback); + }; /** * Retrieve a record from the database */ - emailPlugin.retrieve = authorizedRequest(true, - function(email, passphrase, key, request, response) { - emailPlugin.retrieveDataByEmailAndPassphrase(email, key, passphrase, function(err, value) { + emailPlugin.retrieve = function(request, response) { + emailPlugin.authorizeRequestWithKey(request, function(err, email, key) { + if (err) { + return emailPlugin.returnError(err, response); + } + + emailPlugin.retrieveByEmailAndKey(email, key, function(err, value) { if (err) { return emailPlugin.returnError(err, response); } + emailPlugin.addValidationHeader(response, email, function(err) { if (err) { return emailPlugin.returnError(err, response); } + response.send(value).end(); }); }); - } - ); + }); + }; /** * Remove a record from the database */ - emailPlugin.erase = authorizedRequest(true, - function(email, passphrase, key, request, response) { - emailPlugin.checkPassphrase(email, passphrase, function(err, matches) { - if (err || !matches) { - return emailPlugin.returnError(emailPlugin.errors.INVALID_CODE, response); - } - emailPlugin.deleteByEmailAndKey(email, key, function(err, value) { - if (err) { - return emailPlugin.returnError(err, response); - } else { - return response.json({success: true}).end(); - }; - }); + emailPlugin.erase = function(request, response) { + emailPlugin.authorizeRequestWithKey(request, function(err, email, key) { + if (err) { + return emailPlugin.returnError(err, response); + } + emailPlugin.deleteByEmailAndKey(email, key, function(err, value) { + if (err) { + return emailPlugin.returnError(err, response); + } else { + return response.json({ + success: true + }).end(); + }; }); - } - ); + }); + }; /** * Remove a whole profile from the database * * @TODO: This looks very similar to the method above */ - emailPlugin.eraseProfile = authorizedRequest(false, - function(email, passphrase, unused_key, request, response) { - - emailPlugin.checkPassphrase(email, passphrase, function(err, matches) { - if (err || !matches) { - return emailPlugin.returnError(emailPlugin.errors.INVALID_CODE, response); - } - emailPlugin.deleteWholeProfile(email, function(err, value) { - if (err) { - return emailPlugin.returnError(err, response); - } else { - return response.json({success: true}).end(); - }; - }); + emailPlugin.eraseProfile = function(request, response) { + emailPlugin.authorizeRequestWithoutKey(request, function(err, email) { + if (err) { + return emailPlugin.returnError(err, response); + } + + emailPlugin.deleteWholeProfile(email, function(err, value) { + if (err) { + return emailPlugin.returnError(err, response); + } else { + return response.json({ + success: true + }).end(); + }; }); - } - ); + }); + }; /** @@ -642,32 +654,28 @@ * @param {Express.Response} response */ emailPlugin.changePassphrase = function(request, response) { - var credentialsResult = emailPlugin.getCredentialsFromRequest(request); - if (_.contains(emailPlugin.errors, credentialsResult)) { - return emailPlugin.returnError(credentialsResult); - } - var email = credentialsResult.email; - var passphrase = credentialsResult.passphrase; - var queryData = ''; - request.on('data', function(data) { - queryData += data; - if (queryData.length > MAX_ALLOWED_STORAGE) { - queryData = ''; - response.writeHead(413, { - 'Content-Type': 'text/plain' - }).end(); - request.connection.destroy(); + emailPlugin.authorizeRequestWithoutKey(request, function(err, email) { + + if (err) { + return emailPlugin.returnError(err, response); } - }).on('end', function() { - var params = querystring.parse(queryData); - var newPassphrase = params.newPassphrase; - if (!email || !passphrase || !newPassphrase) { - return emailPlugin.returnError(emailPlugin.errors.INVALID_REQUEST, response); - } - emailPlugin.checkPassphrase(email, passphrase, function(error) { - if (error) { - return emailPlugin.returnError(error, response); + + var queryData = ''; + request.on('data', function(data) { + queryData += data; + if (queryData.length > MAX_ALLOWED_STORAGE) { + queryData = ''; + response.writeHead(413, { + 'Content-Type': 'text/plain' + }).end(); + request.connection.destroy(); + } + }).on('end', function() { + var params = querystring.parse(queryData); + var newPassphrase = params.newPassphrase; + if (!newPassphrase) { + return emailPlugin.returnError(emailPlugin.errors.INVALID_REQUEST, response); } emailPlugin.savePassphrase(email, newPassphrase, function(error) { if (error) { @@ -682,7 +690,23 @@ }; + // // Backwards compatibility + // + + emailPlugin.oldRetrieveDataByEmailAndPassphrase = function(email, key, passphrase, callback) { + emailPlugin.checkPassphrase(email, passphrase, function(err, matches) { + if (err) { + return callback(err); + } + if (matches) { + return emailPlugin.retrieveByEmailAndKey(email, key, callback); + } else { + return callback(emailPlugin.errors.INVALID_CODE); + } + }); + }; + emailPlugin.oldRetrieve = function(request, response) { var email = request.param('email'); @@ -692,7 +716,7 @@ return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); } - emailPlugin.retrieveDataByEmailAndPassphrase(email, key, secret, function(err, value) { + emailPlugin.oldRetrieveDataByEmailAndPassphrase(email, key, secret, function(err, value) { if (err) { return emailPlugin.returnError(err, response); } diff --git a/test/test.EmailStore.js b/test/test.EmailStore.js index 4281ba7..ffe2229 100644 --- a/test/test.EmailStore.js +++ b/test/test.EmailStore.js @@ -433,39 +433,115 @@ describe('emailstore test', function() { describe('when retrieving data', function() { it('should validate the secret and return the data', function() { - request.header = sinon.stub(); - request.header.onFirstCall().returns(new Buffer('email:pass', 'utf8').toString('base64')); request.param.onFirstCall().returns('key'); - plugin.retrieveDataByEmailAndPassphrase = sinon.stub(); - plugin.retrieveDataByEmailAndPassphrase.onFirstCall().callsArgWith(3, null, 'encrypted'); + plugin.authorizeRequestWithKey = sinon.stub().callsArgWith(1,null, 'email','key'); + plugin.retrieveByEmailAndKey = sinon.stub().yields(null, 'encrypted'); + response.send.onFirstCall().returnsThis(); plugin.addValidationHeader = sinon.stub().callsArg(2); plugin.retrieve(request, response); - request.header.calledOnce.should.equal(true); response.send.calledOnce.should.equal(true); - assert(request.header.firstCall.args[0] === 'authorization'); - assert(plugin.retrieveDataByEmailAndPassphrase.firstCall.args[0] === 'email'); - assert(plugin.retrieveDataByEmailAndPassphrase.firstCall.args[1] === 'key'); - assert(plugin.retrieveDataByEmailAndPassphrase.firstCall.args[2] === 'pass'); + assert(plugin.retrieveByEmailAndKey.firstCall.args[0] === 'email'); + assert(plugin.retrieveByEmailAndKey.firstCall.args[1] === 'key'); assert(response.send.firstCall.args[0] === 'encrypted'); assert(response.end.calledOnce); }); }); - describe('changing the user password', function() { - - var originalCredentials = plugin.getCredentialsFromRequest; + describe('authorizing requests', function() { + var originalCredentials; beforeEach(function() { + originalCredentials = plugin.getCredentialsFromRequest; + plugin.getCredentialsFromRequest = sinon.mock(); plugin.getCredentialsFromRequest.onFirstCall().returns({ email: 'email', - passphrase: 'passphrase' + passphrase: 'pass' }); + request.param.onFirstCall().returns('key'); + + request.on = sinon.stub(); + request.on.onFirstCall().callsArgWith(1, 'newPassphrase=newPassphrase'); + request.on.onFirstCall().returns(request); + request.on.onSecondCall().callsArg(1); + plugin.checkPassphrase = sinon.stub().callsArgWith(2,null, true); + + }); + + it('should authorize a request', function(done){ + plugin.authorizeRequest(request, false, function(err, email, key) { + expect(err).to.be.null; + expect(key).to.be.undefined; + email.should.be.equal('email'); + done(); + }); + }); + it('should authorize a request with key', function(done){ + plugin.getCredentialsFromRequest.onFirstCall().returns({ + email: 'email', + passphrase: 'pass', + }); + plugin.authorizeRequest(request, true, function(err, email, key) { + expect(err).to.be.null; + email.should.be.equal('email'); + key.should.be.equal('key'); + done(); + }); + }); + + it('should not authorize a request when param are missing', function(done){ + plugin.getCredentialsFromRequest.onFirstCall().returns({ + email: 'email', + }); + + plugin.authorizeRequest(request, false, function(err, email, key) { + expect(err).not.to.be.null; + expect(key).to.be.undefined; + expect(email).to.be.undefined; + done(); + }); + }); + it('should not authorize a request when param are missing (case2)', function(done){ + plugin.getCredentialsFromRequest.onFirstCall().returns({ + passphrase: 'pass' + }); + + plugin.authorizeRequest(request, false, function(err, email, key) { + expect(err).not.to.be.null; + expect(key).to.be.undefined; + expect(email).to.be.undefined; + done(); + }); + }); + it('should not authorize a request when param are missing (case3)', function(done){ + request.param.onFirstCall().returns(undefined); + plugin.getCredentialsFromRequest.onFirstCall().returns({ + email: 'email', + passphrase: 'pass' + }); + plugin.authorizeRequest(request, true, function(err, email, key) { + expect(err).not.to.be.null; + expect(key).to.be.undefined; + expect(email).to.be.undefined; + done(); + }); + }); + + + after(function() { + plugin.getCredentialsFromRequest = originalCredentials; + }); + }); + + describe('changing the user password', function() { + + + beforeEach(function() { request.on = sinon.stub(); request.on.onFirstCall().callsArgWith(1, 'newPassphrase=newPassphrase'); request.on.onFirstCall().returns(request); @@ -478,7 +554,7 @@ describe('emailstore test', function() { it('should validate the previous passphrase', function() { response.status.onFirstCall().returnsThis(); response.json.onFirstCall().returnsThis(); - plugin.checkPassphrase.onFirstCall().callsArgWith(2, 'error'); + plugin.authorizeRequestWithoutKey = sinon.stub().callsArgWith(1,'error'); plugin.changePassphrase(request, response); @@ -489,6 +565,7 @@ describe('emailstore test', function() { it('should change the passphrase', function() { response.json.onFirstCall().returnsThis(); + plugin.authorizeRequestWithoutKey = sinon.stub().callsArgWith(1,null, 'email'); plugin.checkPassphrase.onFirstCall().callsArgWith(2, null); plugin.savePassphrase.onFirstCall().callsArgWith(2, null); @@ -496,9 +573,5 @@ describe('emailstore test', function() { assert(response.json.calledOnce); assert(response.end.calledOnce); }); - - after(function() { - plugin.getCredentialsFromRequest = originalCredentials; - }); }); });