diff --git a/src/boxerror.js b/src/boxerror.js index c52de2ea1..991dd582f 100644 --- a/src/boxerror.js +++ b/src/boxerror.js @@ -38,6 +38,7 @@ BoxError.BAD_STATE = 'Bad State'; BoxError.BUSY = 'Busy'; BoxError.COLLECTD_ERROR = 'Collectd Error'; BoxError.CONFLICT = 'Conflict'; +BoxError.CRYPTO_ERROR = 'Crypto Error'; BoxError.DATABASE_ERROR = 'Database Error'; BoxError.DNS_ERROR = 'DNS Error'; BoxError.DOCKER_ERROR = 'Docker Error'; diff --git a/src/ldap.js b/src/ldap.js index 085b379df..7269c1dc3 100644 --- a/src/ldap.js +++ b/src/ldap.js @@ -18,8 +18,7 @@ var assert = require('assert'), mailboxdb = require('./mailboxdb.js'), path = require('path'), safe = require('safetydance'), - users = require('./users.js'), - UsersError = users.UsersError; + users = require('./users.js'); var gServer = null; @@ -420,8 +419,8 @@ function authenticateUser(req, res, next) { } api(commonName, req.credentials || '', function (error, user) { - if (error && error.reason === UsersError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString())); - if (error && error.reason === UsersError.WRONG_PASSWORD) return next(new ldap.InvalidCredentialsError(req.dn.toString())); + if (error && error.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString())); + if (error && error.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString())); if (error) return next(new ldap.OperationsError(error.message)); req.user = user; @@ -466,8 +465,8 @@ function authenticateUserMailbox(req, res, next) { if (error) return next(new ldap.OperationsError(error.message)); users.verify(mailbox.ownerId, req.credentials || '', function (error, result) { - if (error && error.reason === UsersError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString())); - if (error && error.reason === UsersError.WRONG_PASSWORD) return next(new ldap.InvalidCredentialsError(req.dn.toString())); + if (error && error.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString())); + if (error && error.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString())); if (error) return next(new ldap.OperationsError(error.message)); eventlog.add(eventlog.ACTION_USER_LOGIN, { authType: 'ldap', mailboxId: email }, { userId: result.id, user: users.removePrivateFields(result) }); @@ -577,8 +576,8 @@ function authenticateMailAddon(req, res, next) { if (error) return next(new ldap.OperationsError(error.message)); users.verify(mailbox.ownerId, req.credentials || '', function (error, result) { - if (error && error.reason === UsersError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString())); - if (error && error.reason === UsersError.WRONG_PASSWORD) return next(new ldap.InvalidCredentialsError(req.dn.toString())); + if (error && error.reason === BoxError.NOT_FOUND) return next(new ldap.NoSuchObjectError(req.dn.toString())); + if (error && error.reason === BoxError.INVALID_CREDENTIALS) return next(new ldap.InvalidCredentialsError(req.dn.toString())); if (error) return next(new ldap.OperationsError(error.message)); eventlog.add(eventlog.ACTION_USER_LOGIN, { authType: 'ldap', mailboxId: email }, { userId: result.id, user: users.removePrivateFields(result) }); diff --git a/src/routes/accesscontrol.js b/src/routes/accesscontrol.js index 940a83523..655d70bd5 100644 --- a/src/routes/accesscontrol.js +++ b/src/routes/accesscontrol.js @@ -18,8 +18,7 @@ var accesscontrol = require('../accesscontrol.js'), HttpError = require('connect-lastmile').HttpError, LocalStrategy = require('passport-local').Strategy, passport = require('passport'), - users = require('../users.js'), - UsersError = users.UsersError; + users = require('../users.js'); function initialize(callback) { assert.strictEqual(typeof callback, 'function'); @@ -42,16 +41,16 @@ function initialize(callback) { passport.use(new LocalStrategy(function (username, password, callback) { if (username.indexOf('@') === -1) { users.verifyWithUsername(username, password, function (error, result) { - if (error && error.reason === UsersError.NOT_FOUND) return callback(null, false); - if (error && error.reason === UsersError.WRONG_PASSWORD) return callback(null, false); + if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false); + if (error && error.reason === BoxError.INVALID_CREDENTIALS) return callback(null, false); if (error) return callback(error); if (!result) return callback(null, false); callback(null, result); }); } else { users.verifyWithEmail(username, password, function (error, result) { - if (error && error.reason === UsersError.NOT_FOUND) return callback(null, false); - if (error && error.reason === UsersError.WRONG_PASSWORD) return callback(null, false); + if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false); + if (error && error.reason === BoxError.INVALID_CREDENTIALS) return callback(null, false); if (error) return callback(error); if (!result) return callback(null, false); callback(null, result); diff --git a/src/routes/profile.js b/src/routes/profile.js index 00ab1ea3e..26bad9585 100644 --- a/src/routes/profile.js +++ b/src/routes/profile.js @@ -11,12 +11,30 @@ exports = module.exports = { var assert = require('assert'), auditSource = require('../auditsource.js'), + BoxError = require('../boxerror.js'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess, users = require('../users.js'), - UsersError = users.UsersError, _ = require('underscore'); +function toHttpError(error) { + switch (error.reason) { + case BoxError.NOT_FOUND: + return new HttpError(404, error); + case BoxError.ALREADY_EXISTS: + return new HttpError(409, error); + case BoxError.BAD_FIELD: + return new HttpError(400, error); + case BoxError.EXTERNAL_ERROR: + return new HttpError(424, error); + case BoxError.INVALID_CREDENTIALS: + return new HttpError(412, error); + case BoxError.INTERNAL_ERROR: + default: + return new HttpError(500, error); + } +} + function get(req, res, next) { assert.strictEqual(typeof req.user, 'object'); @@ -43,10 +61,7 @@ function update(req, res, next) { var data = _.pick(req.body, 'email', 'fallbackEmail', 'displayName'); users.update(req.user.id, data, auditSource.fromRequest(req), function (error) { - if (error && error.reason === UsersError.BAD_FIELD) return next(new HttpError(400, error.message)); - if (error && error.reason === UsersError.ALREADY_EXISTS) return next(new HttpError(409, error.message)); - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'User not found')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(204)); }); @@ -59,9 +74,7 @@ function changePassword(req, res, next) { if (typeof req.body.newPassword !== 'string') return next(new HttpError(400, 'newPassword must be a string')); users.setPassword(req.user.id, req.body.newPassword, function (error) { - if (error && error.reason === UsersError.BAD_FIELD) return next(new HttpError(400, error.message)); - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'User not found')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(204)); }); @@ -71,8 +84,7 @@ function setTwoFactorAuthenticationSecret(req, res, next) { assert.strictEqual(typeof req.user, 'object'); users.setTwoFactorAuthenticationSecret(req.user.id, function (error, result) { - if (error && error.reason === UsersError.ALREADY_EXISTS) return next(new HttpError(409, 'TwoFactor Authentication is enabled, disable first')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(201, { secret: result.secret, qrcode: result.qrcode })); }); @@ -85,10 +97,7 @@ function enableTwoFactorAuthentication(req, res, next) { if (!req.body.totpToken || typeof req.body.totpToken !== 'string') return next(new HttpError(400, 'totpToken must be a nonempty string')); users.enableTwoFactorAuthentication(req.user.id, req.body.totpToken, function (error) { - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'User not found')); - if (error && error.reason === UsersError.BAD_TOKEN) return next(new HttpError(412, 'Invalid token')); - if (error && error.reason === UsersError.ALREADY_EXISTS) return next(new HttpError(409, 'TwoFactor Authentication is already enabled')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(202, {})); }); diff --git a/src/routes/users.js b/src/routes/users.js index 46a1cf757..aac74c946 100644 --- a/src/routes/users.js +++ b/src/routes/users.js @@ -15,10 +15,28 @@ exports = module.exports = { var assert = require('assert'), auditSource = require('../auditsource.js'), + BoxError = require('../boxerror.js'), HttpError = require('connect-lastmile').HttpError, HttpSuccess = require('connect-lastmile').HttpSuccess, - users = require('../users.js'), - UsersError = users.UsersError; + users = require('../users.js'); + +function toHttpError(error) { + switch (error.reason) { + case BoxError.NOT_FOUND: + return new HttpError(404, error); + case BoxError.ALREADY_EXISTS: + return new HttpError(409, error); + case BoxError.BAD_FIELD: + return new HttpError(400, error); + case BoxError.EXTERNAL_ERROR: + return new HttpError(424, error); + case BoxError.INVALID_CREDENTIALS: + return new HttpError(412, error); + case BoxError.INTERNAL_ERROR: + default: + return new HttpError(500, error); + } +} function create(req, res, next) { assert.strictEqual(typeof req.body, 'object'); @@ -35,9 +53,7 @@ function create(req, res, next) { var displayName = req.body.displayName || ''; users.create(username, password, email, displayName, { invitor: req.user, admin: req.body.admin }, auditSource.fromRequest(req), function (error, user) { - if (error && error.reason === UsersError.BAD_FIELD) return next(new HttpError(400, error.message)); - if (error && error.reason === UsersError.ALREADY_EXISTS) return next(new HttpError(409, error.message)); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); var userInfo = { id: user.id, @@ -72,10 +88,7 @@ function update(req, res, next) { if ('active' in req.body && typeof req.body.active !== 'boolean') return next(new HttpError(400, 'active must be a boolean')); users.update(req.params.userId, req.body, auditSource.fromRequest(req), function (error) { - if (error && error.reason === UsersError.BAD_FIELD) return next(new HttpError(400, error.message)); - if (error && error.reason === UsersError.ALREADY_EXISTS) return next(new HttpError(409, error.message)); - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'User not found')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(204)); }); @@ -91,7 +104,7 @@ function list(req, res, next) { if (req.query.search && typeof req.query.search !== 'string') return next(new HttpError(400, 'search must be a string')); users.getAllPaged(req.query.search || null, page, perPage, function (error, results) { - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); results = results.map(users.removeRestrictedFields); @@ -104,8 +117,7 @@ function get(req, res, next) { assert.strictEqual(typeof req.user, 'object'); users.get(req.params.userId, function (error, result) { - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'No such user')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(200, users.removePrivateFields(result))); }); @@ -117,9 +129,7 @@ function remove(req, res, next) { if (req.user.id === req.params.userId) return next(new HttpError(409, 'Not allowed to remove yourself.')); users.remove(req.params.userId, auditSource.fromRequest(req), function (error) { - if (error && error.reason === UsersError.BAD_FIELD) return next(new HttpError(400, error.message)); - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'No such user')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(204)); }); @@ -133,9 +143,7 @@ function verifyPassword(req, res, next) { if (typeof req.body.password !== 'string') return next(new HttpError(400, 'API call requires user password')); users.verifyWithUsername(req.user.username, req.body.password, function (error) { - if (error && error.reason === UsersError.WRONG_PASSWORD) return next(new HttpError(412, 'Password incorrect')); - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'No such user')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); req.body.password = ''; // this will prevent logs from displaying plain text password @@ -147,8 +155,7 @@ function createInvite(req, res, next) { assert.strictEqual(typeof req.params.userId, 'string'); users.createInvite(req.params.userId, function (error, resetToken) { - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'User not found')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(200, { resetToken: resetToken })); }); @@ -158,9 +165,7 @@ function sendInvite(req, res, next) { assert.strictEqual(typeof req.params.userId, 'string'); users.sendInvite(req.params.userId, { invitor: req.user }, function (error) { - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'User not found')); - if (error && error.reason === UsersError.BAD_FIELD) return next(new HttpError(409, 'Call createInvite API first')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(200, { })); }); @@ -173,8 +178,7 @@ function setGroups(req, res, next) { if (!Array.isArray(req.body.groupIds)) return next(new HttpError(400, 'API call requires a groups array.')); users.setMembership(req.params.userId, req.body.groupIds, function (error) { - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'One or more groups not found')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(204)); }); @@ -187,9 +191,7 @@ function changePassword(req, res, next) { if (typeof req.body.password !== 'string') return next(new HttpError(400, 'password must be a string')); users.setPassword(req.params.userId, req.body.password, function (error) { - if (error && error.reason === UsersError.BAD_FIELD) return next(new HttpError(400, error.message)); - if (error && error.reason === UsersError.NOT_FOUND) return next(new HttpError(404, 'User not found')); - if (error) return next(new HttpError(500, error)); + if (error) return next(toHttpError(error)); next(new HttpSuccess(204)); }); diff --git a/src/test/database-test.js b/src/test/database-test.js index 038a864ad..3ee1d3ae9 100644 --- a/src/test/database-test.js +++ b/src/test/database-test.js @@ -13,7 +13,6 @@ var appdb = require('../appdb.js'), BoxError = require('../boxerror.js'), clientdb = require('../clientdb.js'), database = require('../database'), - DatabaseError = require('../databaseerror.js'), domaindb = require('../domaindb'), eventlogdb = require('../eventlogdb.js'), expect = require('expect.js'), @@ -466,7 +465,7 @@ describe('database', function () { userdb.add(tmp.id, tmp, function (error) { expect(error).to.be.ok(); - expect(error.reason).to.be(DatabaseError.ALREADY_EXISTS); + expect(error.reason).to.be(BoxError.ALREADY_EXISTS); expect(error.message).to.equal('email already exists'); done(); }); @@ -479,7 +478,7 @@ describe('database', function () { userdb.add(tmp.id, tmp, function (error) { expect(error).to.be.ok(); - expect(error.reason).to.be(DatabaseError.ALREADY_EXISTS); + expect(error.reason).to.be(BoxError.ALREADY_EXISTS); expect(error.message).to.equal('username already exists'); done(); }); @@ -512,7 +511,7 @@ describe('database', function () { it('getByResetToken fails for empty resetToken', function (done) { userdb.getByResetToken(USER_0.email, '', function (error, user) { expect(error).to.be.ok(); - expect(error.reason).to.be(DatabaseError.INTERNAL_ERROR); + expect(error.reason).to.be(BoxError.NOT_FOUND); expect(user).to.not.be.ok(); done(); }); @@ -521,7 +520,7 @@ describe('database', function () { it('getByResetToken fails for bad email', function (done) { userdb.getByResetToken(USER_0.email + 'x', USER_0.resetToken, function (error, user) { expect(error).to.be.ok(); - expect(error.reason).to.be(DatabaseError.NOT_FOUND); + expect(error.reason).to.be(BoxError.NOT_FOUND); expect(user).to.not.be.ok(); done(); }); @@ -633,7 +632,7 @@ describe('database', function () { it('can update the user with already existing email', function (done) { userdb.update(USER_0.id, { email: USER_2.email }, function (error) { expect(error).to.be.ok(); - expect(error.reason).to.be(DatabaseError.ALREADY_EXISTS); + expect(error.reason).to.be(BoxError.ALREADY_EXISTS); expect(error.message).to.equal('email already exists'); done(); }); @@ -642,7 +641,7 @@ describe('database', function () { it('can update the user with already existing username', function (done) { userdb.update(USER_0.id, { username: USER_2.username }, function (error) { expect(error).to.be.ok(); - expect(error.reason).to.be(DatabaseError.ALREADY_EXISTS); + expect(error.reason).to.be(BoxError.ALREADY_EXISTS); expect(error.message).to.equal('username already exists'); done(); }); @@ -657,7 +656,7 @@ describe('database', function () { it('cannot del non-existing user', function (done) { userdb.del(USER_0.id + USER_0.id, function (error) { expect(error).to.be.ok(); - expect(error.reason).to.be(DatabaseError.NOT_FOUND); + expect(error.reason).to.be(BoxError.NOT_FOUND); done(); }); }); diff --git a/src/test/users-test.js b/src/test/users-test.js index ee676c56c..28afe09db 100644 --- a/src/test/users-test.js +++ b/src/test/users-test.js @@ -246,7 +246,7 @@ describe('User', function () { users.verify(userObject.id, '', function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); @@ -256,7 +256,7 @@ describe('User', function () { users.verify(userObject.id, PASSWORD+PASSWORD, function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); @@ -274,7 +274,7 @@ describe('User', function () { it('fails for ghost if not enabled', function (done) { users.verify(userObject.id, 'foobar', function (error) { expect(error).to.be.a(UsersError); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); }); @@ -288,7 +288,7 @@ describe('User', function () { fs.unlinkSync(constants.GHOST_USER_FILE); expect(error).to.be.a(UsersError); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); }); @@ -346,7 +346,7 @@ describe('User', function () { users.verifyWithUsername(USERNAME, '', function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); @@ -356,7 +356,7 @@ describe('User', function () { users.verifyWithUsername(USERNAME, PASSWORD+PASSWORD, function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); @@ -390,7 +390,7 @@ describe('User', function () { fs.unlinkSync(constants.GHOST_USER_FILE); expect(error).to.be.a(UsersError); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); }); @@ -433,7 +433,7 @@ describe('User', function () { users.verifyWithEmail(EMAIL, '', function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); @@ -443,7 +443,7 @@ describe('User', function () { users.verifyWithEmail(EMAIL, PASSWORD+PASSWORD, function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); @@ -477,7 +477,7 @@ describe('User', function () { fs.unlinkSync(constants.GHOST_USER_FILE); expect(error).to.be.a(UsersError); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); }); @@ -804,7 +804,7 @@ describe('User', function () { users.verify(userObject.id, PASSWORD, function (error, result) { expect(error).to.be.ok(); expect(result).to.not.be.ok(); - expect(error.reason).to.equal(UsersError.WRONG_PASSWORD); + expect(error.reason).to.equal(UsersError.INVALID_CREDENTIALS); done(); }); }); diff --git a/src/userdb.js b/src/userdb.js index 55a77f3e1..902d01631 100644 --- a/src/userdb.js +++ b/src/userdb.js @@ -19,9 +19,9 @@ exports = module.exports = { }; var assert = require('assert'), + BoxError = require('./boxerror.js'), database = require('./database.js'), debug = require('debug')('box:userdb'), - DatabaseError = require('./databaseerror'), mysql = require('mysql'); var USERS_FIELDS = [ 'id', 'username', 'email', 'fallbackEmail', 'password', 'salt', 'createdAt', 'modifiedAt', 'resetToken', 'displayName', @@ -42,8 +42,8 @@ function get(userId, callback) { assert.strictEqual(typeof callback, 'function'); database.query('SELECT ' + USERS_FIELDS + ' FROM users WHERE id = ?', [ userId ], function (error, result) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); - if (result.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); + if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND)); callback(null, postProcess(result[0])); }); @@ -54,8 +54,8 @@ function getByUsername(username, callback) { assert.strictEqual(typeof callback, 'function'); database.query('SELECT ' + USERS_FIELDS + ' FROM users WHERE username = ?', [ username ], function (error, result) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); - if (result.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); + if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND)); callback(null, postProcess(result[0])); }); @@ -66,8 +66,8 @@ function getByEmail(email, callback) { assert.strictEqual(typeof callback, 'function'); database.query('SELECT ' + USERS_FIELDS + ' FROM users WHERE email = ?', [ email ], function (error, result) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); - if (result.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); + if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND)); callback(null, postProcess(result[0])); }); @@ -78,8 +78,8 @@ function getOwner(callback) { // the first created user it the 'owner' database.query('SELECT ' + USERS_FIELDS + ' FROM users WHERE admin=1 ORDER BY createdAt LIMIT 1', function (error, result) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); - if (result.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); + if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND)); callback(null, postProcess(result[0])); }); @@ -90,11 +90,9 @@ function getByResetToken(email, resetToken, callback) { assert.strictEqual(typeof resetToken, 'string'); assert.strictEqual(typeof callback, 'function'); - if (resetToken.length === 0) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, 'Empty resetToken not allowed')); - database.query('SELECT ' + USERS_FIELDS + ' FROM users WHERE email=? AND resetToken=?', [ email, resetToken ], function (error, result) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); - if (result.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); + if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND)); callback(null, postProcess(result[0])); }); @@ -106,7 +104,7 @@ function getAllWithGroupIds(callback) { database.query('SELECT ' + USERS_FIELDS + ',GROUP_CONCAT(groupMembers.groupId) AS groupIds ' + ' FROM users LEFT OUTER JOIN groupMembers ON users.id = groupMembers.userId ' + ' GROUP BY users.id ORDER BY users.username', function (error, results) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); results.forEach(function (result) { result.groupIds = result.groupIds ? result.groupIds.split(',') : [ ]; @@ -138,7 +136,7 @@ function getAllWithGroupIdsPaged(search, page, perPage, callback) { query += ` GROUP BY users.id ORDER BY users.username ASC LIMIT ${(page-1)*perPage},${perPage} `; database.query(query, function (error, results) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); results.forEach(function (result) { result.groupIds = result.groupIds ? result.groupIds.split(',') : [ ]; @@ -155,7 +153,7 @@ function getAllAdmins(callback) { // the mailer code relies on the first object being the 'owner' (thus the ORDER) database.query('SELECT ' + USERS_FIELDS + ' FROM users WHERE admin=1 ORDER BY createdAt', function (error, results) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); results.forEach(postProcess); @@ -182,10 +180,10 @@ function add(userId, user, callback) { const args = [ userId, user.username, user.password, user.email, user.fallbackEmail, user.salt, user.createdAt, user.modifiedAt, user.resetToken, user.displayName, user.admin, user.source ]; database.query(query, args, function (error) { - if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_email') !== -1) return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, 'email already exists')); - if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_username') !== -1) return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, 'username already exists')); - if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('PRIMARY') !== -1) return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, 'id already exists')); - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_email') !== -1) return callback(new BoxError(BoxError.ALREADY_EXISTS, 'email already exists')); + if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_username') !== -1) return callback(new BoxError(BoxError.ALREADY_EXISTS, 'username already exists')); + if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('PRIMARY') !== -1) return callback(new BoxError(BoxError.ALREADY_EXISTS, 'id already exists')); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); callback(null); }); @@ -202,9 +200,9 @@ function del(userId, callback) { queries.push({ query: 'DELETE FROM users WHERE id = ?', args: [ userId ] }); database.transaction(queries, function (error, result) { - if (error && error.code === 'ER_NO_REFERENCED_ROW_2') return callback(new DatabaseError(DatabaseError.NOT_FOUND, error)); - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); - if (result[2].affectedRows !== 1) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + if (error && error.code === 'ER_NO_REFERENCED_ROW_2') return callback(new BoxError(BoxError.NOT_FOUND, error)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); + if (result[2].affectedRows !== 1) return callback(new BoxError(BoxError.NOT_FOUND)); callback(error); }); @@ -217,8 +215,8 @@ function getByAccessToken(accessToken, callback) { debug('getByAccessToken: ' + accessToken); database.query('SELECT ' + USERS_FIELDS + ' FROM users, tokens WHERE tokens.accessToken = ?', [ accessToken ], function (error, result) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); - if (result.length === 0) return callback(new DatabaseError(DatabaseError.NOT_FOUND)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); + if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND)); callback(null, postProcess(result[0])); }); @@ -226,7 +224,7 @@ function getByAccessToken(accessToken, callback) { function clear(callback) { database.query('DELETE FROM users', function (error) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); callback(error); }); @@ -258,9 +256,9 @@ function update(userId, user, callback) { args.push(userId); database.query('UPDATE users SET ' + fields.join(', ') + ' WHERE id = ?', args, function (error) { - if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_email') !== -1) return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, 'email already exists')); - if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_username') !== -1) return callback(new DatabaseError(DatabaseError.ALREADY_EXISTS, 'username already exists')); - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_email') !== -1) return callback(new BoxError(BoxError.ALREADY_EXISTS, 'email already exists')); + if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_username') !== -1) return callback(new BoxError(BoxError.ALREADY_EXISTS, 'username already exists')); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); return callback(null); }); @@ -270,7 +268,7 @@ function count(callback) { assert.strictEqual(typeof callback, 'function'); database.query('SELECT COUNT(*) AS total FROM users', function (error, result) { - if (error) return callback(new DatabaseError(DatabaseError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error)); return callback(null, result[0].total); }); diff --git a/src/users.js b/src/users.js index 12f268168..e1a036092 100644 --- a/src/users.js +++ b/src/users.js @@ -1,8 +1,6 @@ 'use strict'; exports = module.exports = { - UsersError: UsersError, - removePrivateFields: removePrivateFields, removeRestrictedFields: removeRestrictedFields, @@ -38,7 +36,6 @@ let assert = require('assert'), crypto = require('crypto'), constants = require('./constants.js'), debug = require('debug')('box:user'), - DatabaseError = require('./databaseerror.js'), eventlog = require('./eventlog.js'), externalldap = require('./externalldap.js'), groups = require('./groups.js'), @@ -49,7 +46,6 @@ let assert = require('assert'), settings = require('./settings.js'), speakeasy = require('speakeasy'), userdb = require('./userdb.js'), - util = require('util'), uuid = require('uuid'), validator = require('validator'), _ = require('underscore'); @@ -59,48 +55,20 @@ var CRYPTO_ITERATIONS = 10000; // iterations var CRYPTO_KEY_LENGTH = 512; // bits var CRYPTO_DIGEST = 'sha1'; // used to be the default in node 4.1.1 cannot change since it will affect existing db records -// http://dustinsenos.com/articles/customErrorsInNode -// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi -function UsersError(reason, errorOrMessage) { - assert.strictEqual(typeof reason, 'string'); - assert(errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined'); - - Error.call(this); - Error.captureStackTrace(this, this.constructor); - - this.name = this.constructor.name; - this.reason = reason; - if (typeof errorOrMessage === 'undefined') { - this.message = reason; - } else if (typeof errorOrMessage === 'string') { - this.message = errorOrMessage; - } else { - this.message = 'Internal error'; - this.nestedError = errorOrMessage; - } -} -util.inherits(UsersError, Error); -UsersError.INTERNAL_ERROR = 'Internal Error'; -UsersError.ALREADY_EXISTS = 'Already Exists'; -UsersError.NOT_FOUND = 'Not Found'; -UsersError.WRONG_PASSWORD = 'Wrong User or Password'; -UsersError.BAD_FIELD = 'Bad field'; -UsersError.BAD_TOKEN = 'Bad token'; - // keep this in sync with validateGroupname and validateAlias function validateUsername(username) { assert.strictEqual(typeof username, 'string'); - if (username.length < 1) return new UsersError(UsersError.BAD_FIELD, 'Username must be atleast 1 char'); - if (username.length >= 200) return new UsersError(UsersError.BAD_FIELD, 'Username too long'); + if (username.length < 1) return new BoxError(BoxError.BAD_FIELD, 'Username must be atleast 1 char'); + if (username.length >= 200) return new BoxError(BoxError.BAD_FIELD, 'Username too long'); - if (constants.RESERVED_NAMES.indexOf(username) !== -1) return new UsersError(UsersError.BAD_FIELD, 'Username is reserved'); + if (constants.RESERVED_NAMES.indexOf(username) !== -1) return new BoxError(BoxError.BAD_FIELD, 'Username is reserved'); // also need to consider valid LDAP characters here (e.g '+' is reserved) - if (/[^a-zA-Z0-9.-]/.test(username)) return new UsersError(UsersError.BAD_FIELD, 'Username can only contain alphanumerals, dot and -'); + if (/[^a-zA-Z0-9.-]/.test(username)) return new BoxError(BoxError.BAD_FIELD, 'Username can only contain alphanumerals, dot and -'); // app emails are sent using the .app suffix - if (username.indexOf('.app') !== -1) return new UsersError(UsersError.BAD_FIELD, 'Username pattern is reserved for apps'); + if (username.indexOf('.app') !== -1) return new BoxError(BoxError.BAD_FIELD, 'Username pattern is reserved for apps'); return null; } @@ -108,7 +76,7 @@ function validateUsername(username) { function validateEmail(email) { assert.strictEqual(typeof email, 'string'); - if (!validator.isEmail(email)) return new UsersError(UsersError.BAD_FIELD, 'Invalid email'); + if (!validator.isEmail(email)) return new BoxError(BoxError.BAD_FIELD, 'Invalid email'); return null; } @@ -116,7 +84,7 @@ function validateEmail(email) { function validateToken(token) { assert.strictEqual(typeof token, 'string'); - if (token.length !== 64) return new UsersError(UsersError.BAD_TOKEN, 'Invalid token'); // 256-bit hex coded token + if (token.length !== 64) return new BoxError(BoxError.BAD_FIELD, 'Invalid token'); // 256-bit hex coded token return null; } @@ -130,8 +98,8 @@ function validateDisplayName(name) { function validatePassword(password) { assert.strictEqual(typeof password, 'string'); - if (password.length < 8) return new UsersError(UsersError.BAD_FIELD, 'Password must be atleast 8 characters'); - if (password.length > 256) return new UsersError(UsersError.BAD_FIELD, 'Password cannot be more than 256 characters'); + if (password.length < 8) return new BoxError(BoxError.BAD_FIELD, 'Password must be atleast 8 characters'); + if (password.length > 256) return new BoxError(BoxError.BAD_FIELD, 'Password cannot be more than 256 characters'); return null; } @@ -169,7 +137,7 @@ function create(username, password, email, displayName, options, auditSource, ca if (password !== null) { error = validatePassword(password); - if (error) return callback(new UsersError(UsersError.BAD_FIELD, error.message)); + if (error) return callback(error); } else { password = hat(8 * 8); } @@ -182,10 +150,10 @@ function create(username, password, email, displayName, options, auditSource, ca if (error) return callback(error); crypto.randomBytes(CRYPTO_SALT_SIZE, function (error, salt) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.CRYPTO_ERROR, error)); crypto.pbkdf2(password, salt, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST, function (error, derivedKey) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.CRYPTO_ERROR, error)); var now = (new Date()).toISOString(); var user = { @@ -204,8 +172,7 @@ function create(username, password, email, displayName, options, auditSource, ca }; userdb.add(user.id, user, function (error) { - if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new UsersError(UsersError.ALREADY_EXISTS, error.message)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); // when this is used to create the owner, then we have to patch the auditSource to contain himself if (isOwner) { @@ -245,7 +212,7 @@ function verify(userId, password, callback) { get(userId, function (error, user) { if (error) return callback(error); - if (!user.active) return callback(new UsersError(UsersError.NOT_FOUND)); + if (!user.active) return callback(new BoxError(BoxError.NOT_FOUND)); // for just invited users the username may be still null if (user.username && verifyGhost(user.username, password)) { @@ -255,18 +222,17 @@ function verify(userId, password, callback) { if (user.source === 'ldap') { externalldap.verifyPassword(user, password, function (error) { - if (error && error.reason === BoxError.INVALID_CREDENTIALS) return callback(new UsersError(UsersError.WRONG_PASSWORD)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null, user); }); } else { var saltBinary = Buffer.from(user.salt, 'hex'); crypto.pbkdf2(password, saltBinary, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST, function (error, derivedKey) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.CRYPTO_ERROR, error)); var derivedKeyHex = Buffer.from(derivedKey, 'binary').toString('hex'); - if (derivedKeyHex !== user.password) return callback(new UsersError(UsersError.WRONG_PASSWORD)); + if (derivedKeyHex !== user.password) return callback(new BoxError(BoxError.INVALID_CREDENTIALS)); callback(null, user); }); @@ -280,8 +246,7 @@ function verifyWithUsername(username, password, callback) { assert.strictEqual(typeof callback, 'function'); userdb.getByUsername(username.toLowerCase(), function (error, user) { - if (error && error.reason == DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); verify(user.id, password, callback); }); @@ -293,8 +258,7 @@ function verifyWithEmail(email, password, callback) { assert.strictEqual(typeof callback, 'function'); userdb.getByEmail(email.toLowerCase(), function (error, user) { - if (error && error.reason == DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); verify(user.id, password, callback); }); @@ -308,11 +272,10 @@ function removeUser(userId, auditSource, callback) { get(userId, function (error, user) { if (error) return callback(error); - if (settings.isDemo() && user.username === constants.DEMO_USERNAME) return callback(new UsersError(UsersError.BAD_FIELD, 'Not allowed in demo mode')); + if (settings.isDemo() && user.username === constants.DEMO_USERNAME) return callback(new BoxError(BoxError.BAD_FIELD, 'Not allowed in demo mode')); userdb.del(userId, function (error) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); eventlog.add(eventlog.ACTION_USER_REMOVE, auditSource, { userId: userId, user: removePrivateFields(user) }, callback); }); @@ -323,7 +286,7 @@ function getAll(callback) { assert.strictEqual(typeof callback, 'function'); userdb.getAllWithGroupIds(function (error, results) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); return callback(null, results); }); @@ -336,7 +299,7 @@ function getAllPaged(search, page, perPage, callback) { assert.strictEqual(typeof callback, 'function'); userdb.getAllWithGroupIdsPaged(search, page, perPage, function (error, results) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); return callback(null, results); }); @@ -346,7 +309,7 @@ function count(callback) { assert.strictEqual(typeof callback, 'function'); userdb.count(function (error, count) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null, count); }); @@ -367,11 +330,10 @@ function get(userId, callback) { assert.strictEqual(typeof callback, 'function'); userdb.get(userId, function (error, result) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); groups.getMembership(userId, function (error, groupIds) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); result.groupIds = groupIds; @@ -392,8 +354,7 @@ function getByResetToken(email, resetToken, callback) { if (error) return callback(error); userdb.getByResetToken(email, resetToken, function (error, result) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null, result); }); @@ -404,8 +365,7 @@ function getByUsername(username, callback) { assert.strictEqual(typeof callback, 'function'); userdb.getByUsername(username.toLowerCase(), function (error, result) { - if (error && error.reason == DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); get(result.id, callback); }); @@ -441,18 +401,15 @@ function updateUser(userId, data, auditSource, callback) { } userdb.get(userId, function (error, oldUser) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); userdb.update(userId, data, function (error) { - if (error && error.reason === DatabaseError.ALREADY_EXISTS) return callback(new UsersError(UsersError.ALREADY_EXISTS, error.message)); - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND, error.message)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null); get(userId, function (error, result) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); eventlog.add(eventlog.ACTION_USER_UPDATE, auditSource, { userId: userId, @@ -471,8 +428,7 @@ function setMembership(userId, groupIds, callback) { assert.strictEqual(typeof callback, 'function'); groups.setMembership(userId, groupIds, function (error) { - if (error && error.reason === BoxError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND, 'One or more groups not found')); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null); }); @@ -482,7 +438,7 @@ function getAllAdmins(callback) { assert.strictEqual(typeof callback, 'function'); userdb.getAllAdmins(function (error, admins) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null, admins); }); @@ -497,14 +453,12 @@ function resetPasswordByIdentifier(identifier, callback) { else getter = userdb.getByEmail; getter(identifier.toLowerCase(), function (error, result) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); result.resetToken = hat(256); userdb.update(result.id, result, function (error) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); mailer.passwordReset(result); @@ -519,25 +473,23 @@ function setPassword(userId, newPassword, callback) { assert.strictEqual(typeof callback, 'function'); var error = validatePassword(newPassword); - if (error) return callback(new UsersError(UsersError.BAD_FIELD, error.message)); + if (error) return callback(error); userdb.get(userId, function (error, user) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); - if (settings.isDemo() && user.username === constants.DEMO_USERNAME) return callback(new UsersError(UsersError.BAD_FIELD, 'Not allowed in demo mode')); + if (settings.isDemo() && user.username === constants.DEMO_USERNAME) return callback(new BoxError(BoxError.BAD_FIELD, 'Not allowed in demo mode')); var saltBuffer = Buffer.from(user.salt, 'hex'); crypto.pbkdf2(newPassword, saltBuffer, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST, function (error, derivedKey) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.CRYPTO_ERROR, error)); user.modifiedAt = (new Date()).toISOString(); user.password = Buffer.from(derivedKey, 'binary').toString('hex'); user.resetToken = ''; userdb.update(userId, user, function (error) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(); }); @@ -554,11 +506,11 @@ function createOwner(username, password, email, displayName, auditSource, callba assert.strictEqual(typeof callback, 'function'); // This is only not allowed for the owner - if (username === '') return callback(new UsersError(UsersError.BAD_FIELD, 'Username cannot be empty')); + if (username === '') return callback(new BoxError(BoxError.BAD_FIELD, 'Username cannot be empty')); count(function (error, count) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); - if (count !== 0) return callback(new UsersError(UsersError.ALREADY_EXISTS, 'Owner already exists')); + if (error) return callback(error); + if (count !== 0) return callback(new BoxError(BoxError.ALREADY_EXISTS, 'Owner already exists')); create(username, password, email, displayName, { owner: true }, auditSource, function (error, user) { if (error) return callback(error); @@ -570,8 +522,7 @@ function createOwner(username, password, email, displayName, auditSource, callba function getOwner(callback) { userdb.getOwner(function (error, owner) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); return callback(null, owner); }); @@ -582,14 +533,12 @@ function createInvite(userId, callback) { assert.strictEqual(typeof callback, 'function'); userdb.get(userId, function (error, userObject) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); userObject.resetToken = hat(256); userdb.update(userId, userObject, function (error) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null, userObject.resetToken); }); @@ -602,10 +551,9 @@ function sendInvite(userId, options, callback) { assert.strictEqual(typeof callback, 'function'); userdb.get(userId, function (error, userObject) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); - if (!userObject.resetToken) return callback(new UsersError(UsersError.BAD_FIELD, 'Must generate resetToken to send inivitation')); + if (!userObject.resetToken) return callback(new BoxError(BoxError.BAD_FIELD, 'Must generate resetToken to send inivitation')); mailer.sendInvite(userObject, options.invitor || null); @@ -618,19 +566,17 @@ function setTwoFactorAuthenticationSecret(userId, callback) { assert.strictEqual(typeof callback, 'function'); userdb.get(userId, function (error, result) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); - if (result.twoFactorAuthenticationEnabled) return callback(new UsersError(UsersError.ALREADY_EXISTS)); + if (result.twoFactorAuthenticationEnabled) return callback(new BoxError(BoxError.ALREADY_EXISTS)); var secret = speakeasy.generateSecret({ name: `Cloudron ${settings.adminFqdn()} (${result.username})` }); userdb.update(userId, { twoFactorAuthenticationSecret: secret.base32, twoFactorAuthenticationEnabled: false }, function (error) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND, error.message)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); qrcode.toDataURL(secret.otpauth_url, function (error, dataUrl) { - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(new BoxError(BoxError.INTERNAL_ERROR, error)); callback(null, { secret: secret.base32, qrcode: dataUrl }); }); @@ -644,17 +590,15 @@ function enableTwoFactorAuthentication(userId, totpToken, callback) { assert.strictEqual(typeof callback, 'function'); userdb.get(userId, function (error, result) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); var verified = speakeasy.totp.verify({ secret: result.twoFactorAuthenticationSecret, encoding: 'base32', token: totpToken, window: 2 }); - if (!verified) return callback(new UsersError(UsersError.BAD_TOKEN)); + if (!verified) return callback(new BoxError(BoxError.INVALID_CREDENTIALS)); - if (result.twoFactorAuthenticationEnabled) return callback(new UsersError(UsersError.ALREADY_EXISTS)); + if (result.twoFactorAuthenticationEnabled) return callback(new BoxError(BoxError.ALREADY_EXISTS)); userdb.update(userId, { twoFactorAuthenticationEnabled: true }, function (error) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND, error.message)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null); }); @@ -666,8 +610,7 @@ function disableTwoFactorAuthentication(userId, callback) { assert.strictEqual(typeof callback, 'function'); userdb.update(userId, { twoFactorAuthenticationEnabled: false, twoFactorAuthenticationSecret: '' }, function (error) { - if (error && error.reason === DatabaseError.NOT_FOUND) return callback(new UsersError(UsersError.NOT_FOUND, error.message)); - if (error) return callback(new UsersError(UsersError.INTERNAL_ERROR, error)); + if (error) return callback(error); callback(null); });