Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 1s
440 lines
15 KiB
TypeScript
440 lines
15 KiB
TypeScript
import type { Credentials } from '@rocket.chat/api-client';
|
|
import type { IRoom, IUser } from '@rocket.chat/core-typings';
|
|
import { Random } from '@rocket.chat/random';
|
|
import { expect } from 'chai';
|
|
import EJSON from 'ejson';
|
|
import { before, describe, it, after } from 'mocha';
|
|
|
|
import { getCredentials, api, request, credentials, methodCall } from '../../data/api-data';
|
|
import { updatePermission } from '../../data/permissions.helper';
|
|
import { createRoom, deleteRoom } from '../../data/rooms.helper';
|
|
import { password } from '../../data/user';
|
|
import { createUser, deleteUser, login } from '../../data/users.helper';
|
|
import { IS_EE } from '../../e2e/config/constants';
|
|
|
|
(IS_EE ? describe : describe.skip)('Audit Panel', () => {
|
|
let testChannel: IRoom;
|
|
let testPrivateChannel: IRoom;
|
|
let dummyUser: IUser;
|
|
let auditor: IUser;
|
|
let auditorCredentials: Credentials;
|
|
before((done) => getCredentials(done));
|
|
before(async () => {
|
|
testChannel = (await createRoom({ type: 'c', name: `chat.api-test-${Date.now()}` })).body.channel;
|
|
testPrivateChannel = (await createRoom({ type: 'p', name: `chat.api-test-${Date.now()}` })).body.group;
|
|
dummyUser = await createUser();
|
|
auditor = await createUser({ roles: ['user', 'auditor'] });
|
|
|
|
auditorCredentials = await login(auditor.username, password);
|
|
|
|
// the auditor role has can-audit but not can-audit-log by default; grant it suite-wide for the audit.auditions cases
|
|
await updatePermission('can-audit-log', ['admin', 'auditor']);
|
|
});
|
|
after(async () => {
|
|
await updatePermission('can-audit-log', ['admin']);
|
|
await deleteRoom({ type: 'c', roomId: testChannel._id });
|
|
await deleteUser({ _id: dummyUser._id });
|
|
await deleteUser({ _id: auditor._id });
|
|
await deleteRoom({ type: 'p', roomId: testPrivateChannel._id });
|
|
});
|
|
|
|
describe('audit/rooms.members [no permissions]', () => {
|
|
before(async () => {
|
|
await updatePermission('view-members-list-all-rooms', []);
|
|
});
|
|
after(async () => {
|
|
await updatePermission('view-members-list-all-rooms', ['admin', 'auditor']);
|
|
});
|
|
it('should fail if user does not have view-members-list-all-rooms permission', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: 'GENERAL',
|
|
})
|
|
.expect(403);
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(auditorCredentials)
|
|
.query({
|
|
roomId: 'GENERAL',
|
|
})
|
|
.expect(403);
|
|
});
|
|
});
|
|
|
|
describe('audit/rooms.members', () => {
|
|
it('should fail if user is not logged in', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.query({
|
|
roomId: 'GENERAL',
|
|
})
|
|
.expect(401);
|
|
});
|
|
it('should fail if roomId is invalid', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: Random.id(),
|
|
})
|
|
.expect(404);
|
|
});
|
|
it('should fail if roomId is not present', async () => {
|
|
await request.get(api('audit/rooms.members')).set(credentials).query({}).expect(400);
|
|
});
|
|
it('should fail if roomId is an empty string', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: '',
|
|
})
|
|
.expect(400);
|
|
});
|
|
it('should fetch the members of a room', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: testChannel._id,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.members).to.be.an('array');
|
|
expect(res.body.members).to.have.lengthOf(1);
|
|
});
|
|
});
|
|
it('should persist a log entry', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: testChannel._id,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.members).to.be.an('array');
|
|
expect(res.body.members).to.have.lengthOf(1);
|
|
});
|
|
|
|
await request
|
|
.post(methodCall('auditGetAuditions'))
|
|
.set(credentials)
|
|
.send({
|
|
message: EJSON.stringify({
|
|
method: 'auditGetAuditions',
|
|
params: [{ startDate: new Date(Date.now() - 86400000), endDate: new Date() }],
|
|
id: 'id',
|
|
msg: 'method',
|
|
}),
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
const message = JSON.parse(res.body.message);
|
|
|
|
expect(message.result).to.be.an('array').with.lengthOf.greaterThan(1);
|
|
const entry = message.result.find((audition: any) => {
|
|
return audition.fields?.rids?.includes(testChannel._id);
|
|
});
|
|
expect(entry).to.have.property('u').that.is.an('object').deep.equal({
|
|
_id: 'rocketchat.internal.admin.test',
|
|
username: 'rocketchat.internal.admin.test',
|
|
name: 'RocketChat Internal Admin Test',
|
|
});
|
|
expect(entry).to.have.property('fields').that.is.an('object');
|
|
const { fields } = entry;
|
|
|
|
expect(fields).to.have.property('msg', 'Room_members_list');
|
|
expect(fields).to.have.property('rids').that.is.an('array').with.lengthOf(1);
|
|
});
|
|
});
|
|
it('should fetch the members of a room with offset and count', async () => {
|
|
await request
|
|
.post(methodCall('addUsersToRoom'))
|
|
.set(credentials)
|
|
.send({
|
|
message: JSON.stringify({
|
|
method: 'addUsersToRoom',
|
|
params: [{ rid: testChannel._id, users: [dummyUser.username] }],
|
|
id: 'id',
|
|
msg: 'method',
|
|
}),
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
});
|
|
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: testChannel._id,
|
|
offset: 1,
|
|
count: 1,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.members).to.be.an('array');
|
|
expect(res.body.members).to.have.lengthOf(1);
|
|
expect(res.body.members[0].username).to.be.equal(dummyUser.username);
|
|
expect(res.body.total).to.be.equal(2);
|
|
expect(res.body.offset).to.be.equal(1);
|
|
expect(res.body.count).to.be.equal(1);
|
|
});
|
|
});
|
|
|
|
it('should filter by username', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: testChannel._id,
|
|
filter: dummyUser.username,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.members).to.be.an('array');
|
|
expect(res.body.members).to.have.lengthOf(1);
|
|
expect(res.body.members[0].username).to.be.equal(dummyUser.username);
|
|
});
|
|
});
|
|
|
|
it('should filter by user name', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: testChannel._id,
|
|
filter: dummyUser.name,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.members).to.be.an('array');
|
|
expect(res.body.members).to.have.lengthOf(1);
|
|
expect(res.body.members[0].name).to.be.equal(dummyUser.name);
|
|
});
|
|
});
|
|
|
|
it('should sort by username', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: testChannel._id,
|
|
sort: '{ "username": -1 }',
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.members).to.be.an('array');
|
|
expect(res.body.members).to.have.lengthOf(2);
|
|
expect(res.body.members[1].username).to.be.equal('rocketchat.internal.admin.test');
|
|
expect(res.body.members[0].username).to.be.equal(dummyUser.username);
|
|
});
|
|
});
|
|
|
|
it('should not allow nosqlinjection on filter param', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: testChannel._id,
|
|
filter: '{ "$ne": "rocketchat.internal.admin.test" }',
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.members).to.be.an('array');
|
|
expect(res.body.members).to.have.lengthOf(0);
|
|
});
|
|
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: testChannel._id,
|
|
filter: { username: 'rocketchat.internal.admin.test' },
|
|
})
|
|
.expect(400);
|
|
});
|
|
|
|
it('should allow to fetch info even if user is not in the room', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(auditorCredentials)
|
|
.query({
|
|
roomId: testChannel._id,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.members).to.be.an('array');
|
|
expect(res.body.members[0].username).to.be.equal('rocketchat.internal.admin.test');
|
|
expect(res.body.members[1].username).to.be.equal(dummyUser.username);
|
|
expect(res.body.total).to.be.equal(2);
|
|
});
|
|
});
|
|
|
|
it('should allow to fetch info from private rooms', async () => {
|
|
await request
|
|
.get(api('audit/rooms.members'))
|
|
.set(auditorCredentials)
|
|
.query({
|
|
roomId: testPrivateChannel._id,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.members).to.be.an('array');
|
|
expect(res.body.members[0].username).to.be.equal('rocketchat.internal.admin.test');
|
|
expect(res.body.total).to.be.equal(1);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('[/audit.auditions]', () => {
|
|
const startDate = new Date(0).toISOString();
|
|
const endDate = new Date().toISOString();
|
|
|
|
it('should fail if user is not logged in', () => request.get(api('audit.auditions')).query({ startDate, endDate }).expect(401));
|
|
|
|
it('should fail with 400 when startDate/endDate are missing', () =>
|
|
request.get(api('audit.auditions')).set(auditorCredentials).query({}).expect(400));
|
|
|
|
it('should fail with 400 when a date is invalid', () =>
|
|
request.get(api('audit.auditions')).set(auditorCredentials).query({ startDate: 'not-a-date', endDate }).expect(400));
|
|
|
|
it('should fail with 403 when the user lacks the can-audit-log permission', async () => {
|
|
await updatePermission('can-audit-log', []);
|
|
await request.get(api('audit.auditions')).set(auditorCredentials).query({ startDate, endDate }).expect(403);
|
|
await updatePermission('can-audit-log', ['admin', 'auditor']);
|
|
});
|
|
|
|
it('should return the list of auditions', () =>
|
|
request
|
|
.get(api('audit.auditions'))
|
|
.set(auditorCredentials)
|
|
.query({ startDate, endDate })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('auditions').that.is.an('array');
|
|
}));
|
|
});
|
|
|
|
describe('[/audit.messages]', () => {
|
|
const startDate = new Date(0).toISOString();
|
|
const endDate = new Date().toISOString();
|
|
|
|
it('should fail if user is not logged in', () =>
|
|
request.post(api('audit.messages')).send({ startDate, endDate, users: [], msg: '', type: 'u' }).expect(401));
|
|
|
|
it('should fail with 400 when required params are missing', () =>
|
|
request.post(api('audit.messages')).set(auditorCredentials).send({ startDate, endDate }).expect(400));
|
|
|
|
it('should fail with 400 when a date is invalid', () =>
|
|
request
|
|
.post(api('audit.messages'))
|
|
.set(auditorCredentials)
|
|
.send({ startDate: 'not-a-date', endDate, users: [], msg: '', type: 'u' })
|
|
.expect(400));
|
|
|
|
it('should fail with 403 when the user lacks the can-audit permission', async () => {
|
|
await updatePermission('can-audit', []);
|
|
await request
|
|
.post(api('audit.messages'))
|
|
.set(auditorCredentials)
|
|
.send({ startDate, endDate, users: [], msg: '', type: 'u' })
|
|
.expect(403);
|
|
await updatePermission('can-audit', ['admin', 'auditor']);
|
|
});
|
|
|
|
it('should return matching messages', () =>
|
|
request
|
|
.post(api('audit.messages'))
|
|
.set(auditorCredentials)
|
|
.send({ startDate, endDate, users: [], msg: '', type: 'u' })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').that.is.an('array');
|
|
}));
|
|
|
|
it('should persist an audit log entry', async () => {
|
|
// query auditions with a future endDate so the entry created by the request below (ts = now) is in range
|
|
const auditionsRange = { startDate, endDate: new Date(Date.now() + 60000).toISOString() };
|
|
const before = await request.get(api('audit.auditions')).set(auditorCredentials).query(auditionsRange);
|
|
await request
|
|
.post(api('audit.messages'))
|
|
.set(auditorCredentials)
|
|
.send({ startDate, endDate, users: [], msg: '', type: 'u' })
|
|
.expect(200);
|
|
const after = await request.get(api('audit.auditions')).set(auditorCredentials).query(auditionsRange);
|
|
expect(after.body.auditions.length).to.be.greaterThan(before.body.auditions.length);
|
|
});
|
|
});
|
|
|
|
describe('[/audit.omnichannelMessages]', () => {
|
|
const startDate = new Date(0).toISOString();
|
|
const endDate = new Date().toISOString();
|
|
|
|
it('should fail if user is not logged in', () =>
|
|
request.post(api('audit.omnichannelMessages')).send({ startDate, endDate, users: [], msg: '', type: 'l' }).expect(401));
|
|
|
|
it('should fail with 400 when required params are missing', () =>
|
|
request.post(api('audit.omnichannelMessages')).set(auditorCredentials).send({ startDate, endDate }).expect(400));
|
|
|
|
it('should fail with 400 when a date is invalid', () =>
|
|
request
|
|
.post(api('audit.omnichannelMessages'))
|
|
.set(auditorCredentials)
|
|
.send({ startDate: 'not-a-date', endDate, users: [], msg: '', type: 'l' })
|
|
.expect(400));
|
|
|
|
it('should fail with 403 when the user lacks the can-audit permission', async () => {
|
|
await updatePermission('can-audit', []);
|
|
await request
|
|
.post(api('audit.omnichannelMessages'))
|
|
.set(auditorCredentials)
|
|
.send({ startDate, endDate, users: [], msg: '', type: 'l' })
|
|
.expect(403);
|
|
await updatePermission('can-audit', ['admin', 'auditor']);
|
|
});
|
|
|
|
it('should return matching omnichannel messages', () =>
|
|
request
|
|
.post(api('audit.omnichannelMessages'))
|
|
.set(auditorCredentials)
|
|
.send({ startDate, endDate, users: [], msg: '', type: 'l' })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').that.is.an('array');
|
|
}));
|
|
|
|
it('should persist an audit log entry', async () => {
|
|
// query auditions with a future endDate so the entry created by the request below (ts = now) is in range
|
|
const auditionsRange = { startDate, endDate: new Date(Date.now() + 60000).toISOString() };
|
|
const before = await request.get(api('audit.auditions')).set(auditorCredentials).query(auditionsRange);
|
|
await request
|
|
.post(api('audit.omnichannelMessages'))
|
|
.set(auditorCredentials)
|
|
.send({ startDate, endDate, users: [], msg: '', type: 'l' })
|
|
.expect(200);
|
|
const after = await request.get(api('audit.auditions')).set(auditorCredentials).query(auditionsRange);
|
|
expect(after.body.auditions.length).to.be.greaterThan(before.body.auditions.length);
|
|
});
|
|
});
|
|
});
|