From 7d3139d0934576dd195d0176b3b22c9d1b266a45 Mon Sep 17 00:00:00 2001 From: Jason Williams Date: Fri, 18 Jul 2014 20:40:47 +0000 Subject: [PATCH] Check setup status when making API responses Closes #3303, Closes #3299 - Check whether or not setup has been completed when deciding how to respond to certain API requests. - Add tests. --- core/server/api/authentication.js | 47 ++++- .../api/api_authentication_spec.js | 177 ++++++++++++++++++ 2 files changed, 216 insertions(+), 8 deletions(-) create mode 100644 core/test/integration/api/api_authentication_spec.js diff --git a/core/server/api/authentication.js b/core/server/api/authentication.js index 96b6b0ff19..2a68495623 100644 --- a/core/server/api/authentication.js +++ b/core/server/api/authentication.js @@ -26,7 +26,15 @@ authentication = { var expires = Date.now() + ONE_DAY, email; - return utils.checkObject(object, 'passwordreset').then(function (checkedPasswordReset) { + return authentication.isSetup().then(function (result) { + var setup = result.setup[0].status; + + if (!setup) { + return when.reject(new errors.NoPermissionError('Setup must be completed before making this request.')); + } + + return utils.checkObject(object, 'passwordreset'); + }).then(function (checkedPasswordReset) { if (checkedPasswordReset.passwordreset[0].email) { email = checkedPasswordReset.passwordreset[0].email; } else { @@ -63,6 +71,7 @@ authentication = { if (error && error.message === 'NotFound') { error = new errors.UnauthorizedError('Invalid email address'); } + return when.reject(error); }); }); @@ -78,7 +87,16 @@ authentication = { var resetToken, newPassword, ne2Password; - return utils.checkObject(object, 'passwordreset').then(function (checkedPasswordReset) { + + return authentication.isSetup().then(function (result) { + var setup = result.setup[0].status; + + if (!setup) { + return when.reject(new errors.NoPermissionError('Setup must be completed before making this request.')); + } + + return utils.checkObject(object, 'passwordreset'); + }).then(function (checkedPasswordReset) { resetToken = checkedPasswordReset.passwordreset[0].token; newPassword = checkedPasswordReset.passwordreset[0].newPassword; ne2Password = checkedPasswordReset.passwordreset[0].ne2Password; @@ -106,7 +124,15 @@ authentication = { name, email; - return utils.checkObject(object, 'invitation').then(function (checkedInvitation) { + return authentication.isSetup().then(function (result) { + var setup = result.setup[0].status; + + if (!setup) { + return when.reject(new errors.NoPermissionError('Setup must be completed before making this request.')); + } + + return utils.checkObject(object, 'invitation'); + }).then(function (checkedInvitation) { resetToken = checkedInvitation.invitation[0].token; newPassword = checkedInvitation.invitation[0].password; ne2Password = checkedInvitation.invitation[0].password; @@ -127,7 +153,6 @@ authentication = { }, isSetup: function () { - return dataProvider.User.query(function (qb) { qb.where('status', '=', 'active') .orWhere('status', '=', 'warn-1') @@ -148,7 +173,15 @@ authentication = { setup: function (object) { var setupUser; - return utils.checkObject(object, 'setup').then(function (checkedSetupData) { + return authentication.isSetup().then(function (result) { + var setup = result.setup[0].status; + + if (setup) { + return when.reject(new errors.NoPermissionError('Setup has already been completed.')); + } + + return utils.checkObject(object, 'setup'); + }).then(function (checkedSetupData) { setupUser = { name: checkedSetupData.setup[0].name, email: checkedSetupData.setup[0].email, @@ -206,10 +239,8 @@ authentication = { }); }).then(function () { return when.resolve({ users: [setupUser]}); - }).otherwise(function (error) { - return when.reject(new errors.UnauthorizedError(error.message)); }); } }; -module.exports = authentication; \ No newline at end of file +module.exports = authentication; diff --git a/core/test/integration/api/api_authentication_spec.js b/core/test/integration/api/api_authentication_spec.js new file mode 100644 index 0000000000..97946230cc --- /dev/null +++ b/core/test/integration/api/api_authentication_spec.js @@ -0,0 +1,177 @@ +var testUtils = require('../../utils'), + should = require('should'), + when = require('when'), + rewire = require('rewire'), + mail = rewire('../../../server/api/mail'), + permissions = require('../../../server/permissions'), + settings = require('../../../server/api/settings'), + + authentication = require('../../../server/api/authentication'); + +describe('Authentication API', function () { + + before(function (done) { + testUtils.clearData().then(function () { + done(); + }).catch(done); + }); + + describe('Setup', function () { + + describe('Not completed', function () { + + beforeEach(function (done) { + testUtils.clearData().then(function () { + return testUtils.initData().then(function () { + return permissions.init().then(function () { + return settings.updateSettingsCache(); + }); + }); + }).then(function () { + done(); + }).catch(done); + }); + + it('should report that setup has not been completed', function (done) { + authentication.isSetup().then(function (result) { + should.exist(result); + result.setup[0].status.should.be.false; + + done(); + }).catch(done); + }); + + it('should allow setup to be completed', function (done) { + var setupData = { + name: 'test user', + email: 'test@example.com', + password: 'areallygoodpassword', + title: 'a test blog' + }, + + send = mail.__get__('mail.send'); + + mail.__set__('mail.send', function () { + return when.resolve(); + }); + + authentication.setup({ setup: [setupData] }).then(function (result) { + should.exist(result); + + var newUser = result.users[0]; + + newUser.id.should.equal(1); + newUser.name.should.equal(setupData.name); + newUser.email.should.equal(setupData.email); + + done(); + }).catch(done).finally(function () { + mail.__set__('mail.send', send); + }); + }); + }); + + describe('Completed', function () { + + beforeEach(function (done) { + testUtils.clearData().then(function () { + return testUtils.initData().then(function () { + return testUtils.insertDefaultFixtures().then(function () { + return permissions.init().then(function () { + return settings.updateSettingsCache(); + }); + }); + }); + }).then(function () { + done(); + }).catch(done); + }); + + it('should report that setup has been completed', function (done) { + authentication.isSetup().then(function (result) { + should.exist(result); + result.setup[0].status.should.be.true; + + done(); + }).catch(done); + }); + + it('should not allow setup to be run again', function (done) { + var setupData = { + name: 'test user', + email: 'test@example.com', + password: 'areallygoodpassword', + title: 'a test blog' + }; + + authentication.setup({ setup: [setupData] }).then(function (result) { + done(new Error('Setup was able to be run')); + }).catch(function (err) { + should.exist(err); + + err.name.should.equal('NoPermissionError'); + err.code.should.equal(403); + + done(); + }); + }); + }); + }); + + describe('Authentication', function () { + + describe('Setup not completed', function () { + + beforeEach(function (done) { + testUtils.clearData().then(function () { + return testUtils.initData().then(function () { + return permissions.init().then(function () { + return settings.updateSettingsCache(); + }); + }); + }).then(function () { + done(); + }).catch(done); + }); + + it('should not allow an invitation to be accepted', function (done) { + authentication.acceptInvitation().then(function () { + done(new Error('Invitation was allowed to be accepted')); + }).catch(function (err) { + should.exist(err); + + err.name.should.equal('NoPermissionError'); + err.code.should.equal(403); + + done(); + }); + }); + + it('should not generate a password reset token', function (done) { + authentication.generateResetToken().then(function () { + done(new Error('Reset token was generated')); + }).catch(function (err) { + should.exist(err); + + err.name.should.equal('NoPermissionError'); + err.code.should.equal(403); + + done(); + }); + }); + + it('should not allow a password reset', function (done) { + authentication.resetPassword().then(function () { + done(new Error('Password was reset')); + }).catch(function (err) { + should.exist(err); + + err.name.should.equal('NoPermissionError'); + err.code.should.equal(403); + + done(); + }); + }); + }); + }); +});