Fix a few issues related to the integrations.

1. process_incoming_request can now return falsey (null, undefined, 0, false, etc) and nothing will be sent to the channel
2. integrations can post messages to channels without the user being in them (direct messages, etc)
3. users can't brute force check if a room exists by successfully sending a message there
pull/7793/head
Bradley Hilton 8 years ago
parent 25792e619b
commit ae3f82183d
No known key found for this signature in database
GPG Key ID: 0666B2C24C43C358
  1. 2
      packages/rocketchat-api/server/v1/chat.js
  2. 42
      packages/rocketchat-integrations/server/api/api.js
  3. 7
      packages/rocketchat-integrations/server/processWebhookMessage.js

@ -73,7 +73,7 @@ RocketChat.API.v1.addRoute('chat.pinMessage', { authRequired: true }, {
RocketChat.API.v1.addRoute('chat.postMessage', { authRequired: true }, {
post() {
const messageReturn = processWebhookMessage(this.bodyParams, this.user)[0];
const messageReturn = processWebhookMessage(this.bodyParams, this.user, undefined, true)[0];
if (!messageReturn) {
return RocketChat.API.v1.failure('unknown-error');

@ -158,18 +158,21 @@ function executeIntegrationRest() {
logger.incoming.info('Post integration:', this.integration.name);
logger.incoming.debug('@urlParams:', this.urlParams);
logger.incoming.debug('@bodyParams:', this.bodyParams);
if (this.integration.enabled !== true) {
return {
statusCode: 503,
body: 'Service Unavailable'
};
}
const defaultValues = {
channel: this.integration.channel,
alias: this.integration.alias,
avatar: this.integration.avatar,
emoji: this.integration.emoji
};
if (this.integration.scriptEnabled === true && this.integration.scriptCompiled && this.integration.scriptCompiled.trim() !== '') {
let script;
try {
@ -178,6 +181,7 @@ function executeIntegrationRest() {
logger.incoming.warn(e);
return RocketChat.API.v1.failure(e.message);
}
const request = {
url: {
hash: this.request._parsedUrl.hash,
@ -197,23 +201,29 @@ function executeIntegrationRest() {
username: this.user.username
}
};
try {
const {sandbox} = buildSandbox(compiledScripts[this.integration._id].store);
const { sandbox } = buildSandbox(compiledScripts[this.integration._id].store);
sandbox.script = script;
sandbox.request = request;
const result = vm.runInNewContext('script.process_incoming_request({ request: request })', sandbox, {
timeout: 3000
});
if (result && result.error) {
if (!result) {
logger.incoming.debug('[Process Incoming Request result of Trigger', this.integration.name, ':] No data');
return RocketChat.API.v1.success();
} else if (result && result.error) {
return RocketChat.API.v1.failure(result.error);
}
this.bodyParams = result && result.content;
if (typeof result !== 'undefined') {
this.scriptResponse = result.response;
if (result.user) {
this.user = result.user;
}
this.scriptResponse = result.response;
if (result.user) {
this.user = result.user;
}
logger.incoming.debug('[Process Incoming Request result of Trigger', this.integration.name, ':]');
logger.incoming.debug('result', this.bodyParams);
} catch ({stack}) {
@ -224,22 +234,28 @@ function executeIntegrationRest() {
return RocketChat.API.v1.failure('error-running-script');
}
}
if (this.bodyParams == null) {
return RocketChat.API.v1.failure('body-empty');
// TODO: Turn this into an option on the integrations - no body means a success
// TODO: Temporary fix for https://github.com/RocketChat/Rocket.Chat/issues/7770 until the above is implemented
if (!this.bodyParams) {
// return RocketChat.API.v1.failure('body-empty');
return RocketChat.API.v1.success();
}
this.bodyParams.bot = {
i: this.integration._id
};
this.bodyParams.bot = { i: this.integration._id };
try {
const message = processWebhookMessage(this.bodyParams, this.user, defaultValues);
if (_.isEmpty(message)) {
return RocketChat.API.v1.failure('unknown-error');
}
if (this.scriptResponse) {
logger.incoming.debug('response', this.scriptResponse);
}
return RocketChat.API.v1.success(this.scriptResponse);
} catch ({error}) {
} catch ({ error }) {
return RocketChat.API.v1.failure(error);
}
}

@ -1,4 +1,4 @@
this.processWebhookMessage = function(messageObj, user, defaultValues = { channel: '', alias: '', avatar: '', emoji: '' }) {
this.processWebhookMessage = function(messageObj, user, defaultValues = { channel: '', alias: '', avatar: '', emoji: '' }, mustBeJoined = false) {
const sentData = [];
const channels = [].concat(messageObj.channel || messageObj.roomId || defaultValues.channel);
@ -34,6 +34,11 @@ this.processWebhookMessage = function(messageObj, user, defaultValues = { channe
throw new Meteor.Error('invalid-channel');
}
if (mustBeJoined && !room.usernames.includes(user.username)) {
// throw new Meteor.Error('invalid-room', 'Invalid room provided to send a message to, must be joined.');
throw new Meteor.Error('invalid-channel'); // Throwing the generic one so people can't "brute force" find rooms
}
if (messageObj.attachments && !_.isArray(messageObj.attachments)) {
console.log('Attachments should be Array, ignoring value'.red, messageObj.attachments);
messageObj.attachments = undefined;

Loading…
Cancel
Save