diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index 178c455ea1e..ee6840338c4 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -590,6 +590,7 @@ "Integration_Outgoing_WebHook": "Outgoing WebHook Integration", "Integration_updated": "Integration has been updated", "Integrations": "Integrations", + "Integrations_for_all_channels": "Enter all_public_channels to listen on all public channels, all_private_groups to listen on all private groups, and all_direct_messages to listen to all direct messages.", "InternalHubot": "Internal Hubot", "InternalHubot_ScriptsToLoad": "Scripts to load", "InternalHubot_ScriptsToLoad_Description": "Please enter a comma separated list of scripts to load from https://github.com/github/hubot-scripts/tree/master/src/scripts", @@ -1424,4 +1425,4 @@ "your_message_optional": "your message (optional)", "Your_password_is_wrong": "Your password is wrong!", "Your_push_was_sent_to_s_devices": "Your push was sent to %s devices" -} \ No newline at end of file +} diff --git a/packages/rocketchat-integrations/client/views/integrationsOutgoing.html b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html index 4d7bca6929e..49e8dc1f56a 100644 --- a/packages/rocketchat-integrations/client/views/integrationsOutgoing.html +++ b/packages/rocketchat-integrations/client/views/integrationsOutgoing.html @@ -25,7 +25,7 @@
{{_ "Optional channel to listen on"}}
{{{_ "Start_with_s_for_user_or_s_for_channel_Eg_s_or_s" "@" "#" "@john" "#general"}}}
-
{{{_ "Leave empty to listen any public channel"}}}
+
{{{_ "Integrations_for_all_channels"}}}
diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js index 39251305cbe..eee59622436 100644 --- a/packages/rocketchat-integrations/package.js +++ b/packages/rocketchat-integrations/package.js @@ -41,6 +41,7 @@ Package.onUse(function(api) { api.addFiles('client/stylesheets/load.coffee', 'server'); api.addFiles('server/logger.js', 'server'); + api.addFiles('server/lib/validation.coffee', 'server'); api.addFiles('server/models/Integrations.coffee', 'server'); diff --git a/packages/rocketchat-integrations/server/lib/validation.coffee b/packages/rocketchat-integrations/server/lib/validation.coffee new file mode 100644 index 00000000000..a9ac119e268 --- /dev/null +++ b/packages/rocketchat-integrations/server/lib/validation.coffee @@ -0,0 +1,90 @@ +RocketChat.integrations.validateOutgoing = (integration, userId) -> + if integration.channel?.trim? and integration.channel.trim() is '' + delete integration.channel + + if integration.username.trim() is '' + throw new Meteor.Error 'error-invalid-username', 'Invalid username', { method: 'addOutgoingIntegration' } + + if not Match.test integration.urls, [String] + throw new Meteor.Error 'error-invalid-urls', 'Invalid URLs', { method: 'addOutgoingIntegration' } + + for url, index in integration.urls + delete integration.urls[index] if url.trim() is '' + + integration.urls = _.without integration.urls, [undefined] + + if integration.urls.length is 0 + throw new Meteor.Error 'error-invalid-urls', 'Invalid URLs', { method: 'addOutgoingIntegration' } + + channels = if integration.channel then _.map(integration.channel.split(','), (channel) -> s.trim(channel)) else [] + + scopedChannels = ['all_public_channels', 'all_private_groups', 'all_direct_messages'] + for channel in channels + if channel[0] not in ['@', '#'] and channel not in scopedChannels + throw new Meteor.Error 'error-invalid-channel-start-with-chars', 'Invalid channel. Start with @ or #', { method: 'updateIncomingIntegration' } + + if integration.triggerWords? + if not Match.test integration.triggerWords, [String] + throw new Meteor.Error 'error-invalid-triggerWords', 'Invalid triggerWords', { method: 'addOutgoingIntegration' } + + for triggerWord, index in integration.triggerWords + delete integration.triggerWords[index] if triggerWord.trim() is '' + + integration.triggerWords = _.without integration.triggerWords, [undefined] + + if integration.scriptEnabled is true and integration.script? and integration.script.trim() isnt '' + try + babelOptions = Babel.getDefaultOptions({ runtime: false }) + babelOptions = _.extend(babelOptions, { compact: true, minified: true, comments: false }) + + integration.scriptCompiled = Babel.compile(integration.script, babelOptions).code + integration.scriptError = undefined + catch e + integration.scriptCompiled = undefined + integration.scriptError = _.pick e, 'name', 'message', 'stack' + + + for channel in channels + if channel in scopedChannels + if channel is 'all_public_channels' + #No special permissions needed to add integration to public channels + else if not RocketChat.authz.hasPermission userId, 'manage-integrations' + throw new Meteor.Error 'error-invalid-channel', 'Invalid Channel', { method: 'addOutgoingIntegration' } + else + record = undefined + channelType = channel[0] + channel = channel.substr(1) + + switch channelType + when '#' + record = RocketChat.models.Rooms.findOne + $or: [ + {_id: channel} + {name: channel} + ] + when '@' + record = RocketChat.models.Users.findOne + $or: [ + {_id: channel} + {username: channel} + ] + + if record is undefined + throw new Meteor.Error 'error-invalid-room', 'Invalid room', { method: 'addOutgoingIntegration' } + + if record.usernames? and + (not RocketChat.authz.hasPermission userId, 'manage-integrations') and + (RocketChat.authz.hasPermission userId, 'manage-own-integrations') and + Meteor.user()?.username not in record.usernames + throw new Meteor.Error 'error-invalid-channel', 'Invalid Channel', { method: 'addOutgoingIntegration' } + + user = RocketChat.models.Users.findOne({username: integration.username}) + + if not user? + throw new Meteor.Error 'error-invalid-user', 'Invalid user', { method: 'addOutgoingIntegration' } + + integration.type = 'webhook-outgoing' + integration.userId = user._id + integration.channel = channels + + return integration diff --git a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee index 90e9860285c..af42d9bb291 100644 --- a/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/outgoing/addOutgoingIntegration.coffee @@ -1,7 +1,5 @@ Meteor.methods addOutgoingIntegration: (integration) -> - if integration.channel?.trim? and integration.channel.trim() is '' - delete integration.channel if (not RocketChat.authz.hasPermission @userId, 'manage-integrations') and not (RocketChat.authz.hasPermission @userId, 'manage-own-integrations') and @@ -9,82 +7,8 @@ Meteor.methods not (RocketChat.authz.hasPermission @userId, 'manage-own-integrations', 'bot') throw new Meteor.Error 'not_authorized' - if integration.username.trim() is '' - throw new Meteor.Error 'error-invalid-username', 'Invalid username', { method: 'addOutgoingIntegration' } + integration = RocketChat.integrations.validateOutgoing(integration, @userId) - if not Match.test integration.urls, [String] - throw new Meteor.Error 'error-invalid-urls', 'Invalid URLs', { method: 'addOutgoingIntegration' } - - for url, index in integration.urls - delete integration.urls[index] if url.trim() is '' - - integration.urls = _.without integration.urls, [undefined] - - if integration.urls.length is 0 - throw new Meteor.Error 'error-invalid-urls', 'Invalid URLs', { method: 'addOutgoingIntegration' } - - channels = if integration.channel then _.map(integration.channel.split(','), (channel) -> s.trim(channel)) else [] - - for channel in channels - if channel[0] not in ['@', '#'] - throw new Meteor.Error 'error-invalid-channel-start-with-chars', 'Invalid channel. Start with @ or #', { method: 'updateIncomingIntegration' } - - if integration.triggerWords? - if not Match.test integration.triggerWords, [String] - throw new Meteor.Error 'error-invalid-triggerWords', 'Invalid triggerWords', { method: 'addOutgoingIntegration' } - - for triggerWord, index in integration.triggerWords - delete integration.triggerWords[index] if triggerWord.trim() is '' - - integration.triggerWords = _.without integration.triggerWords, [undefined] - - if integration.scriptEnabled is true and integration.script? and integration.script.trim() isnt '' - try - babelOptions = Babel.getDefaultOptions({ runtime: false }) - babelOptions = _.extend(babelOptions, { compact: true, minified: true, comments: false }) - - integration.scriptCompiled = Babel.compile(integration.script, babelOptions).code - integration.scriptError = undefined - catch e - integration.scriptCompiled = undefined - integration.scriptError = _.pick e, 'name', 'message', 'stack' - - - for channel in channels - record = undefined - channelType = channel[0] - channel = channel.substr(1) - - switch channelType - when '#' - record = RocketChat.models.Rooms.findOne - $or: [ - {_id: channel} - {name: channel} - ] - when '@' - record = RocketChat.models.Users.findOne - $or: [ - {_id: channel} - {username: channel} - ] - - if record is undefined - throw new Meteor.Error 'error-invalid-room', 'Invalid room', { method: 'addOutgoingIntegration' } - - if record.usernames? and - (not RocketChat.authz.hasPermission @userId, 'manage-integrations') and - (RocketChat.authz.hasPermission @userId, 'manage-own-integrations') and - Meteor.user()?.username not in record.usernames - throw new Meteor.Error 'error-invalid-channel', 'Invalid Channel', { method: 'addOutgoingIntegration' } - - user = RocketChat.models.Users.findOne({username: integration.username}) - - if not user? - throw new Meteor.Error 'error-invalid-user', 'Invalid user', { method: 'addOutgoingIntegration' } - - integration.type = 'webhook-outgoing' - integration.userId = user._id integration._createdAt = new Date integration._createdBy = RocketChat.models.Users.findOne @userId, {fields: {username: 1}} diff --git a/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee b/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee index c1bc0c2aca8..d9db71a1484 100644 --- a/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee +++ b/packages/rocketchat-integrations/server/methods/outgoing/updateOutgoingIntegration.coffee @@ -1,43 +1,10 @@ Meteor.methods updateOutgoingIntegration: (integrationId, integration) -> - - if integration.username.trim() is '' - throw new Meteor.Error 'error-invalid-username', 'Invalid username', { method: 'updateOutgoingIntegration' } - - if not Match.test integration.urls, [String] - throw new Meteor.Error 'error-invalid-urls', 'Invalid URLs', { method: 'updateOutgoingIntegration' } - - for url, index in integration.urls - delete integration.urls[index] if url.trim() is '' - - integration.urls = _.without integration.urls, [undefined] - - if integration.urls.length is 0 - throw new Meteor.Error 'error-invalid-urls', 'Invalid URLs', { method: 'updateOutgoingIntegration' } - - if _.isString(integration.channel) - integration.channel = integration.channel.trim() - else - integration.channel = undefined - - channels = if integration.channel then _.map(integration.channel.split(','), (channel) -> s.trim(channel)) else [] - - for channel in channels - if channel[0] not in ['@', '#'] - throw new Meteor.Error 'error-invalid-channel-start-with-chars', 'Invalid channel. Start with @ or #', { method: 'updateIncomingIntegration' } + integration = RocketChat.integrations.validateOutgoing(integration, @userId) if not integration.token? or integration.token?.trim() is '' throw new Meteor.Error 'error-invalid-token', 'Invalid token', { method: 'updateOutgoingIntegration' } - if integration.triggerWords? - if not Match.test integration.triggerWords, [String] - throw new Meteor.Error 'error-invalid-triggerWords', 'Invalid triggerWords', { method: 'updateOutgoingIntegration' } - - for triggerWord, index in integration.triggerWords - delete integration.triggerWords[index] if triggerWord.trim() is '' - - integration.triggerWords = _.without integration.triggerWords, [undefined] - currentIntegration = null if RocketChat.authz.hasPermission @userId, 'manage-integrations' @@ -50,50 +17,6 @@ Meteor.methods if not currentIntegration? throw new Meteor.Error 'invalid_integration', '[methods] updateOutgoingIntegration -> integration not found' - if integration.scriptEnabled is true and integration.script? and integration.script.trim() isnt '' - try - babelOptions = Babel.getDefaultOptions({ runtime: false }) - babelOptions = _.extend(babelOptions, { compact: true, minified: true, comments: false }) - - integration.scriptCompiled = Babel.compile(integration.script, babelOptions).code - integration.scriptError = undefined - catch e - integration.scriptCompiled = undefined - integration.scriptError = _.pick e, 'name', 'message', 'stack', - - - for channel in channels - record = undefined - channelType = channel[0] - channel = channel.substr(1) - - switch channelType - when '#' - record = RocketChat.models.Rooms.findOne - $or: [ - {_id: channel} - {name: channel} - ] - when '@' - record = RocketChat.models.Users.findOne - $or: [ - {_id: channel} - {username: channel} - ] - - if record is undefined - throw new Meteor.Error 'error-invalid-room', 'Invalid room', { method: 'updateOutgoingIntegration' } - - if record.usernames? and - (not RocketChat.authz.hasPermission @userId, 'manage-integrations') and - (RocketChat.authz.hasPermission @userId, 'manage-own-integrations') and - Meteor.user()?.username not in record.usernames - throw new Meteor.Error 'error-invalid-channel', 'Invalid Channel', { method: 'updateOutgoingIntegration' } - - user = RocketChat.models.Users.findOne({username: integration.username}) - - if not user? - throw new Meteor.Error 'error-invalid-user', 'Invalid user', { method: 'updateOutgoingIntegration' } RocketChat.models.Integrations.update integrationId, $set: @@ -102,9 +25,9 @@ Meteor.methods avatar: integration.avatar emoji: integration.emoji alias: integration.alias - channel: channels + channel: integration.channel username: integration.username - userId: user._id + userId: integration.userId urls: integration.urls token: integration.token script: integration.script diff --git a/packages/rocketchat-integrations/server/triggers.coffee b/packages/rocketchat-integrations/server/triggers.coffee index 625bbad822b..5ea52c66696 100644 --- a/packages/rocketchat-integrations/server/triggers.coffee +++ b/packages/rocketchat-integrations/server/triggers.coffee @@ -278,6 +278,9 @@ ExecuteTriggers = (message, room) -> if triggers['@'+id]? triggersToExecute.push trigger for key, trigger of triggers['@'+id] + if triggers.all_direct_messages? + triggersToExecute.push trigger for key, trigger of triggers.all_direct_messages + if id isnt username and triggers['@'+username]? triggersToExecute.push trigger for key, trigger of triggers['@'+username] @@ -285,6 +288,9 @@ ExecuteTriggers = (message, room) -> if triggers.__any? triggersToExecute.push trigger for key, trigger of triggers.__any + if triggers.all_public_channels? + triggersToExecute.push trigger for key, trigger of triggers.all_public_channels + if triggers['#'+room._id]? triggersToExecute.push trigger for key, trigger of triggers['#'+room._id] @@ -292,6 +298,9 @@ ExecuteTriggers = (message, room) -> triggersToExecute.push trigger for key, trigger of triggers['#'+room.name] else + if triggers.all_private_groups? + triggersToExecute.push trigger for key, trigger of triggers.all_private_groups + if triggers['#'+room._id]? triggersToExecute.push trigger for key, trigger of triggers['#'+room._id]