From a2c853c5e98800a59672ba7e73896501f7419f7b Mon Sep 17 00:00:00 2001 From: Bradley Hilton Date: Thu, 23 Mar 2017 18:08:02 -0300 Subject: [PATCH] Rocket models in webhooks (#6420) * Allow access to the models within integrations and fix a few issues with incoming webhooks * Update the history file to reflect the changes to the integrations --- HISTORY.md | 3 + .../server/api/api.coffee | 72 ++++++++++--------- .../server/lib/triggerHandler.js | 49 ++++++------- 3 files changed, 61 insertions(+), 63 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index af7537c30ca..4b2f33cc530 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,6 +2,9 @@ ## 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.54.1 - 2017-Mar-23 - [FIX] Images on attachments were not loading except for uploaded files. diff --git a/packages/rocketchat-integrations/server/api/api.coffee b/packages/rocketchat-integrations/server/api/api.coffee index 3ad1abdb43b..83f455b7d1d 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 eb23f982f86..68c2fc24c60 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 });