diff --git a/packages/rocketchat-lib/server/functions/saveUser.js b/packages/rocketchat-lib/server/functions/saveUser.js index 8502fd453fb..1efe210985e 100644 --- a/packages/rocketchat-lib/server/functions/saveUser.js +++ b/packages/rocketchat-lib/server/functions/saveUser.js @@ -179,35 +179,35 @@ RocketChat.saveUser = function(userId, userData) { return _id; } else { - if (!RocketChat.settings.get('Accounts_AllowUserProfileChange')) { + if (!RocketChat.settings.get('Accounts_AllowUserProfileChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-info') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-password')) { throw new Meteor.Error('error-action-not-allowed', 'Edit user profile is not allowed', { method: 'insertOrUpdateUser', action: 'Update_user', }); } - if (userData.username && !RocketChat.settings.get('Accounts_AllowUsernameChange')) { + if (userData.username && !RocketChat.settings.get('Accounts_AllowUsernameChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-info')) { throw new Meteor.Error('error-action-not-allowed', 'Edit username is not allowed', { method: 'insertOrUpdateUser', action: 'Update_user', }); } - if (userData.name && !RocketChat.settings.get('Accounts_AllowRealNameChange')) { + if (userData.name && !RocketChat.settings.get('Accounts_AllowRealNameChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-info')) { throw new Meteor.Error('error-action-not-allowed', 'Edit user real name is not allowed', { method: 'insertOrUpdateUser', action: 'Update_user', }); } - if (userData.email && !RocketChat.settings.get('Accounts_AllowEmailChange')) { + if (userData.email && !RocketChat.settings.get('Accounts_AllowEmailChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-info')) { throw new Meteor.Error('error-action-not-allowed', 'Edit user email is not allowed', { method: 'insertOrUpdateUser', action: 'Update_user', }); } - if (userData.password && !RocketChat.settings.get('Accounts_AllowPasswordChange')) { + if (userData.password && !RocketChat.settings.get('Accounts_AllowPasswordChange') && !RocketChat.authz.hasPermission(userId, 'edit-other-user-password')) { throw new Meteor.Error('error-action-not-allowed', 'Edit user password is not allowed', { method: 'insertOrUpdateUser', action: 'Update_user', diff --git a/tests/end-to-end/api/01-users.js b/tests/end-to-end/api/01-users.js index 46171f7c633..10b72f61676 100644 --- a/tests/end-to-end/api/01-users.js +++ b/tests/end-to-end/api/01-users.js @@ -234,6 +234,17 @@ describe('[Users]', function() { }) .end(resolve); }); + const updatePermission = (permission, roles) => new Promise((resolve) => { + request.post(api('permissions.update')) + .set(credentials) + .send({ permissions: [{ _id: permission, roles }] }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(resolve); + }); before((done) => { updateSetting('Accounts_AllowUserProfileChange', true) .then(() => updateSetting('Accounts_AllowUsernameChange', true)) @@ -315,103 +326,223 @@ describe('[Users]', function() { }); it('should return an error when trying update username and it is not allowed', (done) => { - updateSetting('Accounts_AllowUsernameChange', false) - .then(() => { - request.post(api('users.update')) - .set(credentials) - .send({ - userId: targetUser._id, - data: { - username: 'fake.name', - }, - }) - .expect('Content-Type', 'application/json') - .expect(400) - .expect((res) => { - expect(res.body).to.have.property('success', false); - }) - .end(done); - }); + updatePermission('edit-other-user-info', ['user']).then(() => { + updateSetting('Accounts_AllowUsernameChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + username: 'fake.name', + }, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + }); + }); + + it('should update the user name when the required permission is applied', (done) => { + updatePermission('edit-other-user-info', ['admin']).then(() => { + updateSetting('Accounts_AllowUsernameChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + username: 'fake.name', + }, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + }); }); it('should return an error when trying update user real name and it is not allowed', (done) => { - updateSetting('Accounts_AllowRealNameChange', false) - .then(() => { - request.post(api('users.update')) - .set(credentials) - .send({ - userId: targetUser._id, - data: { - name: 'Fake name', - }, - }) - .expect('Content-Type', 'application/json') - .expect(400) - .expect((res) => { - expect(res.body).to.have.property('success', false); - }) - .end(done); - }); + updatePermission('edit-other-user-info', ['user']).then(() => { + updateSetting('Accounts_AllowRealNameChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + name: 'Fake name', + }, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + }); + }); + + it('should update user real name when the required permission is applied', (done) => { + updatePermission('edit-other-user-info', ['admin']).then(() => { + updateSetting('Accounts_AllowRealNameChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + name: 'Fake name', + }, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + }); }); it('should return an error when trying update user email and it is not allowed', (done) => { - updateSetting('Accounts_AllowEmailChange', false) - .then(() => { - request.post(api('users.update')) - .set(credentials) - .send({ - userId: targetUser._id, - data: { - email: 'itsnotworking@email.com', - }, - }) - .expect('Content-Type', 'application/json') - .expect(400) - .expect((res) => { - expect(res.body).to.have.property('success', false); - }) - .end(done); - }); + updatePermission('edit-other-user-info', ['user']).then(() => { + updateSetting('Accounts_AllowEmailChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + email: 'itsnotworking@email.com', + }, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + }); + }); + + it('should update user email when the required permission is applied', (done) => { + updatePermission('edit-other-user-info', ['admin']).then(() => { + updateSetting('Accounts_AllowEmailChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + email: apiEmail, + }, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + }); }); it('should return an error when trying update user password and it is not allowed', (done) => { - updateSetting('Accounts_AllowPasswordChange', false) - .then(() => { - request.post(api('users.update')) - .set(credentials) - .send({ - userId: targetUser._id, - data: { - password: 'itsnotworking', - }, - }) - .expect('Content-Type', 'application/json') - .expect(400) - .expect((res) => { - expect(res.body).to.have.property('success', false); - }) - .end(done); - }); + updatePermission('edit-other-user-password', ['user']).then(() => { + updateSetting('Accounts_AllowPasswordChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + password: 'itsnotworking', + }, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + }); + }); + + it('should update user password when the required permission is applied', (done) => { + updatePermission('edit-other-user-password', ['admin']).then(() => { + updateSetting('Accounts_AllowPasswordChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + password: 'itsnotworking', + }, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + }); }); it('should return an error when trying update profile and it is not allowed', (done) => { - updateSetting('Accounts_AllowUserProfileChange', false) - .then(() => { - request.post(api('users.update')) - .set(credentials) - .send({ - userId: targetUser._id, - data: { - verified: true, - }, - }) - .expect('Content-Type', 'application/json') - .expect(400) - .expect((res) => { - expect(res.body).to.have.property('success', false); - }) - .end(done); - }); + updatePermission('edit-other-user-info', ['user']).then(() => { + updateSetting('Accounts_AllowUserProfileChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + verified: true, + }, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); + }); + }); + + it('should update profile when the required permission is applied', (done) => { + updatePermission('edit-other-user-info', ['admin']).then(() => { + updateSetting('Accounts_AllowUserProfileChange', false) + .then(() => { + request.post(api('users.update')) + .set(credentials) + .send({ + userId: targetUser._id, + data: { + verified: true, + }, + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + }) + .end(done); + }); + }); }); });