diff --git a/src/routes/users.js b/src/routes/users.js index 7754162ef..5dda1b7a6 100644 --- a/src/routes/users.js +++ b/src/routes/users.js @@ -138,12 +138,10 @@ async function list(req, res, next) { const active = typeof req.query.active !== 'undefined' ? ((req.query.active === '1' || req.query.active === 'true') ? true : false) : null; - let [error, results] = await safe(users.listPaged(req.query.search || null, active, page, perPage)); + const [error, results] = await safe(users.listPaged(req.query.search || null, active, page, perPage)); if (error) return next(BoxError.toHttpError(error)); - results = results.map(users.removePrivateFields); - - next(new HttpSuccess(200, { users: results })); + next(new HttpSuccess(200, { users: results.map(users.removePrivateFields) })); } function get(req, res, next) { @@ -237,7 +235,7 @@ async function getPasswordResetLink(req, res, next) { if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`)); - let [error, passwordResetLink] = await safe(users.getPasswordResetLink(req.resource, AuditSource.fromRequest(req))); + const [error, passwordResetLink] = await safe(users.getPasswordResetLink(req.resource, AuditSource.fromRequest(req))); if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(200, { passwordResetLink })); @@ -249,7 +247,7 @@ async function sendPasswordResetEmail(req, res, next) { if (!req.body.email || typeof req.body.email !== 'string') return next(new HttpError(400, 'email must be a non-empty string')); if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`)); - let [error] = await safe(users.sendPasswordResetEmail(req.resource, req.body.email, AuditSource.fromRequest(req))); + const [error] = await safe(users.sendPasswordResetEmail(req.resource, req.body.email, AuditSource.fromRequest(req))); if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(202, {})); @@ -260,7 +258,7 @@ async function getInviteLink(req, res, next) { if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`)); - let [error, inviteLink] = await safe(users.getInviteLink(req.resource, AuditSource.fromRequest(req))); + const [error, inviteLink] = await safe(users.getInviteLink(req.resource, AuditSource.fromRequest(req))); if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(200, { inviteLink })); @@ -272,7 +270,7 @@ async function sendInviteEmail(req, res, next) { if (!req.body.email || typeof req.body.email !== 'string') return next(new HttpError(400, 'email must be a non-empty string')); if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`)); - let [error] = await safe(users.sendInviteEmail(req.resource, req.body.email, AuditSource.fromRequest(req))); + const [error] = await safe(users.sendInviteEmail(req.resource, req.body.email, AuditSource.fromRequest(req))); if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(202, {})); diff --git a/src/users.js b/src/users.js index 45ff0efcc..5232dc00e 100644 --- a/src/users.js +++ b/src/users.js @@ -205,7 +205,8 @@ async function add(email, data, auditSource) { assert.strictEqual(typeof data.displayName, 'string'); if ('fallbackEmail' in data) assert.strictEqual(typeof data.fallbackEmail, 'string'); - let { username, password, displayName } = data; + const { displayName } = data; + let { username, password } = data; let fallbackEmail = data.fallbackEmail || ''; const source = data.source || ''; // empty is local user const role = data.role || exports.ROLE_USER; @@ -241,26 +242,24 @@ async function add(email, data, auditSource) { error = validateRole(role); if (error) throw error; - let salt, derivedKey; + const [randomBytesError, salt] = await safe(randomBytesAsync(CRYPTO_SALT_SIZE)); + if (randomBytesError) throw new BoxError(BoxError.CRYPTO_ERROR, randomBytesError); - [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)); - if (error) throw new BoxError(BoxError.CRYPTO_ERROR, error); + const [pbkdf2Error, derivedKey] = await safe(pbkdf2Async(password, salt, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST)); + if (pbkdf2Error) throw new BoxError(BoxError.CRYPTO_ERROR, pbkdf2Error); const user = { id: 'uid-' + uuid.v4(), - username: username, - email: email, - fallbackEmail: fallbackEmail, + username, + email, + fallbackEmail, password: Buffer.from(derivedKey, 'binary').toString('hex'), salt: salt.toString('hex'), resetToken: '', inviteToken: hat(256), // new users start out with invite tokens - displayName: displayName, - source: source, - role: role, + displayName, + source, + role, avatar: constants.AVATAR_NONE, language: '' }; @@ -591,8 +590,6 @@ async function update(user, data, auditSource) { if (constants.DEMO && user.username === constants.DEMO_USERNAME) throw new BoxError(BoxError.BAD_STATE, 'Not allowed in demo mode'); - let error, result; - if (_.isEmpty(data)) return; if (data.username) { @@ -600,34 +597,33 @@ async function update(user, data, auditSource) { // already know about it if (user.username) throw new BoxError(BoxError.CONFLICT, 'Username cannot be changed'); data.username = data.username.toLowerCase(); - error = validateUsername(data.username); + const error = validateUsername(data.username); if (error) throw error; } if (data.email) { data.email = data.email.toLowerCase(); - error = validateEmail(data.email); + const error = validateEmail(data.email); if (error) throw error; } if (data.fallbackEmail) { data.fallbackEmail = data.fallbackEmail.toLowerCase(); - error = validateEmail(data.fallbackEmail); + const error = validateEmail(data.fallbackEmail); if (error) throw error; } if (data.role) { - error = validateRole(data.role); + const error = validateRole(data.role); if (error) throw error; } if (data.language) { - error = await validateLanguage(data.language); + const error = await validateLanguage(data.language); if (error) throw error; } - let args = []; - let fields = []; + const args = [], fields = []; for (const k in data) { if (k === 'twoFactorAuthenticationEnabled' || k === 'active') { fields.push(k + ' = ?'); @@ -642,7 +638,7 @@ async function update(user, data, auditSource) { } args.push(user.id); - [error, result] = await safe(database.query('UPDATE users SET ' + fields.join(', ') + ' WHERE id = ?', args)); + const [error, result] = await safe(database.query('UPDATE users SET ' + fields.join(', ') + ' WHERE id = ?', args)); if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_email') !== -1) throw new BoxError(BoxError.ALREADY_EXISTS, 'email already exists'); if (error && error.code === 'ER_DUP_ENTRY' && error.sqlMessage.indexOf('users_username') !== -1) throw new BoxError(BoxError.ALREADY_EXISTS, 'username already exists'); if (error) throw new BoxError(BoxError.DATABASE_ERROR, error); @@ -785,17 +781,17 @@ async function setPassword(user, newPassword, auditSource) { assert.strictEqual(typeof newPassword, 'string'); assert.strictEqual(typeof auditSource, 'object'); - let error = validatePassword(newPassword); + const error = validatePassword(newPassword); if (error) throw error; if (constants.DEMO && user.username === constants.DEMO_USERNAME) throw new BoxError(BoxError.BAD_STATE, 'Not allowed in demo mode'); if (user.source) throw new BoxError(BoxError.CONFLICT, 'User is from an external directory'); - let salt, derivedKey; - [error, salt] = await safe(randomBytesAsync(CRYPTO_SALT_SIZE)); + const [randomBytesError, salt] = await safe(randomBytesAsync(CRYPTO_SALT_SIZE)); + if (randomBytesError) throw new BoxError(BoxError.CRYPTO_ERROR, randomBytesError); - [error, derivedKey] = await safe(pbkdf2Async(newPassword, salt, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST)); - if (error) throw new BoxError(BoxError.CRYPTO_ERROR, error); + const [pbkdf2Error, derivedKey] = await safe(pbkdf2Async(newPassword, salt, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST)); + if (pbkdf2Error) throw new BoxError(BoxError.CRYPTO_ERROR, pbkdf2Error); const data = { salt: salt.toString('hex'),