botium-core 1.13.18 → 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.
- package/dist/botium-cjs.js +326 -387
- package/dist/botium-cjs.js.map +1 -1
- package/dist/botium-es.js +326 -385
- package/dist/botium-es.js.map +1 -1
- package/package.json +21 -25
- package/samples/extensions/asserterHooks/botium.json +1 -0
- package/samples/extensions/logichooks/botium.json +1 -0
- package/samples/extensions/logichooks/custom/MyAsserter.js +3 -3
- package/src/Capabilities.js +2 -1
- package/src/containers/PluginConnectorContainer.js +8 -0
- package/src/containers/plugins/SimpleRestContainer.js +17 -9
- package/src/containers/plugins/index.js +29 -41
- package/src/helpers/HookUtils.js +32 -68
- package/src/scripting/Convo.js +17 -5
- package/src/scripting/ScriptingMemory.js +0 -24
- package/src/scripting/logichook/LogicHookConsts.js +5 -1
- package/src/scripting/logichook/LogicHookUtils.js +27 -47
- package/src/scripting/logichook/asserter/ButtonsAsserter.js +5 -5
- package/src/scripting/logichook/logichooks/ConditionalBusinessHoursLogicHook.js +56 -0
- package/src/scripting/logichook/logichooks/ConditionalCapabilityValueBasedLogicHook.js +37 -0
- package/src/scripting/logichook/logichooks/ConditionalJsonPathBasedLogicHook.js +31 -0
- package/src/scripting/logichook/logichooks/ConditionalTimeBasedLogicHook.js +46 -0
- package/test/compiler/precompilerscript.spec.js +24 -26
- package/test/connectors/pluginconnectorcontainer.spec.js +60 -0
- package/test/connectors/simplerest.spec.js +24 -27
- package/test/convo/fillAndApplyScriptingMemory.spec.js +1 -47
- package/test/hooks/customhooks.spec.js +3 -25
- package/test/logichooks/hookfromsrc.spec.js +13 -3
- package/test/plugins/plugins.spec.js +29 -2
- package/test/scripting/logichooks/CustomConditionalLogicHook.js +21 -0
- package/test/scripting/logichooks/conditionalStepBusinessHoursLogicHook.spec.js +130 -0
- package/test/scripting/logichooks/conditionalStepCapabilityValueBasedLogicHook.spec.js +35 -0
- package/test/scripting/logichooks/conditionalStepJsonPathBasedLogicHook.spec.js +35 -0
- package/test/scripting/logichooks/conditionalStepTimeBasedLogicHook.spec.js +91 -0
- package/test/scripting/logichooks/convos/conditional_steps.convo.txt +12 -0
- package/test/scripting/logichooks/convos/conditional_steps_business_hours.convo.txt +16 -0
- package/test/scripting/logichooks/convos/conditional_steps_cap_value_based.convo.txt +12 -0
- package/test/scripting/logichooks/convos/conditional_steps_followed_by_bot_msg.convo.txt +15 -0
- package/test/scripting/logichooks/convos/conditional_steps_followed_by_me.convo.txt +18 -0
- package/test/scripting/logichooks/convos/conditional_steps_json_path_based.convo.txt.convo.txt +12 -0
- package/test/scripting/logichooks/convos/conditional_steps_multiple_condition_groups.convo.txt +20 -0
- package/test/scripting/logichooks/convos/conditional_steps_multiple_condition_groups_no_assertion.convo.txt +20 -0
- package/test/scripting/logichooks/convos/conditional_steps_time_based.convo.txt +12 -0
- package/test/scripting/logichooks/customConditionalStepLogicHook.spec.js +105 -0
- package/test/scripting/scriptingProvider.spec.js +1 -1
- package/test/security/allowUnsafe.spec.js +20 -129
- package/LICENSES-3RDPARTY.txt +0 -6450
- package/test/scripting/asserters/convos/customembeddedasserterwithhugo.convo.txt +0 -7
- package/test/scripting/asserters/convos/customembeddedasserterwithouthugo.convo.txt +0 -7
- package/test/scripting/asserters/customEmbeddedAsserter.json +0 -14
- package/test/scripting/asserters/customEmbeddedAsserter.spec.js +0 -55
- package/test/scripting/logichooks/convos/custom_embedded.convo.txt +0 -8
- package/test/scripting/logichooks/convos/custom_embedded_skip.convo.txt +0 -11
- package/test/scripting/logichooks/convos/custom_embedded_skip_followed_by_me.convo.txt +0 -11
- package/test/scripting/logichooks/convos/custom_embedded_skip_followed_by_nothing.convo.txt +0 -8
- package/test/scripting/logichooks/customEmbedded.json +0 -14
- package/test/scripting/logichooks/customEmbedded.spec.js +0 -44
- package/test/scripting/logichooks/customEmbeddedSkip.json +0 -14
- package/test/scripting/logichooks/customEmbeddedSkip.spec.js +0 -58
- 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.
|
|
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.
|
|
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.
|
|
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",
|
|
@@ -51,47 +49,45 @@
|
|
|
51
49
|
"mime-types": "^2.1.35",
|
|
52
50
|
"mkdirp": "^3.0.1",
|
|
53
51
|
"moment": "^2.29.4",
|
|
52
|
+
"moment-timezone": "^0.5.43",
|
|
54
53
|
"mustache": "^4.2.0",
|
|
55
54
|
"promise-retry": "^2.0.1",
|
|
56
|
-
"promise.allsettled": "^1.0.
|
|
55
|
+
"promise.allsettled": "^1.0.7",
|
|
57
56
|
"randomatic": "^3.1.1",
|
|
58
57
|
"request": "^2.88.2",
|
|
59
|
-
"rimraf": "^5.0.
|
|
58
|
+
"rimraf": "^5.0.1",
|
|
60
59
|
"sanitize-filename": "^1.6.3",
|
|
61
60
|
"slugify": "^1.6.6",
|
|
62
|
-
"socket.io": "^4.
|
|
63
|
-
"socket.io-client": "^4.
|
|
61
|
+
"socket.io": "^4.7.2",
|
|
62
|
+
"socket.io-client": "^4.7.2",
|
|
64
63
|
"socketio-auth": "^0.1.1",
|
|
65
64
|
"swagger-jsdoc": "^6.2.8",
|
|
66
|
-
"swagger-ui-express": "^
|
|
65
|
+
"swagger-ui-express": "^5.0.0",
|
|
67
66
|
"uuid": "^9.0.0",
|
|
68
|
-
"vm2": "^3.9.17",
|
|
69
67
|
"word-error-rate": "0.0.7",
|
|
70
68
|
"write-yaml": "^1.0.0",
|
|
71
69
|
"xlsx": "^0.18.5",
|
|
72
70
|
"xregexp": "^5.1.1",
|
|
73
|
-
"yaml": "^2.
|
|
71
|
+
"yaml": "^2.3.2"
|
|
74
72
|
},
|
|
75
73
|
"devDependencies": {
|
|
76
|
-
"@babel/core": "^7.
|
|
77
|
-
"@babel/node": "^7.
|
|
78
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
79
|
-
"@babel/preset-env": "^7.
|
|
80
|
-
"chai": "^4.3.
|
|
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",
|
|
81
79
|
"chai-as-promised": "^7.1.1",
|
|
82
80
|
"cross-env": "^7.0.3",
|
|
83
|
-
"eslint": "^8.
|
|
84
|
-
"eslint-config-standard": "^17.
|
|
85
|
-
"eslint-plugin-import": "^2.
|
|
81
|
+
"eslint": "^8.49.0",
|
|
82
|
+
"eslint-config-standard": "^17.1.0",
|
|
83
|
+
"eslint-plugin-import": "^2.28.1",
|
|
86
84
|
"eslint-plugin-mocha": "^10.1.0",
|
|
87
|
-
"eslint-plugin-n": "^
|
|
85
|
+
"eslint-plugin-n": "^16.1.0",
|
|
88
86
|
"eslint-plugin-promise": "^6.1.1",
|
|
89
87
|
"eslint-plugin-standard": "^4.1.0",
|
|
90
|
-
"license-checker": "^25.0.1",
|
|
91
|
-
"license-compatibility-checker": "^0.3.5",
|
|
92
88
|
"mocha": "^10.2.0",
|
|
93
|
-
"nock": "^13.3.
|
|
94
|
-
"npm-check-updates": "^16.
|
|
89
|
+
"nock": "^13.3.3",
|
|
90
|
+
"npm-check-updates": "^16.13.3",
|
|
95
91
|
"nyc": "^15.1.0",
|
|
96
92
|
"rollup": "2.79.1",
|
|
97
93
|
"rollup-plugin-babel": "^4.4.0",
|
|
@@ -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
|
}
|
package/src/Capabilities.js
CHANGED
|
@@ -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
|
|
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
|
|
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 =>
|
|
345
|
-
} else
|
|
346
|
-
|
|
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
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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(
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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)
|
package/src/helpers/HookUtils.js
CHANGED
|
@@ -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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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 = {
|
package/src/scripting/Convo.js
CHANGED
|
@@ -356,6 +356,7 @@ class Convo {
|
|
|
356
356
|
throw failErr
|
|
357
357
|
}
|
|
358
358
|
} else if (convoStep.sender === 'bot') {
|
|
359
|
+
const previousWaitForBotSays = waitForBotSays
|
|
359
360
|
if (waitForBotSays) {
|
|
360
361
|
botMsg = null
|
|
361
362
|
} else {
|
|
@@ -404,13 +405,24 @@ class Convo {
|
|
|
404
405
|
throw failErr
|
|
405
406
|
}
|
|
406
407
|
|
|
407
|
-
if (convoStep.
|
|
408
|
-
skipTranscriptStep = true
|
|
408
|
+
if (convoStep.conditional) {
|
|
409
409
|
const nextConvoStep = this.conversation[i + 1]
|
|
410
|
-
|
|
411
|
-
|
|
410
|
+
|
|
411
|
+
if (!previousWaitForBotSays) {
|
|
412
|
+
skipTranscriptStep = true
|
|
413
|
+
}
|
|
414
|
+
waitForBotSays = false
|
|
415
|
+
if (!nextConvoStep || nextConvoStep.sender !== 'bot' || !nextConvoStep.logicHooks || !nextConvoStep.logicHooks.some(lh => lh.name.toUpperCase().startsWith('CONDITIONAL_STEP'))) {
|
|
416
|
+
waitForBotSays = true
|
|
417
|
+
} else {
|
|
418
|
+
const conditionalLogicHook = convoStep.logicHooks.find(lh => lh.name.startsWith('CONDITIONAL_STEP'))
|
|
419
|
+
const nextConditionalLogicHook = nextConvoStep.logicHooks.find(lh => lh.name.startsWith('CONDITIONAL_STEP'))
|
|
420
|
+
waitForBotSays = conditionalLogicHook.args[1] !== nextConditionalLogicHook.args[1]
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (convoStep.conditional.skip) {
|
|
424
|
+
continue
|
|
412
425
|
}
|
|
413
|
-
continue
|
|
414
426
|
}
|
|
415
427
|
|
|
416
428
|
if (!botMsg || (!botMsg.messageText && !botMsg.media && !botMsg.buttons && !botMsg.cards && !botMsg.sourceData && !botMsg.nlp)) {
|
|
@@ -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
|
|
|
@@ -57,7 +57,11 @@ module.exports = {
|
|
|
57
57
|
{ name: 'ASSIGN_SCRIPTING_MEMORY', className: 'AssignScriptingMemoryLogicHook' },
|
|
58
58
|
{ name: 'UPDATE_CUSTOM', className: 'UpdateCustomLogicHook' },
|
|
59
59
|
{ name: 'SKIP_BOT_UNCONSUMED', className: 'ClearQueueLogicHook' },
|
|
60
|
-
{ name: LOGIC_HOOK_INCLUDE, className: 'IncludeLogicHook' }
|
|
60
|
+
{ name: LOGIC_HOOK_INCLUDE, className: 'IncludeLogicHook' },
|
|
61
|
+
{ name: 'CONDITIONAL_STEP_TIME_BASED', className: 'ConditionalTimeBasedLogicHook' },
|
|
62
|
+
{ name: 'CONDITIONAL_STEP_BUSINESS_HOURS', className: 'ConditionalBusinessHoursLogicHook' },
|
|
63
|
+
{ name: 'CONDITIONAL_STEP_CAPABILITY_VALUE_BASED', className: 'ConditionalCapabilityValueBasedLogicHook' },
|
|
64
|
+
{ name: 'CONDITIONAL_STEP_JSON_PATH_BASED', className: 'ConditionalJsonPathBasedLogicHook.js' }
|
|
61
65
|
],
|
|
62
66
|
DEFAULT_USER_INPUTS: [
|
|
63
67
|
{ name: 'BUTTON', className: 'ButtonInput' },
|