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
1732 lines
57 KiB
TypeScript
1732 lines
57 KiB
TypeScript
import type { Credentials } from '@rocket.chat/api-client';
|
|
import { TeamType } from '@rocket.chat/core-typings';
|
|
import type { AtLeast, IIntegration, IMessage, IRoom, ITeam, IUser } from '@rocket.chat/core-typings';
|
|
import { Random } from '@rocket.chat/random';
|
|
import { assert, expect } from 'chai';
|
|
import { after, before, describe, it } from 'mocha';
|
|
|
|
import { getCredentials, api, request, credentials } from '../../data/api-data';
|
|
import { createIntegration, removeIntegration } from '../../data/integration.helper';
|
|
import { addPermissions, updatePermission, updateSetting } from '../../data/permissions.helper';
|
|
import { assignRoleToUser } from '../../data/roles.helper';
|
|
import { createRoom, deleteRoom } from '../../data/rooms.helper';
|
|
import { createTeam, deleteTeam } from '../../data/teams.helper';
|
|
import { adminUsername, password } from '../../data/user';
|
|
import type { TestUser } from '../../data/users.helper';
|
|
import { createUser, deleteUser, login, removeRoleFromUser } from '../../data/users.helper';
|
|
|
|
describe('[Incoming Integrations]', () => {
|
|
let integration: IIntegration;
|
|
let integrationCreatedByAnUser: IIntegration;
|
|
let user: TestUser<IUser>;
|
|
let userCredentials: Credentials;
|
|
let channel: IRoom;
|
|
let testChannelName: string;
|
|
|
|
before((done) => getCredentials(done));
|
|
|
|
before(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', []),
|
|
updatePermission('manage-own-incoming-integrations', []),
|
|
updatePermission('manage-own-outgoing-integrations', []),
|
|
updatePermission('manage-outgoing-integrations', []),
|
|
]);
|
|
|
|
testChannelName = `channel.test.${Date.now()}-${Math.random()}`;
|
|
|
|
channel = (await createRoom({ type: 'c', name: testChannelName })).body.channel;
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-outgoing-integrations', ['admin']),
|
|
updatePermission('manage-outgoing-integrations', ['admin']),
|
|
deleteRoom({ type: 'c', roomId: channel._id }),
|
|
deleteUser(user),
|
|
]);
|
|
});
|
|
|
|
describe('[/integrations.create]', () => {
|
|
describe('Permission checks', () => {
|
|
before(async () => {
|
|
await Promise.all([updatePermission('manage-incoming-integrations', []), updatePermission('manage-own-incoming-integrations', [])]);
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
]);
|
|
});
|
|
|
|
it('should return an error when the user DOES NOT have the permission "manage-incoming-integrations" to add an incoming integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: true,
|
|
channel: '#general',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('errorType', 'not_authorized');
|
|
});
|
|
|
|
it('should return an error when the user DOES NOT have the permission "manage-own-incoming-integrations" to add an incoming integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: true,
|
|
channel: '#general',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('errorType', 'not_authorized');
|
|
});
|
|
});
|
|
|
|
describe('With manage-incoming-integrations permission', () => {
|
|
let tempIntegrationId: IIntegration['_id'];
|
|
|
|
before(async () => {
|
|
await updatePermission('manage-incoming-integrations', ['admin']);
|
|
});
|
|
|
|
after(async () => {
|
|
if (tempIntegrationId) {
|
|
await removeIntegration(tempIntegrationId, 'incoming');
|
|
}
|
|
});
|
|
|
|
it('should add the integration successfully when the user ONLY has the permission "manage-incoming-integrations" to add an incoming integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: '#general',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration').and.to.be.an('object');
|
|
tempIntegrationId = res.body.integration._id;
|
|
});
|
|
|
|
it('should set overrideDestinationChannelEnabled setting to false when it is not provided', async () => {
|
|
const res = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: false,
|
|
channel: '#general',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration').and.to.be.an('object');
|
|
expect(res.body.integration).to.have.property('overrideDestinationChannelEnabled', false);
|
|
const integrationId = res.body.integration._id;
|
|
await removeIntegration(integrationId, 'incoming');
|
|
});
|
|
});
|
|
|
|
describe('With manage-own-incoming-integrations permission', () => {
|
|
before(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', []),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
]);
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
]);
|
|
});
|
|
|
|
it('should add the integration successfully when the user ONLY has the permission "manage-own-incoming-integrations" to add an incoming integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test 2',
|
|
enabled: true,
|
|
alias: 'test2',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: '#general',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration').and.to.be.an('object');
|
|
integration = res.body.integration;
|
|
});
|
|
});
|
|
|
|
describe('With both manage-own-incoming-integrations and manage-incoming-integrations', () => {
|
|
it('should not allow users without a role with the message-impersonate permission to be assigned to new incoming integrations', async () => {
|
|
await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: adminUsername,
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: true,
|
|
channel: '#general',
|
|
})
|
|
.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 selected for the incoming integration lacks the 'message-impersonate' permission. [error-user-lacks-message-impersonate-permission]",
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Incoming Integration execution', () => {
|
|
it('should return an error when the user sends an invalid type of integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming-invalid',
|
|
name: 'Incoming test',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: true,
|
|
channel: '#general',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'Invalid integration type.');
|
|
});
|
|
|
|
it('should execute the incoming integration', async () => {
|
|
await request
|
|
.post(`/hooks/${integration._id}/${integration.token}`)
|
|
.send({
|
|
text: 'Example message',
|
|
})
|
|
.expect(200);
|
|
});
|
|
|
|
it("should return an error when sending 'channel' field telling its configuration is disabled", async () => {
|
|
const res = await request
|
|
.post(`/hooks/${integration._id}/${integration.token}`)
|
|
.send({
|
|
text: 'Example message',
|
|
channel: [testChannelName],
|
|
})
|
|
.expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'overriding destination channel is disabled for this integration');
|
|
});
|
|
|
|
it("should return an error when sending 'roomId' field telling its configuration is disabled", async () => {
|
|
const res = await request
|
|
.post(`/hooks/${integration._id}/${integration.token}`)
|
|
.send({
|
|
text: 'Example message',
|
|
roomId: channel._id,
|
|
})
|
|
.expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'overriding destination channel is disabled for this integration');
|
|
});
|
|
it('should send a message for a channel that is specified in the webhooks configuration', (done) => {
|
|
const successfulMessage = `Message sent successfully at #${Date.now()}`;
|
|
void request
|
|
.post(`/hooks/${integration._id}/${integration.token}`)
|
|
.send({
|
|
text: successfulMessage,
|
|
})
|
|
.expect(200)
|
|
.end(() => {
|
|
return request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: 'GENERAL',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
expect(!!(res.body.messages as IMessage[]).find((m) => m.msg === successfulMessage)).to.be.true;
|
|
})
|
|
.end(done);
|
|
});
|
|
});
|
|
it('should send a message for a channel that is not specified in the webhooks configuration', async () => {
|
|
await request
|
|
.put(api('integrations.update'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
overrideDestinationChannelEnabled: true,
|
|
integrationId: integration._id,
|
|
username: 'rocket.cat',
|
|
channel: '#general',
|
|
scriptEnabled: true,
|
|
enabled: true,
|
|
name: integration.name,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration');
|
|
expect(res.body.integration.overrideDestinationChannelEnabled).to.be.equal(true);
|
|
});
|
|
const successfulMessage = `Message sent successfully at #${Date.now()}`;
|
|
await request
|
|
.post(`/hooks/${integration._id}/${integration.token}`)
|
|
.send({
|
|
text: successfulMessage,
|
|
channel: [testChannelName],
|
|
})
|
|
.expect(200);
|
|
|
|
return request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: channel._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
expect(!!(res.body.messages as IMessage[]).find((m) => m.msg === successfulMessage)).to.be.true;
|
|
});
|
|
});
|
|
|
|
it('should send a message if the payload is a application/x-www-form-urlencoded JSON', async () => {
|
|
const payload = { msg: `Message as x-www-form-urlencoded JSON sent successfully at #${Date.now()}` };
|
|
|
|
await request
|
|
.post(`/hooks/${integration._id}/${integration.token}`)
|
|
.set('Content-Type', 'application/x-www-form-urlencoded')
|
|
.send(`payload=${JSON.stringify(payload)}`)
|
|
.expect(200);
|
|
|
|
const messagesResult = await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: 'GENERAL',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(messagesResult.body).to.have.property('success', true);
|
|
expect(messagesResult.body).to.have.property('messages').and.to.be.an('array');
|
|
expect(!!(messagesResult.body.messages as IMessage[]).find((m) => m.msg === payload.msg)).to.be.true;
|
|
});
|
|
|
|
describe('When the user does not have a role with the message-impersonate permission', () => {
|
|
before(async () => {
|
|
await addPermissions({
|
|
'message-impersonate': ['user'],
|
|
});
|
|
});
|
|
|
|
after(async () => {
|
|
await addPermissions({
|
|
'message-impersonate': ['bot', 'app'],
|
|
});
|
|
});
|
|
|
|
it('should return an error when executing incoming integration', async () => {
|
|
await request
|
|
.post(`/hooks/${integration._id}/${integration.token}`)
|
|
.send({
|
|
text: 'Example message',
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'error-user-lacks-message-impersonate-permission');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Script integration tests', () => {
|
|
let withScript: IIntegration;
|
|
let withScriptDefaultContentType: IIntegration;
|
|
let withSkipTranspile: IIntegration;
|
|
|
|
const sloppyModeScript =
|
|
'const buildMessage = (obj) => {\n' +
|
|
' \n' +
|
|
' const template = `[#VALUE](${ obj.test })`;\n' +
|
|
' \n' +
|
|
' return {\n' +
|
|
' text: template\n' +
|
|
' };\n' +
|
|
' };\n' +
|
|
' \n' +
|
|
' class Script {\n' +
|
|
' process_incoming_request({ request }) {\n' +
|
|
' msg = buildMessage(request.content);\n' +
|
|
' \n' +
|
|
' return {\n' +
|
|
' content:{\n' +
|
|
' text: msg.text\n' +
|
|
' }\n' +
|
|
' };\n' +
|
|
' }\n' +
|
|
' }\n' +
|
|
' \n';
|
|
|
|
before(async () => {
|
|
await updatePermission('manage-incoming-integrations', ['admin']);
|
|
|
|
const res1 = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test with script',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: true,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: '#general',
|
|
script: `
|
|
class Script {
|
|
process_incoming_request({ request }) {
|
|
return {
|
|
content:{
|
|
text: request.content.text
|
|
}
|
|
};
|
|
}
|
|
}
|
|
`,
|
|
})
|
|
.expect(200);
|
|
withScript = res1.body.integration;
|
|
|
|
const res2 = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test with script and default content-type',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: true,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: '#general',
|
|
script: sloppyModeScript,
|
|
})
|
|
.expect(200);
|
|
withScriptDefaultContentType = res2.body.integration;
|
|
|
|
// Same script but with skipTranspile: true — no Babel, class methods
|
|
// run in strict mode so `msg = buildMessage(...)` throws ReferenceError.
|
|
const res3 = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test with skipTranspile',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: true,
|
|
skipTranspile: true,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: '#general',
|
|
script: sloppyModeScript,
|
|
})
|
|
.expect(200);
|
|
withSkipTranspile = res3.body.integration;
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
removeIntegration(withScript._id, 'incoming'),
|
|
removeIntegration(withScriptDefaultContentType._id, 'incoming'),
|
|
removeIntegration(withSkipTranspile._id, 'incoming'),
|
|
]);
|
|
});
|
|
|
|
it('should send a message if the payload is a application/x-www-form-urlencoded JSON AND the integration has a valid script', async () => {
|
|
const payload = { text: `Message as x-www-form-urlencoded JSON sent successfully at #${Date.now()}` };
|
|
|
|
await request
|
|
.post(`/hooks/${withScript._id}/${withScript.token}`)
|
|
.set('Content-Type', 'application/x-www-form-urlencoded')
|
|
.send(`payload=${JSON.stringify(payload)}`)
|
|
.expect(200);
|
|
|
|
const messagesResult = await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: 'GENERAL',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(messagesResult.body).to.have.property('success', true);
|
|
expect(messagesResult.body).to.have.property('messages').and.to.be.an('array');
|
|
expect(!!(messagesResult.body.messages as IMessage[]).find((m) => m.msg === payload.text)).to.be.true;
|
|
});
|
|
|
|
it('should send a message if the payload is application/json and the integration has a valid script', async () => {
|
|
const payload = { test: 'test' };
|
|
|
|
await request
|
|
.post(`/hooks/${withScriptDefaultContentType._id}/${withScriptDefaultContentType.token}`)
|
|
.set('Content-Type', 'application/json')
|
|
.send(JSON.stringify(payload))
|
|
.expect(200);
|
|
|
|
const messagesResult = await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: 'GENERAL',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(messagesResult.body).to.have.property('success', true);
|
|
expect(messagesResult.body).to.have.property('messages').and.to.be.an('array');
|
|
expect(!!(messagesResult.body.messages as IMessage[]).find((m) => m.msg === '[#VALUE](test)')).to.be.true;
|
|
});
|
|
|
|
it('should create the skipTranspile integration with scriptCompiled and no scriptError', () => {
|
|
expect(withSkipTranspile).to.have.property('scriptCompiled');
|
|
expect(withSkipTranspile).to.not.have.property('scriptError');
|
|
expect(withSkipTranspile).to.have.property('skipTranspile', true);
|
|
});
|
|
|
|
it('should fail to execute the same sloppy-mode script when skipTranspile is true', async () => {
|
|
const payload = { test: 'test' };
|
|
|
|
await request
|
|
.post(`/hooks/${withSkipTranspile._id}/${withSkipTranspile.token}`)
|
|
.set('Content-Type', 'application/json')
|
|
.send(JSON.stringify(payload))
|
|
.expect(400);
|
|
});
|
|
});
|
|
|
|
describe('With manage-own-incoming-integrations permission', () => {
|
|
let integrationId: string;
|
|
|
|
before(async () => {
|
|
await updatePermission('manage-own-incoming-integrations', ['admin']);
|
|
});
|
|
|
|
after(async () => {
|
|
if (integrationId) {
|
|
await removeIntegration(integrationId, 'incoming');
|
|
}
|
|
});
|
|
|
|
it('should return scriptCompiled and no scriptError', async () => {
|
|
const res = await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: true,
|
|
scriptEngine: 'isolated-vm',
|
|
channel: '#general',
|
|
script: `
|
|
class Script {
|
|
process_incoming_request({ request }) {
|
|
return {
|
|
content:{
|
|
text: request.content.text
|
|
}
|
|
};
|
|
}
|
|
}
|
|
`,
|
|
})
|
|
.expect(200);
|
|
|
|
expect(res.body.integration).to.have.property('scriptCompiled');
|
|
expect(res.body.integration).to.not.have.property('scriptError');
|
|
|
|
integrationId = res.body.integration._id;
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('[/integrations.history]', () => {
|
|
before(async () => {
|
|
await Promise.all([updatePermission('manage-incoming-integrations', []), updatePermission('manage-own-incoming-integrations', [])]);
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
]);
|
|
});
|
|
|
|
it('should return an error when trying to get history of incoming integrations if user does NOT have enough permissions', async () => {
|
|
const res = await request
|
|
.get(api('integrations.history'))
|
|
.set(credentials)
|
|
.query({
|
|
id: integration._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(403);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]');
|
|
});
|
|
});
|
|
|
|
describe('[/integrations.list]', () => {
|
|
before((done) => {
|
|
void createUser().then((createdUser) => {
|
|
user = createdUser;
|
|
void login(user.username, password).then((credentials) => {
|
|
userCredentials = credentials;
|
|
void updatePermission('manage-incoming-integrations', ['user']).then(() => {
|
|
void createIntegration(
|
|
{
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test',
|
|
enabled: true,
|
|
alias: 'test',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: true,
|
|
channel: '#general',
|
|
},
|
|
userCredentials,
|
|
).then((integration) => {
|
|
integrationCreatedByAnUser = integration;
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should return the list of incoming integrations', async () => {
|
|
const res = await request.get(api('integrations.list')).set(credentials).expect('Content-Type', 'application/json').expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
const integrationCreatedByAdmin = (res.body.integrations as IIntegration[]).find(
|
|
(createdIntegration) => createdIntegration._id === integration._id,
|
|
);
|
|
assert.isDefined(integrationCreatedByAdmin);
|
|
expect(integrationCreatedByAdmin).to.be.an('object');
|
|
expect(integrationCreatedByAdmin._id).to.be.equal(integration._id);
|
|
expect(res.body).to.have.property('offset');
|
|
expect(res.body).to.have.property('items');
|
|
expect(res.body).to.have.property('total');
|
|
});
|
|
|
|
describe('With manage-own-incoming-integrations permission', () => {
|
|
before(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', []),
|
|
updatePermission('manage-own-incoming-integrations', ['user']),
|
|
]);
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
]);
|
|
});
|
|
|
|
it('should return the list of integrations created by the user only', async () => {
|
|
const res = await request.get(api('integrations.list')).set(userCredentials).expect('Content-Type', 'application/json').expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
const integrationCreatedByAdmin = (res.body.integrations as IIntegration[]).find(
|
|
(createdIntegration) => createdIntegration._id === integration._id,
|
|
);
|
|
expect(integrationCreatedByAdmin).to.be.equal(undefined);
|
|
expect(res.body).to.have.property('offset');
|
|
expect(res.body).to.have.property('items');
|
|
expect(res.body).to.have.property('total');
|
|
});
|
|
});
|
|
|
|
describe('Without any permissions', () => {
|
|
before(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', []),
|
|
updatePermission('manage-own-incoming-integrations', []),
|
|
updatePermission('manage-outgoing-integrations', []),
|
|
updatePermission('manage-own-outgoing-integrations', []),
|
|
]);
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
updatePermission('manage-outgoing-integrations', ['admin']),
|
|
updatePermission('manage-own-outgoing-integrations', ['admin']),
|
|
]);
|
|
});
|
|
|
|
it('should return unauthorized error when the user does not have any integrations permissions', async () => {
|
|
await request
|
|
.get(api('integrations.list'))
|
|
.set(credentials)
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(403)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('[/integrations.get]', () => {
|
|
describe('Invalid params', () => {
|
|
it('should return an error when the required "integrationId" query parameters is not sent', async () => {
|
|
const res = await request.get(api('integrations.get')).set(credentials).expect('Content-Type', 'application/json').expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', `must have required property 'integrationId'`);
|
|
});
|
|
|
|
it('should return an error when the user sends an invalid integration', async () => {
|
|
const res = await request
|
|
.get(api('integrations.get'))
|
|
.query({ integrationId: 'invalid' })
|
|
.set(credentials)
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'The integration does not exists.');
|
|
});
|
|
});
|
|
|
|
describe('Without permissions', () => {
|
|
before(async () => {
|
|
await Promise.all([updatePermission('manage-incoming-integrations', []), updatePermission('manage-own-incoming-integrations', [])]);
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
]);
|
|
});
|
|
|
|
it('should return an error when the user DOES NOT have the permission "manage-incoming-integrations" to get an incoming integration', async () => {
|
|
const res = await request
|
|
.get(api('integrations.get'))
|
|
.query({ integrationId: integration._id })
|
|
.set(credentials)
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'not-authorized');
|
|
});
|
|
|
|
it('should return an error when the user DOES NOT have the permission "manage-incoming-integrations" to get an incoming integration created by another user', async () => {
|
|
const res = await request
|
|
.get(api('integrations.get'))
|
|
.query({ integrationId: integrationCreatedByAnUser._id })
|
|
.set(credentials)
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'not-authorized');
|
|
});
|
|
});
|
|
|
|
describe('With manage-incoming-integrations permission', () => {
|
|
before(async () => {
|
|
await updatePermission('manage-incoming-integrations', ['admin']);
|
|
});
|
|
|
|
it('should return the integration successfully', async () => {
|
|
const res = await request
|
|
.get(api('integrations.get'))
|
|
.query({ integrationId: integration._id })
|
|
.set(credentials)
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration');
|
|
expect(res.body.integration._id).to.be.equal(integration._id);
|
|
});
|
|
});
|
|
|
|
describe('With manage-own-incoming-integrations permission', () => {
|
|
before(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', []),
|
|
updatePermission('manage-own-incoming-integrations', ['user']),
|
|
]);
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
]);
|
|
});
|
|
|
|
it('should return the integration successfully when the user is able to see only your own integrations', async () => {
|
|
const res = await request
|
|
.get(api('integrations.get'))
|
|
.query({ integrationId: integrationCreatedByAnUser._id })
|
|
.set(userCredentials)
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration');
|
|
expect(res.body.integration._id).to.be.equal(integrationCreatedByAnUser._id);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('[/integrations.update]', () => {
|
|
let senderUser: IUser;
|
|
let sendUserCredentials: Credentials;
|
|
|
|
before(async () => {
|
|
await addPermissions({
|
|
'message-impersonate': ['user'],
|
|
});
|
|
senderUser = await createUser();
|
|
sendUserCredentials = await login(senderUser.username, password);
|
|
});
|
|
|
|
after(async () => {
|
|
await addPermissions({
|
|
'message-impersonate': ['bot', 'app'],
|
|
});
|
|
await deleteUser(senderUser);
|
|
});
|
|
|
|
it('should update an integration by id and return the new data', async () => {
|
|
const res = await request
|
|
.put(api('integrations.update'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test updated',
|
|
enabled: true,
|
|
alias: 'test updated',
|
|
username: senderUser.username,
|
|
scriptEnabled: true,
|
|
overrideDestinationChannelEnabled: true,
|
|
channel: '#general',
|
|
integrationId: integration._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration');
|
|
expect(res.body.integration._id).to.be.equal(integration._id);
|
|
expect(res.body.integration.name).to.be.equal('Incoming test updated');
|
|
expect(res.body.integration.alias).to.be.equal('test updated');
|
|
integration = res.body.integration;
|
|
});
|
|
|
|
it('should not allow users without a role with the message-impersonate permission to be assigned to existing incoming integrations', async () => {
|
|
await request
|
|
.put(api('integrations.update'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test update attempt',
|
|
enabled: true,
|
|
alias: 'test update attempt',
|
|
username: 'rocket.cat',
|
|
scriptEnabled: true,
|
|
overrideDestinationChannelEnabled: true,
|
|
channel: '#general',
|
|
integrationId: integration._id,
|
|
})
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property(
|
|
'error',
|
|
"User selected for the incoming integration lacks the 'message-impersonate' permission. [error-user-lacks-message-impersonate-permission]",
|
|
);
|
|
});
|
|
});
|
|
|
|
it('should have integration updated on subsequent gets', async () => {
|
|
const res = await request
|
|
.get(api('integrations.get'))
|
|
.query({ integrationId: integration._id })
|
|
.set(credentials)
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration');
|
|
expect(res.body.integration._id).to.be.equal(integration._id);
|
|
expect(res.body.integration.name).to.be.equal('Incoming test updated');
|
|
expect(res.body.integration.alias).to.be.equal('test updated');
|
|
});
|
|
|
|
it("should update an integration's username and associated userId correctly and return the new data", async () => {
|
|
await request
|
|
.put(api('integrations.update'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test updated x2',
|
|
enabled: true,
|
|
alias: 'test updated x2',
|
|
username: senderUser.username,
|
|
scriptEnabled: true,
|
|
overrideDestinationChannelEnabled: true,
|
|
channel: '#general',
|
|
integrationId: integration._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration');
|
|
expect(res.body.integration._id).to.be.equal(integration._id);
|
|
expect(res.body.integration.name).to.be.equal('Incoming test updated x2');
|
|
expect(res.body.integration.alias).to.be.equal('test updated x2');
|
|
expect(res.body.integration.username).to.be.equal(senderUser.username);
|
|
expect(res.body.integration.userId).to.be.equal(sendUserCredentials['X-User-Id']);
|
|
integration = res.body.integration;
|
|
});
|
|
});
|
|
|
|
it('should send messages to the channel under the updated username', async () => {
|
|
const successfulMessage = `Message sent successfully at #${Random.id()}`;
|
|
await request
|
|
.post(`/hooks/${integration._id}/${integration.token}`)
|
|
.send({
|
|
text: successfulMessage,
|
|
})
|
|
.expect(200);
|
|
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: 'GENERAL',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
const message = (res.body.messages as IMessage[]).find((m) => m.msg === successfulMessage);
|
|
expect(message?.u).have.property('username', senderUser.username);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('[/integrations.remove]', () => {
|
|
describe('Without permissions', () => {
|
|
before(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', []),
|
|
updatePermission('manage-own-incoming-integrations', []),
|
|
updatePermission('manage-outgoing-integrations', []),
|
|
updatePermission('manage-own-outgoing-integrations', []),
|
|
]);
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all([
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
updatePermission('manage-own-incoming-integrations', ['admin']),
|
|
updatePermission('manage-outgoing-integrations', ['admin']),
|
|
updatePermission('manage-own-outgoing-integrations', ['admin']),
|
|
]);
|
|
});
|
|
|
|
it('should return an error when the user DOES NOT have the permission "manage-incoming-integrations" to remove an incoming integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.remove'))
|
|
.set(credentials)
|
|
.send({
|
|
integrationId: integration._id,
|
|
type: 'webhook-incoming',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(403);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]');
|
|
});
|
|
|
|
it('should return an error when the user DOES NOT have the permission "manage-own-incoming-integrations" to remove an incoming integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.remove'))
|
|
.set(credentials)
|
|
.send({
|
|
integrationId: integration._id,
|
|
type: 'webhook-incoming',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(403);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error', 'User does not have the permissions required for this action [error-unauthorized]');
|
|
});
|
|
});
|
|
|
|
describe('Invalid params', () => {
|
|
before(async () => {
|
|
await updatePermission('manage-own-incoming-integrations', ['admin']);
|
|
});
|
|
|
|
it('should return an error when the user sends an invalid type of integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.remove'))
|
|
.set(credentials)
|
|
.send({
|
|
integrationId: integration._id,
|
|
type: 'invalid-type',
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(400);
|
|
|
|
expect(res.body).to.have.property('success', false);
|
|
expect(res.body).to.have.property('error').include(`must match exactly one schema in oneOf`);
|
|
});
|
|
});
|
|
|
|
describe('With manage-incoming-integrations permission', () => {
|
|
before(async () => {
|
|
await updatePermission('manage-incoming-integrations', ['admin']);
|
|
});
|
|
|
|
it('should remove the integration successfully when the user at least one of the necessary permission to remove an incoming integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.remove'))
|
|
.set(credentials)
|
|
.send({
|
|
integrationId: integration._id,
|
|
type: integration.type,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
});
|
|
});
|
|
|
|
describe('Normal user with manage-own-incoming-integrations', () => {
|
|
before(async () => {
|
|
await updatePermission('manage-own-incoming-integrations', ['user']);
|
|
});
|
|
|
|
after(async () => {
|
|
await updatePermission('manage-own-incoming-integrations', ['admin']);
|
|
});
|
|
|
|
it('the normal user should remove the integration successfully when the user have the "manage-own-incoming-integrations" to remove an incoming integration', async () => {
|
|
const res = await request
|
|
.post(api('integrations.remove'))
|
|
.set(userCredentials)
|
|
.send({
|
|
integrationId: integrationCreatedByAnUser._id,
|
|
type: integrationCreatedByAnUser.type,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200);
|
|
|
|
expect(res.body).to.have.property('success', true);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Additional Tests for Message Delivery, Permissions, and Authentication', () => {
|
|
let nonMemberUser: IUser;
|
|
let privateTeam: ITeam;
|
|
let publicChannelInPrivateTeam: IRoom;
|
|
let privateRoom: IRoom;
|
|
let publicRoom: IRoom;
|
|
let integration2: IIntegration;
|
|
let integration3: IIntegration;
|
|
let integration4: IIntegration;
|
|
let integrationMixed1: IIntegration;
|
|
let integrationMixed2: IIntegration;
|
|
|
|
before(async () => {
|
|
nonMemberUser = await createUser({ username: `g_${Random.id()}`, roles: ['bot'] });
|
|
privateTeam = await createTeam(credentials, `private.team.${Random.id()}`, TeamType.PRIVATE);
|
|
await assignRoleToUser({ username: adminUsername, roleId: 'bot' });
|
|
|
|
const [publicInPrivateResponse, privateRoomResponse, publicRoomResponse] = await Promise.all([
|
|
createRoom({
|
|
type: 'c',
|
|
name: `teamPrivate.publicChannel.${Random.id()}`,
|
|
credentials,
|
|
extraData: {
|
|
teamId: privateTeam._id,
|
|
},
|
|
}),
|
|
createRoom({
|
|
type: 'p',
|
|
name: `privateChannel.${Random.id()}`,
|
|
credentials,
|
|
}),
|
|
createRoom({
|
|
type: 'c',
|
|
name: `publicChannel.${Random.id()}`,
|
|
credentials,
|
|
}),
|
|
]);
|
|
|
|
publicChannelInPrivateTeam = publicInPrivateResponse.body.channel;
|
|
privateRoom = privateRoomResponse.body.group;
|
|
publicRoom = publicRoomResponse.body.channel;
|
|
|
|
await updatePermission('manage-incoming-integrations', ['admin']);
|
|
await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test 2 - Sending Messages',
|
|
enabled: true,
|
|
alias: 'Incoming test 2 - Sending Messages',
|
|
username: nonMemberUser.username as string,
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: `#${privateRoom.fname}`,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration').and.to.be.an('object');
|
|
integration2 = res.body.integration;
|
|
});
|
|
|
|
await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test 3 - Sending Messages',
|
|
enabled: true,
|
|
alias: 'Incoming test 3 - Sending Messages',
|
|
username: nonMemberUser.username as string,
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: `#${publicChannelInPrivateTeam.fname}`,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration').and.to.be.an('object');
|
|
integration3 = res.body.integration;
|
|
});
|
|
await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test 4 - Sending Messages',
|
|
enabled: true,
|
|
alias: 'Incoming test 4 - Sending Messages',
|
|
username: nonMemberUser.username as string,
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: `#${publicRoom.fname}`,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration').and.to.be.an('object');
|
|
integration4 = res.body.integration;
|
|
});
|
|
|
|
await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test Mixed - Sending Messages',
|
|
enabled: true,
|
|
alias: 'Incoming test Mixed - Sending Messages',
|
|
username: nonMemberUser.username as string,
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: `#${publicRoom.fname}, #${privateRoom.fname}`,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration').and.to.be.an('object');
|
|
integrationMixed1 = res.body.integration;
|
|
});
|
|
|
|
await request
|
|
.post(api('integrations.create'))
|
|
.set(credentials)
|
|
.send({
|
|
type: 'webhook-incoming',
|
|
name: 'Incoming test Mixed - Sending Messages',
|
|
enabled: true,
|
|
alias: 'Incoming test Mixed - Sending Messages',
|
|
username: adminUsername,
|
|
scriptEnabled: false,
|
|
overrideDestinationChannelEnabled: false,
|
|
channel: `#${publicRoom.fname}, #${privateRoom.fname}`,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('integration').and.to.be.an('object');
|
|
integrationMixed2 = res.body.integration;
|
|
});
|
|
});
|
|
|
|
after(async () => {
|
|
await Promise.all(
|
|
[publicRoom, privateRoom, publicChannelInPrivateTeam].map((room) => deleteRoom({ type: room.t as 'c' | 'p', roomId: room._id })),
|
|
);
|
|
await deleteTeam(credentials, privateTeam.name);
|
|
await deleteUser(nonMemberUser);
|
|
await Promise.all([
|
|
...[integration2, integration3, integration4, integrationMixed1, integrationMixed2].map((integration) =>
|
|
request.post(api('integrations.remove')).set(credentials).send({
|
|
integrationId: integration._id,
|
|
type: integration.type,
|
|
}),
|
|
),
|
|
updatePermission('manage-incoming-integrations', ['admin']),
|
|
]);
|
|
await removeRoleFromUser(adminUsername, 'bot');
|
|
});
|
|
|
|
it('should not send a message in public room if token is invalid', async () => {
|
|
const successfulMessage = `Message sent successfully at #${Random.id()}`;
|
|
await request
|
|
.post(`/hooks/${integration4._id}/invalid-token`)
|
|
.send({
|
|
text: successfulMessage,
|
|
})
|
|
.expect(500)
|
|
.expect((res) => {
|
|
expect(res.text).to.be.equal('Internal Server Error');
|
|
});
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: publicRoom._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === successfulMessage)).to.be.undefined;
|
|
});
|
|
});
|
|
|
|
it('should not send a message in private room if token is invalid', async () => {
|
|
const successfulMessage = `Message sent successfully at #${Random.id()}`;
|
|
await request
|
|
.post(`/hooks/${integration2._id}/invalid-token`)
|
|
.send({
|
|
text: successfulMessage,
|
|
})
|
|
.expect(500)
|
|
.expect((res) => {
|
|
expect(res.text).to.be.equal('Internal Server Error');
|
|
});
|
|
await request
|
|
.get(api('groups.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: privateRoom._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === successfulMessage)).to.be.undefined;
|
|
});
|
|
});
|
|
|
|
it('should not send a message to a private rooms on behalf of a non member', async () => {
|
|
const successfulMessage = `Message sent successfully at #${Random.id()}`;
|
|
await request
|
|
.post(`/hooks/${integration2._id}/${integration2.token}`)
|
|
.send({
|
|
text: successfulMessage,
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('error', 'error-not-allowed');
|
|
});
|
|
await request
|
|
.get(api('groups.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: privateRoom._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === successfulMessage)).to.be.undefined;
|
|
});
|
|
});
|
|
|
|
it('should not add non member to private rooms when sending message', async () => {
|
|
const successfulMessage = `Message sent successfully at #${Random.id()}`;
|
|
await request
|
|
.post(`/hooks/${integration2._id}/${integration2.token}`)
|
|
.send({
|
|
text: successfulMessage,
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('error', 'error-not-allowed');
|
|
});
|
|
await request
|
|
.get(api('groups.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: privateRoom._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('members').and.to.be.an('array');
|
|
expect((res.body.members as AtLeast<IUser, '_id'>[]).find((m) => m._id === nonMemberUser._id)).to.be.undefined;
|
|
});
|
|
});
|
|
|
|
it('should not send a message to public channel of a private team on behalf of a non team member', async () => {
|
|
const successfulMessage = `Message sent successfully at #${Random.id()}`;
|
|
await request
|
|
.post(`/hooks/${integration3._id}/${integration3.token}`)
|
|
.send({
|
|
text: successfulMessage,
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('error', 'error-not-allowed');
|
|
});
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: publicChannelInPrivateTeam._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === successfulMessage)).to.be.undefined;
|
|
});
|
|
});
|
|
|
|
it('should not add non team member to the public channel in a private team when sending message', async () => {
|
|
const successfulMessage = `Message sent successfully at #${Random.id()}`;
|
|
await request
|
|
.post(`/hooks/${integration3._id}/${integration3.token}`)
|
|
.send({
|
|
text: successfulMessage,
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('error', 'error-not-allowed');
|
|
});
|
|
await request
|
|
.get(api('channels.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: publicChannelInPrivateTeam._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('members').and.to.be.an('array');
|
|
expect((res.body.members as AtLeast<IUser, '_id'>[]).find((m) => m._id === nonMemberUser._id)).to.be.undefined;
|
|
});
|
|
});
|
|
|
|
it('should send messages from non-members to public rooms and add them as room members', async () => {
|
|
const successfulMessage = `Message sent successfully at #${Random.id()}`;
|
|
await request
|
|
.post(`/hooks/${integration4._id}/${integration4.token}`)
|
|
.send({
|
|
text: successfulMessage,
|
|
})
|
|
.expect(200);
|
|
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: publicRoom._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === successfulMessage)).not.to.be.undefined;
|
|
});
|
|
|
|
await request
|
|
.get(api('channels.members'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: publicRoom._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('members').and.to.be.an('array');
|
|
expect((res.body.members as AtLeast<IUser, '_id'>[]).find((m) => m._id === nonMemberUser._id)).not.to.be.undefined;
|
|
});
|
|
});
|
|
|
|
describe('Message Settings', async () => {
|
|
const maxSize = 5000;
|
|
before(() => updateSetting('Message_MaxAllowedSize', maxSize));
|
|
after(() => updateSetting('Message_MaxAllowedSize', maxSize));
|
|
|
|
it('should not send a message if message size is greater than the Message_MaxAllowedSize', async () => {
|
|
const largeMesssage = Array.from({ length: maxSize + 1 })
|
|
.map(() => 'A')
|
|
.join('');
|
|
await request
|
|
.post(`/hooks/${integration4._id}/${integration4.token}`)
|
|
.send({
|
|
text: largeMesssage,
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body.error).to.be.equal('error-message-size-exceeded');
|
|
});
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: publicRoom._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === largeMesssage)).to.be.undefined;
|
|
});
|
|
});
|
|
|
|
it('should send a message if message size is less than the Message_MaxAllowedSize', async () => {
|
|
const smallerMessage = Array.from({ length: maxSize - 1 })
|
|
.map(() => 'A')
|
|
.join('');
|
|
await request
|
|
.post(`/hooks/${integration4._id}/${integration4.token}`)
|
|
.send({
|
|
text: smallerMessage,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body.success).to.be.equal(true);
|
|
});
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({
|
|
roomId: publicRoom._id,
|
|
})
|
|
.expect('Content-Type', 'application/json')
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body).to.have.property('messages').and.to.be.an('array');
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === smallerMessage)).to.not.be.undefined;
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Multiple channels delivery', () => {
|
|
it('should not return separate responses when separateResponse is not provided', async () => {
|
|
const testMsg = `msg-${Random.id()}`;
|
|
|
|
await request
|
|
.post(`/hooks/${integrationMixed1._id}/${integrationMixed1.token}`)
|
|
.send({
|
|
text: testMsg,
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body).to.not.have.property('responses');
|
|
});
|
|
});
|
|
|
|
it('should not return separate responses when separateResponse = false', async () => {
|
|
const testMsg = `msg-${Random.id()}`;
|
|
|
|
await request
|
|
.post(`/hooks/${integrationMixed1._id}/${integrationMixed1.token}`)
|
|
.send({
|
|
text: testMsg,
|
|
separateResponse: false,
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body).to.not.have.property('responses');
|
|
});
|
|
});
|
|
|
|
it('should return separate responses when separateResponse = true', async () => {
|
|
const testMsg = `msg-${Random.id()}`;
|
|
|
|
await request
|
|
.post(`/hooks/${integrationMixed1._id}/${integrationMixed1.token}`)
|
|
.send({
|
|
text: testMsg,
|
|
separateResponse: true,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.responses).to.be.an('array').and.to.have.lengthOf(2);
|
|
const publicResponse = res.body.responses.find((r: any) => r.channel === `#${publicRoom.fname}`);
|
|
const privateResponse = res.body.responses.find((r: any) => r.channel === `#${privateRoom.fname}`);
|
|
expect(publicResponse).not.to.have.property('error');
|
|
expect(privateResponse).to.have.property('error');
|
|
});
|
|
});
|
|
|
|
it('should not deliver to any channel if one fails when separateResponse is not provided', async () => {
|
|
const testMsg = `msg-${Random.id()}`;
|
|
await request
|
|
.post(`/hooks/${integrationMixed1._id}/${integrationMixed1.token}`)
|
|
.send({
|
|
text: testMsg,
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('error');
|
|
});
|
|
|
|
await request
|
|
.get(api('groups.messages'))
|
|
.set(credentials)
|
|
.query({ roomId: privateRoom._id })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === testMsg)).to.be.undefined;
|
|
});
|
|
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({ roomId: publicRoom._id })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === testMsg)).to.be.undefined;
|
|
});
|
|
});
|
|
|
|
it('should not deliver to any channel if one fails when separateResponse = false', async () => {
|
|
const testMsg = `msg-${Random.id()}`;
|
|
|
|
await request
|
|
.post(`/hooks/${integrationMixed1._id}/${integrationMixed1.token}`)
|
|
.send({
|
|
text: testMsg,
|
|
separateResponse: false,
|
|
})
|
|
.expect(400)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('error');
|
|
});
|
|
|
|
await request
|
|
.get(api('groups.messages'))
|
|
.set(credentials)
|
|
.query({ roomId: privateRoom._id })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === testMsg)).to.be.undefined;
|
|
});
|
|
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({ roomId: publicRoom._id })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === testMsg)).to.be.undefined;
|
|
});
|
|
});
|
|
|
|
it('should send message to only public channel when separateResponse = true', async () => {
|
|
const testMsg = `msg-${Random.id()}`;
|
|
|
|
await request
|
|
.post(`/hooks/${integrationMixed1._id}/${integrationMixed1.token}`)
|
|
.send({
|
|
text: testMsg,
|
|
separateResponse: true,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
});
|
|
|
|
await request
|
|
.get(api('groups.messages'))
|
|
.set(credentials)
|
|
.query({ roomId: privateRoom._id })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect((res.body.messages as IMessage[]).find((m) => m.msg === testMsg)).to.be.undefined;
|
|
});
|
|
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({ roomId: publicRoom._id })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
const found = (res.body.messages as IMessage[]).filter((m) => m.msg === testMsg);
|
|
expect(found).to.have.lengthOf(1);
|
|
});
|
|
});
|
|
|
|
it('should send messages to all channels when message could be delivered to all channels', async () => {
|
|
const testMsg = `msg-${Random.id()}`;
|
|
|
|
await request
|
|
.post(`/hooks/${integrationMixed2._id}/${integrationMixed2.token}`)
|
|
.send({
|
|
text: testMsg,
|
|
separateResponse: true,
|
|
})
|
|
.expect(200)
|
|
.expect((res) => {
|
|
expect(res.body).to.have.property('success', true);
|
|
expect(res.body.responses).to.be.an('array').and.to.have.lengthOf(2);
|
|
const publicResponse = res.body.responses.find((r: any) => r.channel === `#${publicRoom.fname}`);
|
|
const privateResponse = res.body.responses.find((r: any) => r.channel === `#${privateRoom.fname}`);
|
|
expect(publicResponse).not.to.have.property('error');
|
|
expect(privateResponse).not.to.have.property('error');
|
|
});
|
|
|
|
await request
|
|
.get(api('groups.messages'))
|
|
.set(credentials)
|
|
.query({ roomId: privateRoom._id })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
const found = (res.body.messages as IMessage[]).filter((m) => m.msg === testMsg);
|
|
expect(found).to.have.lengthOf(1);
|
|
});
|
|
|
|
await request
|
|
.get(api('channels.messages'))
|
|
.set(credentials)
|
|
.query({ roomId: publicRoom._id })
|
|
.expect(200)
|
|
.expect((res) => {
|
|
const found = (res.body.messages as IMessage[]).filter((m) => m.msg === testMsg);
|
|
expect(found).to.have.lengthOf(1);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|