botium-core 1.13.19 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/botium-cjs.js +298 -382
  2. package/dist/botium-cjs.js.map +1 -1
  3. package/dist/botium-es.js +298 -380
  4. package/dist/botium-es.js.map +1 -1
  5. package/package.json +20 -25
  6. package/samples/extensions/asserterHooks/botium.json +1 -0
  7. package/samples/extensions/logichooks/botium.json +1 -0
  8. package/samples/extensions/logichooks/custom/MyAsserter.js +3 -3
  9. package/src/Capabilities.js +2 -1
  10. package/src/containers/PluginConnectorContainer.js +8 -0
  11. package/src/containers/plugins/SimpleRestContainer.js +17 -9
  12. package/src/containers/plugins/index.js +29 -41
  13. package/src/helpers/HookUtils.js +32 -68
  14. package/src/scripting/ScriptingMemory.js +0 -24
  15. package/src/scripting/logichook/LogicHookUtils.js +27 -47
  16. package/test/compiler/precompilerscript.spec.js +24 -26
  17. package/test/connectors/pluginconnectorcontainer.spec.js +60 -0
  18. package/test/connectors/simplerest.spec.js +24 -27
  19. package/test/convo/fillAndApplyScriptingMemory.spec.js +1 -47
  20. package/test/hooks/customhooks.spec.js +3 -25
  21. package/test/logichooks/hookfromsrc.spec.js +13 -3
  22. package/test/plugins/plugins.spec.js +29 -2
  23. package/test/security/allowUnsafe.spec.js +20 -129
  24. package/LICENSES-3RDPARTY.txt +0 -6450
  25. package/test/scripting/asserters/convos/customembeddedasserterwithhugo.convo.txt +0 -7
  26. package/test/scripting/asserters/convos/customembeddedasserterwithouthugo.convo.txt +0 -7
  27. package/test/scripting/asserters/customEmbeddedAsserter.json +0 -14
  28. package/test/scripting/asserters/customEmbeddedAsserter.spec.js +0 -55
  29. package/test/scripting/logichooks/convos/custom_embedded.convo.txt +0 -8
  30. package/test/scripting/logichooks/customEmbedded.json +0 -14
  31. package/test/scripting/logichooks/customEmbedded.spec.js +0 -44
  32. package/test/security/convos/withscriptingmemoryfunction.convo.txt +0 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botium-core",
3
- "version": "1.13.19",
3
+ "version": "1.14.0",
4
4
  "description": "The Selenium for Chatbots",
5
5
  "main": "index.js",
6
6
  "module": "dist/botium-es.js",
@@ -18,7 +18,6 @@
18
18
  "link": "npm link botium-connector-dialogflow botium-connector-webdriverio botium-connector-directline3 botium-connector-watson botium-connector-alexa-smapi botium-connector-echo",
19
19
  "test": "cross-env NODE_PATH=\"./test/plugins/plugindir/fromfolder:./test/plugins/plugindir/fromfile:./test/security/resources\" mocha \"./test/**/*.spec.js\"",
20
20
  "coverage:report": "nyc report --reporter=lcov npm test",
21
- "license-checker": "license-checker > LICENSES-3RDPARTY.txt",
22
21
  "update-dependencies": "npm-check-updates --reject globby,rollup -u --timeout 120000"
23
22
  },
24
23
  "repository": {
@@ -32,14 +31,13 @@
32
31
  },
33
32
  "homepage": "https://www.botium.ai",
34
33
  "dependencies": {
35
- "@babel/runtime": "^7.21.5",
34
+ "@babel/runtime": "^7.22.15",
36
35
  "async": "^3.2.4",
37
36
  "body-parser": "^1.20.2",
38
37
  "boolean": "^3.2.0",
39
38
  "bottleneck": "^2.19.5",
40
- "csv-parse": "^5.3.10",
39
+ "csv-parse": "^5.5.0",
41
40
  "debug": "^4.3.4",
42
- "esprima": "^4.0.1",
43
41
  "express": "^4.18.2",
44
42
  "globby": "11.0.4",
45
43
  "ioredis": "^5.3.2",
@@ -54,45 +52,42 @@
54
52
  "moment-timezone": "^0.5.43",
55
53
  "mustache": "^4.2.0",
56
54
  "promise-retry": "^2.0.1",
57
- "promise.allsettled": "^1.0.6",
55
+ "promise.allsettled": "^1.0.7",
58
56
  "randomatic": "^3.1.1",
59
57
  "request": "^2.88.2",
60
- "rimraf": "^5.0.0",
58
+ "rimraf": "^5.0.1",
61
59
  "sanitize-filename": "^1.6.3",
62
60
  "slugify": "^1.6.6",
63
- "socket.io": "^4.6.1",
64
- "socket.io-client": "^4.6.1",
61
+ "socket.io": "^4.7.2",
62
+ "socket.io-client": "^4.7.2",
65
63
  "socketio-auth": "^0.1.1",
66
64
  "swagger-jsdoc": "^6.2.8",
67
- "swagger-ui-express": "^4.6.3",
65
+ "swagger-ui-express": "^5.0.0",
68
66
  "uuid": "^9.0.0",
69
- "vm2": "^3.9.17",
70
67
  "word-error-rate": "0.0.7",
71
68
  "write-yaml": "^1.0.0",
72
69
  "xlsx": "^0.18.5",
73
70
  "xregexp": "^5.1.1",
74
- "yaml": "^2.2.2"
71
+ "yaml": "^2.3.2"
75
72
  },
76
73
  "devDependencies": {
77
- "@babel/core": "^7.21.8",
78
- "@babel/node": "^7.20.7",
79
- "@babel/plugin-transform-runtime": "^7.21.4",
80
- "@babel/preset-env": "^7.21.5",
81
- "chai": "^4.3.7",
74
+ "@babel/core": "^7.22.17",
75
+ "@babel/node": "^7.22.15",
76
+ "@babel/plugin-transform-runtime": "^7.22.15",
77
+ "@babel/preset-env": "^7.22.15",
78
+ "chai": "^4.3.8",
82
79
  "chai-as-promised": "^7.1.1",
83
80
  "cross-env": "^7.0.3",
84
- "eslint": "^8.40.0",
85
- "eslint-config-standard": "^17.0.0",
86
- "eslint-plugin-import": "^2.27.5",
81
+ "eslint": "^8.49.0",
82
+ "eslint-config-standard": "^17.1.0",
83
+ "eslint-plugin-import": "^2.28.1",
87
84
  "eslint-plugin-mocha": "^10.1.0",
88
- "eslint-plugin-n": "^15.7.0",
85
+ "eslint-plugin-n": "^16.1.0",
89
86
  "eslint-plugin-promise": "^6.1.1",
90
87
  "eslint-plugin-standard": "^4.1.0",
91
- "license-checker": "^25.0.1",
92
- "license-compatibility-checker": "^0.3.5",
93
88
  "mocha": "^10.2.0",
94
- "nock": "^13.3.1",
95
- "npm-check-updates": "^16.10.12",
89
+ "nock": "^13.3.3",
90
+ "npm-check-updates": "^16.13.3",
96
91
  "nyc": "^15.1.0",
97
92
  "rollup": "2.79.1",
98
93
  "rollup-plugin-babel": "^4.4.0",
@@ -7,6 +7,7 @@
7
7
  "WATSON_PASSWORD": "ZWDE5xo02sby",
8
8
  "WATSON_WORKSPACE_ID": "97513bc0-c581-4bec-ac9f-ea6a8ec308a9",
9
9
  "SCRIPTING_ENABLE_MEMORY": true,
10
+ "SAFEDIR": ".",
10
11
  "ASSERTERS": [
11
12
  {
12
13
  "ref": "DUMMY",
@@ -3,6 +3,7 @@
3
3
  "Capabilities": {
4
4
  "PROJECTNAME": "Botium Logichooks Sample",
5
5
  "CONTAINERMODE": "echo",
6
+ "SAFEDIR": ".",
6
7
  "ASSERTERS": [
7
8
  {
8
9
  "ref": "MYASSERTER",
@@ -6,17 +6,17 @@ module.exports = class MyAsserter {
6
6
  this.caps = caps
7
7
  }
8
8
 
9
- assertConvoBegin ({convo, container, args}) {
9
+ assertConvoBegin ({ convo, container, args }) {
10
10
  console.log(`MyAsserter assertConvoBegin: ${convo.header.name}`)
11
11
  return Promise.resolve()
12
12
  }
13
13
 
14
- assertConvoStep ({convo, convoStep, args, botMsg}) {
14
+ assertConvoStep ({ convo, convoStep, args, botMsg }) {
15
15
  console.log(`MyAsserter assertConvoStep, botMessage: ${utils.inspect(botMsg)} ...`)
16
16
  return Promise.resolve()
17
17
  }
18
18
 
19
- assertConvoEnd ({convo, container, transcript, args}) {
19
+ assertConvoEnd ({ convo, container, transcript, args }) {
20
20
  console.log(`MyAsserter assertConvoEnd ${convo.header.name}, transcript: ${utils.inspect(transcript)} ...`)
21
21
  return Promise.resolve()
22
22
  }
@@ -3,6 +3,7 @@ module.exports = {
3
3
  TESTSESSIONNAME: 'TESTSESSIONNAME',
4
4
  TESTCASENAME: 'TESTCASENAME',
5
5
  TEMPDIR: 'TEMPDIR',
6
+ SAFEDIR: 'SAFEDIR',
6
7
  CLEANUPTEMPDIR: 'CLEANUPTEMPDIR',
7
8
  WAITFORBOTTIMEOUT: 'WAITFORBOTTIMEOUT',
8
9
  CONTAINERMODE: 'CONTAINERMODE',
@@ -12,7 +13,7 @@ module.exports = {
12
13
  BOTIUMGRIDURL: 'BOTIUMGRIDURL',
13
14
  BOTIUMAPITOKEN: 'BOTIUMAPITOKEN',
14
15
  BOTIUMGRIDSLOT: 'BOTIUMGRIDSLOT',
15
- // Simple Reset Bot Settings
16
+ // Simple Rest Bot Settings
16
17
  SIMPLEREST_PING_URL: 'SIMPLEREST_PING_URL',
17
18
  SIMPLEREST_PING_VERB: 'SIMPLEREST_PING_VERB',
18
19
  SIMPLEREST_PING_BODY: 'SIMPLEREST_PING_BODY',
@@ -162,4 +162,12 @@ module.exports = class PluginConnectorContainer extends BaseContainer {
162
162
  return Promise.reject(new Error(`Clean - Botium plugin failed: ${util.inspect(err)}`))
163
163
  }
164
164
  }
165
+
166
+ GetMetaData () {
167
+ try {
168
+ return (this.pluginInstance.GetMetaData ? (this.pluginInstance.GetMetaData() || Promise.resolve()) : Promise.resolve())
169
+ } catch (err) {
170
+ return Promise.reject(new Error(`GetMetaData - Botium plugin failed: ${util.inspect(err)}`))
171
+ }
172
+ }
165
173
  }
@@ -336,24 +336,33 @@ module.exports = class SimpleRestContainer {
336
336
 
337
337
  const result = []
338
338
  if (isFromUser) {
339
- const _extractFrom = (root, jsonPaths) => {
340
- const flattened = []
339
+ const _extractFrom = (root, jsonPaths, acceptFn = null) => {
340
+ const result = []
341
341
  for (const jsonPath of jsonPaths) {
342
+ const jsonPathRes = []
342
343
  const rb = jp.query(root, jsonPath)
343
344
  if (_.isArray(rb)) {
344
- _.flattenDeep(rb).forEach(r => flattened.push(r))
345
- } else if (rb) {
346
- flattened.push(rb)
345
+ _.flattenDeep(rb).forEach(r => jsonPathRes.push(r))
346
+ } else {
347
+ jsonPathRes.push(rb)
348
+ }
349
+ if (acceptFn) {
350
+ result.push(...jsonPathRes.filter(r => acceptFn(root, jsonPath, r)))
351
+ } else {
352
+ result.push(...jsonPathRes)
347
353
  }
348
354
  }
349
- return flattened
355
+ return result
350
356
  }
351
357
 
352
358
  const jsonPathRoots = []
353
-
354
359
  const jsonPathsBody = getAllCapValues(Capabilities.SIMPLEREST_BODY_JSONPATH, this.caps)
355
360
  if (jsonPathsBody.length > 0) {
356
- jsonPathRoots.push(..._extractFrom(body, jsonPathsBody))
361
+ jsonPathRoots.push(..._extractFrom(body, jsonPathsBody, (root, jsonPath, r) => {
362
+ if (r && _.isObject(r)) return true
363
+ debug(`Ignoring result body from ${jsonPath} - not a querieable object (${util.inspect(r)})`)
364
+ return false
365
+ }))
357
366
  } else {
358
367
  jsonPathRoots.push(body)
359
368
  }
@@ -381,7 +390,6 @@ module.exports = class SimpleRestContainer {
381
390
  const jsonPathsButtonsPayload = getAllCapValues(`${capPrefix}_PAYLOAD_SUBJSONPATH`, this.caps)
382
391
 
383
392
  const retrievedButtons = []
384
-
385
393
  const responseButtons = _extractFrom(jsonPathButtonRoot, jsonPathsButtons)
386
394
  for (const responseButton of responseButtons) {
387
395
  const retrievedButton = {}
@@ -5,7 +5,6 @@ const debug = require('debug')('botium-connector-PluginConnectorContainer-helper
5
5
 
6
6
  const SimpleRestContainer = require('./SimpleRestContainer')
7
7
  const Capabilities = require('../../Capabilities')
8
- const { BotiumError } = require('../../scripting/BotiumError')
9
8
 
10
9
  const pluginResolver = (containermode) => {
11
10
  if (containermode === 'simplerest') {
@@ -59,23 +58,6 @@ const loadConnectorModule = (PluginClass, args) => {
59
58
 
60
59
  const tryLoadPlugin = (containermode, modulepath, args) => {
61
60
  const pluginLoaderSpec = modulepath || containermode
62
- const _checkUnsafe = (caps, mode, cause) => {
63
- if (!caps[Capabilities.SECURITY_ALLOW_UNSAFE]) {
64
- throw new BotiumError(
65
- `Security Error. Using unsafe connector mode "${mode}" is not allowed`,
66
- {
67
- type: 'security',
68
- subtype: 'allow unsafe',
69
- source: 'src/containers/plugins/index.js',
70
- cause: {
71
- SECURITY_ALLOW_UNSAFE: caps[Capabilities.SECURITY_ALLOW_UNSAFE],
72
- mode,
73
- ...cause
74
- }
75
- }
76
- )
77
- }
78
- }
79
61
 
80
62
  if (pluginResolver(pluginLoaderSpec)) {
81
63
  const pluginInstance = new (pluginResolver(pluginLoaderSpec))(args)
@@ -88,44 +70,50 @@ const tryLoadPlugin = (containermode, modulepath, args) => {
88
70
  return pluginInstance
89
71
  }
90
72
  const loadErr = []
73
+ const allowUnsafe = !!args.caps[Capabilities.SECURITY_ALLOW_UNSAFE]
91
74
 
92
75
  if (_.isString(pluginLoaderSpec)) {
93
- const tryLoadFile = path.resolve(process.cwd(), pluginLoaderSpec)
94
- if (fs.existsSync(tryLoadFile)) {
95
- _checkUnsafe(args.caps, 'Using work dir', { modulepath, containermode })
76
+ if (args.caps.SAFEDIR) {
77
+ const tryLoadFile = path.resolve(args.caps.SAFEDIR, pluginLoaderSpec)
78
+ if (tryLoadFile.startsWith(path.resolve(args.caps.SAFEDIR))) {
79
+ if (fs.existsSync(tryLoadFile)) {
80
+ try {
81
+ let plugin = require(tryLoadFile)
82
+ if (plugin.default) {
83
+ plugin = plugin.default
84
+ }
85
+ if (!plugin.PluginVersion || !plugin.PluginClass) {
86
+ loadErr.push(`Invalid Botium plugin loaded from ${tryLoadFile}, expected PluginVersion, PluginClass fields`)
87
+ } else {
88
+ const pluginInstance = loadConnectorModule(plugin.PluginClass, args)
89
+ debug(`Botium plugin loaded from ${tryLoadFile}`)
90
+ return pluginInstance
91
+ }
92
+ } catch (err) {
93
+ loadErr.push(`Loading Botium plugin from ${tryLoadFile} failed - ${err.message}`)
94
+ }
95
+ }
96
+ }
97
+ }
98
+
99
+ if (allowUnsafe) {
96
100
  try {
97
- let plugin = require(tryLoadFile)
101
+ let plugin = require(pluginLoaderSpec)
98
102
  if (plugin.default) {
99
103
  plugin = plugin.default
100
104
  }
101
105
  if (!plugin.PluginVersion || !plugin.PluginClass) {
102
- loadErr.push(`Invalid Botium plugin loaded from ${tryLoadFile}, expected PluginVersion, PluginClass fields`)
106
+ loadErr.push(`Invalid Botium plugin loaded from ${pluginLoaderSpec}, expected PluginVersion, PluginClass fields`)
103
107
  } else {
104
108
  const pluginInstance = loadConnectorModule(plugin.PluginClass, args)
105
- debug(`Botium plugin loaded from ${tryLoadFile}`)
109
+ debug(`Botium plugin loaded from ${pluginLoaderSpec}. Plugin version is ${getModuleVersionSafe(pluginLoaderSpec)}`)
106
110
  return pluginInstance
107
111
  }
108
112
  } catch (err) {
109
- loadErr.push(`Loading Botium plugin from ${tryLoadFile} failed - ${err.message}`)
113
+ loadErr.push(`Loading Botium plugin from ${pluginLoaderSpec} failed - ${err.message}`)
110
114
  }
111
115
  }
112
116
 
113
- try {
114
- let plugin = require(pluginLoaderSpec)
115
- if (plugin.default) {
116
- plugin = plugin.default
117
- }
118
- if (!plugin.PluginVersion || !plugin.PluginClass) {
119
- loadErr.push(`Invalid Botium plugin loaded from ${pluginLoaderSpec}, expected PluginVersion, PluginClass fields`)
120
- } else {
121
- const pluginInstance = loadConnectorModule(plugin.PluginClass, args)
122
- debug(`Botium plugin loaded from ${pluginLoaderSpec}. Plugin version is ${getModuleVersionSafe(pluginLoaderSpec)}`)
123
- return pluginInstance
124
- }
125
- } catch (err) {
126
- loadErr.push(`Loading Botium plugin from ${pluginLoaderSpec} failed - ${err.message}`)
127
- }
128
-
129
117
  const tryLoadPackage = `botium-connector-${pluginLoaderSpec}`
130
118
  try {
131
119
  let plugin = require(tryLoadPackage)
@@ -1,48 +1,28 @@
1
1
  const util = require('util')
2
2
  const path = require('path')
3
3
  const fs = require('fs')
4
- const { NodeVM } = require('vm2')
5
- const esprima = require('esprima')
6
4
  const _ = require('lodash')
7
5
  const debug = require('debug')('botium-core-HookUtils')
8
6
 
9
7
  const Capabilities = require('../Capabilities')
10
- const { BotiumError } = require('../scripting/BotiumError')
11
8
 
12
- const executeHook = async (caps, hook, args) => {
13
- return executeHookSync(caps, hook, args)
9
+ const executeHook = async (caps, hook, ...args) => {
10
+ return executeHookSync(caps, hook, ...args)
14
11
  }
15
12
 
16
- const executeHookSync = (caps, hook, args) => {
13
+ const executeHookSync = (caps, hook, ...args) => {
17
14
  if (!hook) {
18
15
  return
19
16
  }
20
17
 
21
18
  if (_.isFunction(hook)) {
22
19
  try {
23
- return hook(args)
20
+ return hook(...args)
24
21
  } catch (err) {
25
22
  throw new Error(`Calling Hook function failed: ${err.message}`)
26
23
  }
27
24
  }
28
25
 
29
- if (_.isString(hook)) {
30
- try {
31
- const vm = new NodeVM({
32
- eval: false,
33
- require: false,
34
- sandbox: args
35
- })
36
- const r = vm.run(hook)
37
- if (_.isFunction(r)) {
38
- return r(args)
39
- } else {
40
- return r
41
- }
42
- } catch (err) {
43
- throw new Error(`Calling Hook Javascript code failed: ${err.message}`)
44
- }
45
- }
46
26
  throw new Error(`Unknown hook ${typeof hook}`)
47
27
  }
48
28
 
@@ -58,56 +38,40 @@ const getHook = (caps, data) => {
58
38
  }
59
39
 
60
40
  if (_.isString(data)) {
61
- let resultWithRequire
62
- let tryLoadFile = path.resolve(process.cwd(), data)
63
- if (fs.existsSync(tryLoadFile)) {
64
- try {
65
- resultWithRequire = require(tryLoadFile)
66
- } catch (err) {
67
- }
68
- } else {
69
- tryLoadFile = data
70
- try {
71
- resultWithRequire = require(data)
72
- } catch (err) {
73
- }
74
- }
75
-
76
- if (resultWithRequire) {
77
- if (!allowUnsafe) {
78
- throw new BotiumError(
79
- 'Security Error. Using unsafe custom hook with require is not allowed',
80
- {
81
- type: 'security',
82
- subtype: 'allow unsafe',
83
- source: path.basename(__filename),
84
- cause: {
85
- SECURITY_ALLOW_UNSAFE: caps[Capabilities.SECURITY_ALLOW_UNSAFE],
86
- hookData: data
41
+ if (caps.SAFEDIR) {
42
+ const tryLoadFile = path.resolve(caps.SAFEDIR, data)
43
+ if (tryLoadFile.startsWith(path.resolve(caps.SAFEDIR))) {
44
+ if (fs.existsSync(tryLoadFile)) {
45
+ try {
46
+ const resultWithRequire = require(tryLoadFile)
47
+ if (_.isFunction(resultWithRequire)) {
48
+ debug(`found hook, type: safedir, in ${tryLoadFile}`)
49
+ return resultWithRequire
50
+ } else {
51
+ throw new Error(`Expected function from hook specification "${util.inspect(data)}", got: "${util.inspect(resultWithRequire)}"`)
87
52
  }
53
+ } catch (err) {
54
+ debug(`Failed loading hook, type: safedir, from ${tryLoadFile} failed: ${err.message || err}`)
88
55
  }
89
- )
90
- }
91
-
92
- if (_.isFunction(resultWithRequire)) {
93
- debug(`found hook, type: require, in ${tryLoadFile}`)
94
- return resultWithRequire
95
- } else {
96
- throw new Error(`Cant load hook ${tryLoadFile} because it is not a function`)
56
+ }
97
57
  }
98
58
  }
99
-
100
- try {
101
- esprima.parseScript(data)
102
- } catch (err) {
103
- throw new Error(`Cant load hook, syntax is not valid - ${util.inspect(err)}`)
59
+ if (allowUnsafe || data.startsWith('botium-')) {
60
+ const tryLoadFile = data
61
+ try {
62
+ const resultWithRequire = require(tryLoadFile)
63
+ if (_.isFunction(resultWithRequire)) {
64
+ debug(`found hook, type: require, in ${tryLoadFile}`)
65
+ return resultWithRequire
66
+ } else {
67
+ throw new Error(`Expected function from hook specification "${util.inspect(data)}", got: "${util.inspect(resultWithRequire)}"`)
68
+ }
69
+ } catch (err) {
70
+ debug(`Failed loading hook, type: require, from ${tryLoadFile} failed: ${err.message || err}`)
71
+ }
104
72
  }
105
-
106
- debug('Found hook, type: JavaScript as String')
107
- return data
108
73
  }
109
-
110
- throw new Error(`Not valid hook ${util.inspect(data)}`)
74
+ throw new Error(`Hook specification "${util.inspect(data)}" invalid: no loader available`)
111
75
  }
112
76
 
113
77
  module.exports = {
@@ -3,7 +3,6 @@ const debug = require('debug')('botium-core-ScriptingMemory')
3
3
  const randomize = require('randomatic')
4
4
  const { v1: uuidv1 } = require('uuid')
5
5
  const moment = require('moment')
6
- const { NodeVM } = require('vm2')
7
6
  const _ = require('lodash')
8
7
  const path = require('path')
9
8
  const jp = require('jsonpath')
@@ -181,29 +180,6 @@ const SCRIPTING_FUNCTIONS_RAW = {
181
180
  else return ''
182
181
  },
183
182
  numberOfArguments: 1
184
- },
185
-
186
- $func: {
187
- handler: (caps, code) => {
188
- if (code == null) {
189
- throw Error('func function used without args!')
190
- }
191
- try {
192
- const vm = new NodeVM({
193
- eval: false,
194
- require: false,
195
- env: caps[Capabilities.SECURITY_ALLOW_UNSAFE] ? process.env : {},
196
- sandbox: {
197
- caps,
198
- moment
199
- }
200
- })
201
- return vm.run(`module.exports = (${code})`)
202
- } catch (err) {
203
- throw Error(`func function execution failed - ${err}`)
204
- }
205
- },
206
- numberOfArguments: 1
207
183
  }
208
184
  }
209
185
 
@@ -1,11 +1,9 @@
1
- const { NodeVM } = require('vm2')
1
+ const util = require('util')
2
2
  const path = require('path')
3
3
  const fs = require('fs')
4
4
  const isClass = require('is-class')
5
5
  const debug = require('debug')('botium-core-asserterUtils')
6
6
 
7
- const { BotiumError } = require('../BotiumError')
8
-
9
7
  const { DEFAULT_ASSERTERS, DEFAULT_LOGIC_HOOKS, DEFAULT_USER_INPUTS } = require('./LogicHookConsts')
10
8
 
11
9
  DEFAULT_ASSERTERS.forEach((asserter) => {
@@ -129,19 +127,7 @@ module.exports = class LogicHookUtils {
129
127
  }
130
128
  }
131
129
 
132
- const _checkUnsafe = () => {
133
- if (!this.caps[Capabilities.SECURITY_ALLOW_UNSAFE]) {
134
- throw new BotiumError(
135
- 'Security Error. Using unsafe component is not allowed',
136
- {
137
- type: 'security',
138
- subtype: 'allow unsafe',
139
- source: path.basename(__filename),
140
- cause: { src: !!src, ref, args, hookType }
141
- }
142
- )
143
- }
144
- }
130
+ const allowUnsafe = !!this.caps[Capabilities.SECURITY_ALLOW_UNSAFE]
145
131
 
146
132
  if (!src) {
147
133
  const packageName = `botium-${hookType}-${ref}`
@@ -154,10 +140,10 @@ module.exports = class LogicHookUtils {
154
140
  } else if (isClass(CheckClass.PluginClass)) {
155
141
  return new CheckClass.PluginClass({ ref, ...this.buildScriptContext }, this.caps, args)
156
142
  } else {
157
- throw new Error(`${packageName} class or function or PluginClass field expected`)
143
+ throw new Error('Either class or function or PluginClass field expected')
158
144
  }
159
145
  } catch (err) {
160
- throw new Error(`Failed to fetch hook ${ref} ${hookType} from guessed package ${packageName} - ${err.message}`)
146
+ throw new Error(`Logic Hook specification ${ref} ${hookType} (${packageName}) invalid: ${err.message}`)
161
147
  }
162
148
  }
163
149
 
@@ -166,14 +152,14 @@ module.exports = class LogicHookUtils {
166
152
  const CheckClass = src
167
153
  return new CheckClass({ ref, ...this.buildScriptContext }, this.caps, args)
168
154
  } catch (err) {
169
- throw new Error(`Failed to load package ${ref} from provided class - ${err.message}`)
155
+ throw new Error(`Logic Hook specification ${ref} from class invalid: ${err.message}`)
170
156
  }
171
157
  }
172
158
  if (_.isFunction(src)) {
173
159
  try {
174
160
  return src({ ref, ...this.buildScriptContext }, this.caps, args)
175
161
  } catch (err) {
176
- throw new Error(`Failed to load package ${ref} from provided function - ${err.message}`)
162
+ throw new Error(`Logic Hook specification ${ref} from function invalid: ${err.message}`)
177
163
  }
178
164
  }
179
165
  if (_.isObject(src) && !_.isString(src)) {
@@ -183,26 +169,15 @@ module.exports = class LogicHookUtils {
183
169
  const script = src[key]
184
170
  if (_.isFunction(script)) {
185
171
  return script(args)
186
- } else if (_.isString(script)) {
187
- try {
188
- const vm = new NodeVM({
189
- eval: false,
190
- require: false,
191
- sandbox: args
192
- })
193
- return vm.run(script)
194
- } catch (err) {
195
- throw new Error(`Script ${key} is not valid - ${err.message || err}`)
196
- }
197
172
  } else {
198
- throw new Error(`Script "${key}" is not valid - only functions and javascript code accepted`)
173
+ throw new Error(`Script ${key} is not valid - only functions accepted`)
199
174
  }
200
175
  }
201
176
  return result
202
177
  }, {})
203
178
  return hookObject
204
179
  } catch (err) {
205
- throw new Error(`Failed to load package ${ref} ${hookType} from provided src function - ${err.message}`)
180
+ throw new Error(`Logic Hook specification ${ref} ${hookType} from provided src (${util.inspect(src)}) invalid: ${err.message}`)
206
181
  }
207
182
  }
208
183
 
@@ -215,8 +190,8 @@ module.exports = class LogicHookUtils {
215
190
  }]
216
191
  if (src.indexOf('/') >= 0) {
217
192
  tryLoads.push({
218
- tryLoadPackageName: src.substr(0, src.lastIndexOf('/')),
219
- tryLoadAsserterByName: src.substr(src.lastIndexOf('/') + 1)
193
+ tryLoadPackageName: src.substring(0, src.lastIndexOf('/')),
194
+ tryLoadAsserterByName: src.substring(src.lastIndexOf('/') + 1)
220
195
  })
221
196
  }
222
197
 
@@ -243,29 +218,34 @@ module.exports = class LogicHookUtils {
243
218
  } else if (_.isFunction(CheckClass.PluginClass)) {
244
219
  return CheckClass.PluginClass({ ref, ...this.buildScriptContext }, this.caps, args)
245
220
  } else {
246
- throw new Error(`${src} class or function expected`)
221
+ throw new Error('Expected class or function')
247
222
  }
248
223
  }
249
224
 
250
225
  for (const tryLoad of tryLoads) {
251
- const tryLoadFile = path.resolve(process.cwd(), tryLoad.tryLoadPackageName)
252
- if (fs.existsSync(tryLoadFile)) {
253
- _checkUnsafe()
226
+ if (this.caps.SAFEDIR) {
227
+ const tryLoadFile = path.resolve(this.caps.SAFEDIR, tryLoad.tryLoadPackageName)
228
+ if (tryLoadFile.startsWith(path.resolve(this.caps.SAFEDIR))) {
229
+ if (fs.existsSync(tryLoadFile)) {
230
+ try {
231
+ return tryLoadFromSource(tryLoadFile, tryLoad.tryLoadAsserterByName)
232
+ } catch (err) {
233
+ loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `)
234
+ }
235
+ }
236
+ }
237
+ }
238
+ if (allowUnsafe || tryLoad.tryLoadPackageName.startsWith('botium-')) {
254
239
  try {
255
- return tryLoadFromSource(tryLoadFile, tryLoad.tryLoadAsserterByName)
240
+ return tryLoadFromSource(tryLoad.tryLoadPackageName, tryLoad.tryLoadAsserterByName)
256
241
  } catch (err) {
257
- loadErr.push(`Failed to fetch ${ref} ${hookType} from ${src} - ${err.message} `)
242
+ loadErr.push(`Logic Hook specification ${ref} ${hookType} from "${src}" invalid: ${err.message} `)
258
243
  }
259
244
  }
260
- try {
261
- return tryLoadFromSource(tryLoad.tryLoadPackageName, tryLoad.tryLoadAsserterByName)
262
- } catch (err) {
263
- loadErr.push(`Failed to fetch ${ref} ${hookType} from ${src} - ${err.message} `)
264
- }
265
245
  }
266
246
 
267
247
  loadErr.forEach(debug)
268
248
  }
269
- throw new Error(`Failed to fetch ${ref} ${hookType}, no idea how to load ...`)
249
+ throw new Error(`Logic Hook specification ${ref} ${hookType} from "${util.inspect(src)}" invalid : no loader available`)
270
250
  }
271
251
  }