[FIX] Deactivate users that are the last owner of a room using REST API (#18864)

* test: add e2e tests for REST API user deactivation

* fix(app): read confirmRelinquish from HTTP request

* chore(app): remove unnecessary console.log
pull/18945/head
Felipe Parreira 5 years ago committed by GitHub
parent 982773aeda
commit dc6bcbdba0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      app/api/server/v1/users.js
  2. 7
      tests/data/rooms.helper.js
  3. 579
      tests/end-to-end/api/01-users.js

@ -98,8 +98,10 @@ API.v1.addRoute('users.deleteOwnAccount', { authRequired: true }, {
throw new Meteor.Error('error-not-allowed', 'Not allowed'); throw new Meteor.Error('error-not-allowed', 'Not allowed');
} }
const { confirmRelinquish = false } = this.requestParams();
Meteor.runAsUser(this.userId, () => { Meteor.runAsUser(this.userId, () => {
Meteor.call('deleteUserOwnAccount', password); Meteor.call('deleteUserOwnAccount', password, confirmRelinquish);
}); });
return API.v1.success(); return API.v1.success();
@ -133,7 +135,8 @@ API.v1.addRoute('users.setActiveStatus', { authRequired: true }, {
} }
Meteor.runAsUser(this.userId, () => { Meteor.runAsUser(this.userId, () => {
Meteor.call('setUserActiveStatus', this.bodyParams.userId, this.bodyParams.activeStatus, this.bodyParams.confirmRelinquish); const { userId, activeStatus, confirmRelinquish = false } = this.bodyParams;
Meteor.call('setUserActiveStatus', userId, activeStatus, confirmRelinquish);
}); });
return API.v1.success({ user: Users.findOneById(this.bodyParams.userId, { fields: { active: 1 } }) }); return API.v1.success({ user: Users.findOneById(this.bodyParams.userId, { fields: { active: 1 } }) });
}, },
@ -463,8 +466,10 @@ API.v1.addRoute('users.update', { authRequired: true, twoFactorRequired: true },
} }
if (typeof this.bodyParams.data.active !== 'undefined') { if (typeof this.bodyParams.data.active !== 'undefined') {
const { userId, data: { active }, confirmRelinquish = false } = this.bodyParams;
Meteor.runAsUser(this.userId, () => { Meteor.runAsUser(this.userId, () => {
Meteor.call('setUserActiveStatus', this.bodyParams.userId, this.bodyParams.data.active); Meteor.call('setUserActiveStatus', userId, active, confirmRelinquish);
}); });
} }
const { fields } = this.parseJsonQuery(); const { fields } = this.parseJsonQuery();

@ -1,6 +1,6 @@
import { api, credentials, request } from './api-data'; import { api, credentials, request } from './api-data';
export const createRoom = ({ name, type, username }) => { export const createRoom = ({ name, type, username, members = [] }) => {
if (!type) { if (!type) {
throw new Error('"type" is required in "createRoom" test helper'); throw new Error('"type" is required in "createRoom" test helper');
} }
@ -18,7 +18,10 @@ export const createRoom = ({ name, type, username }) => {
return request.post(api(endpoints[type])) return request.post(api(endpoints[type]))
.set(credentials) .set(credentials)
.send(params); .send({
...params,
members,
});
}; };
export const closeRoom = ({ type, roomId }) => { export const closeRoom = ({ type, roomId }) => {

@ -18,6 +18,7 @@ import { imgURL } from '../../data/interactions.js';
import { customFieldText, clearCustomFields, setCustomFields } from '../../data/custom-fields.js'; import { customFieldText, clearCustomFields, setCustomFields } from '../../data/custom-fields.js';
import { updatePermission, updateSetting } from '../../data/permissions.helper'; import { updatePermission, updateSetting } from '../../data/permissions.helper';
import { createUser, login, deleteUser, getUserStatus } from '../../data/users.helper.js'; import { createUser, login, deleteUser, getUserStatus } from '../../data/users.helper.js';
import { createRoom } from '../../data/rooms.helper';
describe('[Users]', function() { describe('[Users]', function() {
this.retries(0); this.retries(0);
@ -1355,6 +1356,165 @@ describe('[Users]', function() {
}); });
}); });
}); });
it('should return an error when trying to delete user own account if user is the last room owner', async () => {
const user = await createUser();
const createdUserCredentials = await login(user.username, password);
const room = (await createRoom({
type: 'c',
name: `channel.test.${ Date.now() }-${ Math.random() }`,
username: user.username,
members: [user.username],
})).body.channel;
await request.post(api('channels.addOwner'))
.set(credentials)
.send({
userId: user._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.removeOwner'))
.set(credentials)
.send({
userId: credentials['X-User-Id'],
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request
.post(api('users.deleteOwnAccount'))
.set(createdUserCredentials)
.send({
password: crypto.createHash('sha256').update(password, 'utf8').digest('hex'),
})
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', '[user-last-owner]');
expect(res.body).to.have.property('errorType', 'user-last-owner');
});
});
it('should delete user own account if the user is the last room owner and `confirmRelinquish` is set to `true`', async () => {
const user = await createUser();
const createdUserCredentials = await login(user.username, password);
const room = (await createRoom({
type: 'c',
name: `channel.test.${ Date.now() }-${ Math.random() }`,
username: user.username,
members: [user.username],
})).body.channel;
await request.post(api('channels.addOwner'))
.set(credentials)
.send({
userId: user._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.removeOwner'))
.set(credentials)
.send({
userId: credentials['X-User-Id'],
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request
.post(api('users.deleteOwnAccount'))
.set(createdUserCredentials)
.send({
password: crypto.createHash('sha256').update(password, 'utf8').digest('hex'),
confirmRelinquish: true,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
});
it('should assign a new owner to the room if the last room owner is deleted', async () => {
const user = await createUser();
const createdUserCredentials = await login(user.username, password);
const room = (await createRoom({
type: 'c',
name: `channel.test.${ Date.now() }-${ Math.random() }`,
username: user.username,
members: [user.username],
})).body.channel;
await request.post(api('channels.addOwner'))
.set(credentials)
.send({
userId: user._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.removeOwner'))
.set(credentials)
.send({
userId: credentials['X-User-Id'],
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request
.post(api('users.deleteOwnAccount'))
.set(createdUserCredentials)
.send({
password: crypto.createHash('sha256').update(password, 'utf8').digest('hex'),
confirmRelinquish: true,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.get(api('channels.roles'))
.set(credentials)
.query({
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.roles).to.have.lengthOf(1);
expect(res.body.roles[0].roles).to.eql(['owner']);
expect(res.body.roles[0].u).to.have.property('_id', credentials['X-User-Id']);
});
});
}); });
describe('[/users.delete]', () => { describe('[/users.delete]', () => {
@ -1371,7 +1531,7 @@ describe('[Users]', function() {
}); });
const testUsername = `testuserdelete${ +new Date() }`; const testUsername = `testuserdelete${ +new Date() }`;
let targetUser; let targetUser;
it('register a new user...', (done) => { beforeEach((done) => {
request.post(api('users.register')) request.post(api('users.register'))
.set(credentials) .set(credentials)
.send({ .send({
@ -1384,40 +1544,196 @@ describe('[Users]', function() {
.expect(200) .expect(200)
.expect((res) => { .expect((res) => {
targetUser = res.body.user; targetUser = res.body.user;
}).end(done);
});
afterEach((done) => {
updatePermission('delete-user', ['admin']).then(() => {
request.post(api('users.delete'))
.set(credentials)
.send({
userId: targetUser._id,
confirmRelinquish: true,
}).end(done);
});
});
it('should return an error when trying delete user account without "delete-user" permission', async () => {
await updatePermission('delete-user', ['user']);
await request.post(api('users.delete'))
.set(credentials)
.send({
userId: targetUser._id,
}) })
.end(done); .expect('Content-Type', 'application/json')
.expect(403)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', 'unauthorized');
});
}); });
it('should return an error when trying delete user account without "delete-user" permission', (done) => {
updatePermission('delete-user', ['user']) it('should return an error when trying to delete user account if the user is the last room owner', async () => {
.then(() => { await updatePermission('delete-user', ['admin']);
request.post(api('users.delete')) const room = (await createRoom({
.set(credentials) type: 'c',
.send({ name: `channel.test.${ Date.now() }-${ Math.random() }`,
userId: targetUser._id, members: [targetUser.username],
}) })).body.channel;
.expect('Content-Type', 'application/json')
.expect(403) await request.post(api('channels.addOwner'))
.expect((res) => { .set(credentials)
expect(res.body).to.have.property('success', false); .send({
expect(res.body).to.have.property('error', 'unauthorized'); userId: targetUser._id,
}) roomId: room._id,
.end(done); })
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.removeOwner'))
.set(credentials)
.send({
userId: credentials['X-User-Id'],
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('users.delete'))
.set(credentials)
.send({
userId: targetUser._id,
})
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', '[user-last-owner]');
expect(res.body).to.have.property('errorType', 'user-last-owner');
}); });
}); });
it('should delete user account when logged user has "delete-user" permission', (done) => {
updatePermission('delete-user', ['admin']) it('should delete user account if the user is the last room owner and `confirmRelinquish` is set to `true`', async () => {
.then(() => { await updatePermission('delete-user', ['admin']);
request.post(api('users.delete')) const room = (await createRoom({
.set(credentials) type: 'c',
.send({ name: `channel.test.${ Date.now() }-${ Math.random() }`,
userId: targetUser._id, members: [targetUser.username],
}) })).body.channel;
.expect('Content-Type', 'application/json')
.expect(200) await request.post(api('channels.addOwner'))
.expect((res) => { .set(credentials)
expect(res.body).to.have.property('success', true); .send({
}) userId: targetUser._id,
.end(done); roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.removeOwner'))
.set(credentials)
.send({
userId: credentials['X-User-Id'],
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('users.delete'))
.set(credentials)
.send({
userId: targetUser._id,
confirmRelinquish: true,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
});
it('should delete user account when logged user has "delete-user" permission', async () => {
await updatePermission('delete-user', ['admin']);
await request.post(api('users.delete'))
.set(credentials)
.send({
userId: targetUser._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
});
it('should assign a new owner to the room if the last room owner is deleted', async () => {
await updatePermission('delete-user', ['admin']);
const room = (await createRoom({
type: 'c',
name: `channel.test.${ Date.now() }-${ Math.random() }`,
members: [targetUser.username],
})).body.channel;
await request.post(api('channels.addOwner'))
.set(credentials)
.send({
userId: targetUser._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.removeOwner'))
.set(credentials)
.send({
userId: credentials['X-User-Id'],
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('users.delete'))
.set(credentials)
.send({
userId: targetUser._id,
confirmRelinquish: true,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.get(api('channels.roles'))
.set(credentials)
.query({
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.roles).to.have.lengthOf(1);
expect(res.body.roles[0].roles).to.eql(['owner']);
expect(res.body.roles[0].u).to.have.property('_id', credentials['X-User-Id']);
}); });
}); });
}); });
@ -1681,6 +1997,207 @@ describe('[Users]', function() {
}) })
.end(done); .end(done);
}); });
it('should return an error when trying to set other user status to inactive and the user is the last owner of a room', async () => {
const room = (await createRoom({
type: 'c',
name: `channel.test.${ Date.now() }-${ Math.random() }`,
username: targetUser.username,
members: [targetUser.username],
})).body.channel;
await request.post(api('channels.invite'))
.set(credentials)
.send({
userId: targetUser._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.addOwner'))
.set(credentials)
.send({
userId: targetUser._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.removeOwner'))
.set(credentials)
.send({
userId: credentials['X-User-Id'],
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('users.setActiveStatus'))
.set(userCredentials)
.send({
activeStatus: false,
userId: targetUser._id,
})
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', '[user-last-owner]');
expect(res.body).to.have.property('errorType', 'user-last-owner');
});
});
it('should set other user status to inactive if the user is the last owner of a room and `confirmRelinquish` is set to `true`', async () => {
const room = (await createRoom({
type: 'c',
name: `channel.test.${ Date.now() }-${ Math.random() }`,
username: targetUser.username,
members: [targetUser.username],
})).body.channel;
await request.post(api('channels.invite'))
.set(credentials)
.send({
userId: targetUser._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.addOwner'))
.set(credentials)
.send({
userId: targetUser._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.removeOwner'))
.set(credentials)
.send({
userId: credentials['X-User-Id'],
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('users.setActiveStatus'))
.set(userCredentials)
.send({
activeStatus: false,
userId: targetUser._id,
confirmRelinquish: true,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
});
it('should set other user as room owner if the last owner of a room is deactivated and `confirmRelinquish` is set to `true`', async () => {
const room = (await createRoom({
type: 'c',
name: `channel.test.${ Date.now() }-${ Math.random() }`,
members: [targetUser.username],
})).body.channel;
await request.post(api('users.setActiveStatus'))
.set(userCredentials)
.send({
activeStatus: true,
userId: targetUser._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.invite'))
.set(credentials)
.send({
userId: targetUser._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.addOwner'))
.set(credentials)
.send({
userId: targetUser._id,
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('channels.removeOwner'))
.set(credentials)
.send({
userId: credentials['X-User-Id'],
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.post(api('users.setActiveStatus'))
.set(userCredentials)
.send({
activeStatus: false,
userId: targetUser._id,
confirmRelinquish: true,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
await request.get(api('channels.roles'))
.set(credentials)
.query({
roomId: room._id,
})
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body.roles).to.have.lengthOf(2);
expect(res.body.roles[1].roles).to.eql(['owner']);
expect(res.body.roles[1].u).to.have.property('_id', credentials['X-User-Id']);
});
});
it('should return an error when trying to set other user active status and has not the necessary permission(edit-other-user-active-status)', (done) => { it('should return an error when trying to set other user active status and has not the necessary permission(edit-other-user-active-status)', (done) => {
updatePermission('edit-other-user-active-status', []).then(() => { updatePermission('edit-other-user-active-status', []).then(() => {
request.post(api('users.setActiveStatus')) request.post(api('users.setActiveStatus'))

Loading…
Cancel
Save