diff --git a/src/test/common.js b/src/test/common.js index 1e88be3e9..dd6d2db0f 100644 --- a/src/test/common.js +++ b/src/test/common.js @@ -6,7 +6,9 @@ const appdb = require('../appdb.js'), blobs = require('../blobs.js'), constants = require('../constants.js'), database = require('../database.js'), + delay = require('delay'), domains = require('../domains.js'), + expect = require('expect.js'), fs = require('fs'), mail = require('../mail.js'), mailboxdb = require('../mailboxdb.js'), @@ -116,6 +118,8 @@ exports = module.exports = { domainSetup, setup, cleanup, + checkMails, + clearMailQueue, mockApiServerOrigin: 'http://localhost:6060', DASHBOARD_DOMAIN: 'test.example.com', @@ -201,3 +205,12 @@ function cleanup(done) { ], done); } +function clearMailQueue() { + mailer._mailQueue = []; +} + +async function checkMails(number) { + await delay(1000); + expect(mailer._mailQueue.length).to.equal(number); + clearMailQueue(); +} diff --git a/src/test/users-test.js b/src/test/users-test.js index d197642de..de72a793e 100644 --- a/src/test/users-test.js +++ b/src/test/users-test.js @@ -15,7 +15,7 @@ const BoxError = require('../boxerror.js'), _ = require('underscore'); describe('User', function () { - const { domainSetup, cleanup, admin, user, auditSource } = common; + const { domainSetup, cleanup, admin, user, auditSource, checkMails, clearMailQueue } = common; async function cleanupUsers() { for (const u of await users.getAll()) { @@ -171,8 +171,8 @@ describe('User', function () { it('can get by resetToken', async function () { user.resetToken = new Array(64).fill('X').join(''); await users.update(user, { resetToken: user.resetToken }, auditSource); - const user = await users.getByResetToken(user.resetToken); - checkUser(user, user); + const result = await users.getByResetToken(user.resetToken); + checkUser(result, user); }); it('can getAll', async function () { @@ -213,22 +213,22 @@ describe('User', function () { expect(error.reason).to.equal(BoxError.BAD_FIELD); }); - xit('cannot update the user with already existing email', async function () { + it('cannot update the user with already existing email', async function () { const result = await users.add(user.email, user, auditSource); user.id = result; - const [error] = await safe(users.update(admin, { email: user.email }), auditSource); + const [error] = await safe(users.update(admin, { email: user.email }, auditSource)); expect(error.reason).to.be(BoxError.ALREADY_EXISTS); expect(error.message).to.equal('email already exists'); }); - xit('can update the user with already existing username', async function () { - const [error] = await safe(users.update(admin, { username: user.username }), auditSource); + it('can update the user with already existing username', async function () { + const [error] = await safe(users.update(admin, { username: user.username }, auditSource)); expect(error.reason).to.be(BoxError.ALREADY_EXISTS); expect(error.message).to.equal('username already exists'); }); - xit('can update the user', async function () { + it('can update the user', async function () { await users.update(admin, { email: 'some@thing.com', displayName: 'Heiter' }, auditSource); const user = await users.get(admin.id); expect(user.email).to.equal('some@thing.com'); @@ -488,13 +488,13 @@ describe('User', function () { expect(error.reason).to.equal(BoxError.INVALID_CREDENTIALS); }); - xit('actually changed the password (login with new password)', async function () { + it('actually changed the password (login with new password)', async function () { await users.verify(admin.id, 'ThisIsNew1Password', users.AP_WEBADMIN); }); }); describe('sendPasswordResetByIdentifier', function () { - before(cleanupUsers); + before(createOwner); it('fails due to unkown email', async function () { const [error] = await safe(users.sendPasswordResetByIdentifier('unknown@mail.com', auditSource)); @@ -507,13 +507,15 @@ describe('User', function () { }); it('succeeds with email', async function () { - await users.sendPasswordResetByIdentifier(admin.email); - // checkMails(1, done); + await clearMailQueue(); + await users.sendPasswordResetByIdentifier(admin.email, auditSource); + await checkMails(1); }); it('succeeds with username', async function () { - await users.sendPasswordResetByIdentifier(admin.username); - // checkMails(1, done); + await clearMailQueue(); + await users.sendPasswordResetByIdentifier(admin.username, auditSource); + await checkMails(1); }); }); @@ -525,19 +527,16 @@ describe('User', function () { expect(error.reason).to.be(BoxError.CONFLICT); }); - it('can create token', function (done) { - users.createInvite(userObject, function (error, resetToken) { - expect(error).to.be(null); - expect(resetToken).to.be.ok(); - done(); - }); + it('can create token', async function () { + const { resetToken, inviteLink } = await users.createInvite(admin, auditSource); + expect(resetToken).to.be.ok(); + expect(inviteLink).to.be.ok(); }); - it('send invite', function (done) { - users.sendInvite(userObject, { }, function (error) { - expect(error).to.be(null); - checkMails(1, done); - }); + it('send invite', async function () { + await clearMailQueue(); + await users.sendInvite(admin, {}); + await checkMails(1); }); }); diff --git a/src/users.js b/src/users.js index b1afdcbad..0310bb0f2 100644 --- a/src/users.js +++ b/src/users.js @@ -91,6 +91,7 @@ const CRYPTO_KEY_LENGTH = 512; // bits const CRYPTO_DIGEST = 'sha1'; // used to be the default in node 4.1.1 cannot change since it will affect existing db records const pbkdf2Async = util.promisify(crypto.pbkdf2); +const randomBytesAsync = util.promisify(crypto.randomBytes); const getDirectoryConfigAsync = util.promisify(settings.getDirectoryConfig); function postProcess(result) { @@ -203,10 +204,9 @@ async function add(email, data, auditSource) { error = validateRole(role); if (error) throw error; - const randomBytes = util.promisify(crypto.randomBytes); let salt, derivedKey; - [error, salt] = await safe(randomBytes(CRYPTO_SALT_SIZE)); + [error, salt] = await safe(randomBytesAsync(CRYPTO_SALT_SIZE)); if (error) throw new BoxError(BoxError.CRYPTO_ERROR, error); [error, derivedKey] = await safe(pbkdf2Async(password, salt, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST)); @@ -611,13 +611,14 @@ async function setPassword(user, newPassword, auditSource) { if (settings.isDemo() && user.username === constants.DEMO_USERNAME) throw new BoxError(BoxError.BAD_FIELD, 'Not allowed in demo mode'); if (user.source) throw new BoxError(BoxError.CONFLICT, 'User is from an external directory'); - const saltBuffer = Buffer.from(user.salt, 'hex'); + let salt, derivedKey; + [error, salt] = await safe(randomBytesAsync(CRYPTO_SALT_SIZE)); - let derivedKey; - [error, derivedKey] = await safe(pbkdf2Async(newPassword, saltBuffer, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST)); + [error, derivedKey] = await safe(pbkdf2Async(newPassword, salt, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST)); if (error) throw new BoxError(BoxError.CRYPTO_ERROR, error); const data = { + salt: salt.toString('hex'), password: Buffer.from(derivedKey, 'binary').toString('hex'), resetToken: '' };