diff --git a/src/api/users.js b/src/api/users.js index 93835be8c1..db9aa15dbb 100644 --- a/src/api/users.js +++ b/src/api/users.js @@ -36,16 +36,14 @@ usersAPI.update = async function (caller, data) { throw new Error('[[error:invalid-data]]'); } - const [isAdminOrGlobalMod, canEdit, hasPassword, passwordMatch] = await Promise.all([ + const [isAdminOrGlobalMod, canEdit] = await Promise.all([ user.isAdminOrGlobalMod(caller.uid), privileges.users.canEdit(caller.uid, data.uid), - user.hasPassword(data.uid), - data.password ? user.isPasswordCorrect(data.uid, data.password, caller.ip) : false, ]); // Changing own email/username requires password confirmation - if (['email', 'username'].some(prop => Object.keys(data).includes(prop)) && !isAdminOrGlobalMod && caller.uid === data.uid && hasPassword && !passwordMatch) { - throw new Error('[[error:invalid-password]]'); + if (['email', 'username'].some(prop => Object.keys(data).includes(prop))) { + await isPrivilegedOrSelfAndPasswordMatch(caller, data); } if (!canEdit) { @@ -189,6 +187,29 @@ usersAPI.unban = async function (caller, data) { }); }; +async function isPrivilegedOrSelfAndPasswordMatch(caller, data) { + const uid = caller.uid; + const isSelf = parseInt(uid, 10) === parseInt(data.uid, 10); + + const [isAdmin, isTargetAdmin, isGlobalMod] = await Promise.all([ + user.isAdministrator(uid), + user.isAdministrator(data.uid), + user.isGlobalModerator(uid), + ]); + + if ((isTargetAdmin && !isAdmin) || (!isSelf && !(isAdmin || isGlobalMod))) { + throw new Error('[[error:no-privileges]]'); + } + const [hasPassword, passwordMatch] = await Promise.all([ + user.hasPassword(data.uid), + data.password ? user.isPasswordCorrect(data.uid, data.password, caller.ip) : false, + ]); + + if (isSelf && hasPassword && !passwordMatch) { + throw new Error('[[error:invalid-password]]'); + } +} + async function processDeletion(uid, caller) { const isTargetAdmin = await user.isAdministrator(uid); const isSelf = parseInt(uid, 10) === caller.uid; diff --git a/test/user.js b/test/user.js index c756528821..cec9238300 100644 --- a/test/user.js +++ b/test/user.js @@ -931,6 +931,18 @@ describe('User', function () { }); }); + it('should not update a user\'s username if a password is not supplied', async () => { + let _err; + try { + await socketUser.updateProfile({ uid: uid }, { uid: uid, username: 'updatedAgain', password: '' }); + } catch (err) { + _err = err; + } + + assert(_err); + assert.strictEqual(_err.message, '[[error:invalid-password]]'); + }); + it('should change email', function (done) { User.create({ username: 'pooremailupdate', email: 'poor@update.me', password: '123456' }, function (err, uid) { assert.ifError(err);