From c903f1449d583e5718252c5ae5a1905107a58611 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Wed, 22 Mar 2017 11:10:46 -0300 Subject: [PATCH 1/2] Allow access to the models within integrations and fix a few issues with incoming webhooks --- packages/rocketchat-i18n/i18n/en.i18n.json | 2 +- .../server/api/api.coffee | 72 ++++++++++--------- .../server/lib/triggerHandler.js | 49 ++++++------- 3 files changed, 59 insertions(+), 64 deletions(-) diff --git a/packages/rocketchat-i18n/i18n/en.i18n.json b/packages/rocketchat-i18n/i18n/en.i18n.json index e08f9931ad8c..733b6dfa4ae8 100644 --- a/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/packages/rocketchat-i18n/i18n/en.i18n.json @@ -1668,4 +1668,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/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 3ad1abdb43bf..83f455b7d1d4 100644 --- a/packages/rocketchat-integrations/server/api/api.coffee +++ b/packages/rocketchat-integrations/server/api/api.coffee @@ -1,18 +1,14 @@ vm = Npm.require('vm') +moment = require('moment') compiledScripts = {} -getIntegrationScript = (integration) -> - compiledScript = compiledScripts[integration._id] - if compiledScript? and +compiledScript._updatedAt is +integration._updatedAt - return compiledScript.script - - script = integration.scriptCompiled - vmScript = undefined +buildSandbox = (store = {}) -> sandbox = _: _ s: s - console: console + console: console, + moment: moment, Store: set: (key, val) -> return store[key] = val @@ -26,17 +22,36 @@ getIntegrationScript = (integration) -> return {} = error: e + Object.keys(RocketChat.models).filter((k) -> + return !k.startsWith('_') + ).forEach (k) => + sandbox[k] = RocketChat.models[k] + + return {} = + store: store, + sandbox: sandbox + +getIntegrationScript = (integration) -> + compiledScript = compiledScripts[integration._id] + if compiledScript? and +compiledScript._updatedAt is +integration._updatedAt + return compiledScript.script + + script = integration.scriptCompiled + vmScript = undefined + sandboxItems = buildSandbox() + try logger.incoming.info 'Will evaluate script of Trigger', integration.name logger.incoming.debug script vmScript = vm.createScript script, 'script.js' - vmScript.runInNewContext sandbox + vmScript.runInNewContext sandboxItems.sandbox - if sandbox.Script? + if sandboxItems.sandbox.Script? compiledScripts[integration._id] = - script: new sandbox.Script() + script: new sandboxItems.sandbox.Script() + store: sandboxItems.store _updatedAt: integration._updatedAt return compiledScripts[integration._id].script @@ -47,7 +62,7 @@ getIntegrationScript = (integration) -> logger.incoming.error e.stack.replace(/^/gm, ' ') throw RocketChat.API.v1.failure 'error-evaluating-script' - if not sandbox.Script? + if not sandboxItems.sandbox.Script? logger.incoming.error '[Class "Script" not in Trigger', integration.name, ']' throw RocketChat.API.v1.failure 'class-script-not-found' @@ -133,9 +148,9 @@ removeIntegration = (options, user) -> executeIntegrationRest = -> - logger.incoming.info 'Post integration', @integration.name - logger.incoming.debug '@urlParams', @urlParams - logger.incoming.debug '@bodyParams', @bodyParams + logger.incoming.info 'Post integration:', @integration.name + logger.incoming.debug '@urlParams:', @urlParams + logger.incoming.debug '@bodyParams:', @bodyParams if @integration.enabled isnt true return {} = @@ -148,13 +163,13 @@ executeIntegrationRest = -> avatar: @integration.avatar emoji: @integration.emoji - if @integration.scriptEnabled is true and @integration.scriptCompiled? and @integration.scriptCompiled.trim() isnt '' script = undefined try script = getIntegrationScript(@integration) catch e - return e + logger.incoming.warn e + return RocketChat.API.v1.failure e.message request = url: @@ -174,24 +189,11 @@ executeIntegrationRest = -> username: @user.username try - sandbox = - _: _ - s: s - console: console - Store: - set: (key, val) -> - return store[key] = val - get: (key) -> - return store[key] - HTTP: (method, url, options) -> - try - return {} = - result: HTTP.call method, url, options - catch e - return {} = - error: e - script: script - request: request + sandboxItems = buildSandbox(compiledScripts[@integration._id].store) + sandbox = sandboxItems.sandbox + sandbox.script = script + sandbox.request = request + result = vm.runInNewContext('script.process_incoming_request({ request: request })', sandbox, { timeout: 3000 }) if result?.error? diff --git a/packages/rocketchat-integrations/server/lib/triggerHandler.js b/packages/rocketchat-integrations/server/lib/triggerHandler.js index eb23f982f86d..68c2fc24c608 100644 --- a/packages/rocketchat-integrations/server/lib/triggerHandler.js +++ b/packages/rocketchat-integrations/server/lib/triggerHandler.js @@ -187,14 +187,7 @@ RocketChat.integrations.triggerHandler = new class RocketChatIntegrationHandler return message; } - getIntegrationScript(integration) { - const compiledScript = this.compiledScripts[integration._id]; - if (compiledScript && +compiledScript._updatedAt === +integration._updatedAt) { - return compiledScript.script; - } - - const script = integration.scriptCompiled; - const store = {}; + buildSandbox(store = {}) { const sandbox = { _, s, console, moment, Store: { @@ -212,6 +205,22 @@ RocketChat.integrations.triggerHandler = new class RocketChatIntegrationHandler } }; + Object.keys(RocketChat.models).filter(k => !k.startsWith('_')).forEach(k => { + sandbox[k] = RocketChat.models[k]; + }); + + return { store, sandbox }; + } + + getIntegrationScript(integration) { + const compiledScript = this.compiledScripts[integration._id]; + if (compiledScript && +compiledScript._updatedAt === +integration._updatedAt) { + return compiledScript.script; + } + + const script = integration.scriptCompiled; + const { store, sandbox } = this.buildSandbox(); + let vmScript; try { logger.outgoing.info('Will evaluate script of Trigger', integration.name); @@ -275,26 +284,10 @@ RocketChat.integrations.triggerHandler = new class RocketChatIntegrationHandler } try { - const store = this.compiledScripts[integration._id].store; - const sandbox = { - _, s, console, moment, - Store: { - set: (key, val) => store[key] = val, - get: (key) => store[key] - }, - HTTP: (method, url, options) => { - try { - return { - result: HTTP.call(method, url, options) - }; - } catch (error) { - return { error }; - } - }, - script, - method, - params - }; + const { sandbox } = this.buildSandbox(this.compiledScripts[integration._id].store); + sandbox.script = script; + sandbox.method = method; + sandbox.params = params; this.updateHistory({ historyId, step: `execute-script-before-running-${method}` }); const result = this.vm.runInNewContext('script[method](params)', sandbox, { timeout: 3000 }); From 4897f5b5f56ff71d243fe008b99190f863acae19 Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Wed, 22 Mar 2017 11:17:27 -0300 Subject: [PATCH 2/2] Update the history file to reflect the changes to the integrations --- HISTORY.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/HISTORY.md b/HISTORY.md index 1376ac6e2870..789893a9e609 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,10 @@ # History +## NEXT + +- [NEW] Integrations, both incoming and outgoing, now have access to the models. Example: `Users.findOneById(id)` (#6336) +- [FIX] Incoming integrations would break when trying to use the `Store` feature. + ## 0.53.0 - 2017-Mar-01 - Add 'Unread Messages' to i18n translation files