foliko 1.0.75 → 1.0.76
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/.claude/settings.local.json +159 -157
- package/cli/bin/foliko.js +12 -12
- package/cli/src/commands/chat.js +143 -143
- package/cli/src/commands/list.js +93 -93
- package/cli/src/index.js +75 -75
- package/cli/src/ui/chat-ui.js +201 -201
- package/cli/src/utils/ansi.js +40 -40
- package/cli/src/utils/markdown.js +292 -292
- package/examples/ambient-example.js +194 -194
- package/examples/basic.js +115 -115
- package/examples/bootstrap.js +121 -121
- package/examples/mcp-example.js +56 -56
- package/examples/skill-example.js +49 -49
- package/examples/test-chat.js +137 -137
- package/examples/test-mcp.js +85 -85
- package/examples/test-reload.js +59 -59
- package/examples/test-telegram.js +50 -50
- package/examples/test-tg-bot.js +45 -45
- package/examples/test-tg-simple.js +47 -47
- package/examples/test-tg.js +62 -62
- package/examples/test-think.js +43 -43
- package/examples/test-web-plugin.js +103 -103
- package/examples/test-weixin-feishu.js +103 -103
- package/examples/workflow.js +158 -158
- package/package.json +1 -1
- package/plugins/ai-plugin.js +102 -102
- package/plugins/ambient-agent/EventWatcher.js +113 -113
- package/plugins/ambient-agent/ExplorerLoop.js +640 -640
- package/plugins/ambient-agent/GoalManager.js +197 -197
- package/plugins/ambient-agent/Reflector.js +95 -95
- package/plugins/ambient-agent/StateStore.js +90 -90
- package/plugins/ambient-agent/constants.js +101 -101
- package/plugins/ambient-agent/index.js +579 -579
- package/plugins/audit-plugin.js +187 -187
- package/plugins/default-plugins.js +662 -662
- package/plugins/email/constants.js +64 -64
- package/plugins/email/handlers.js +461 -461
- package/plugins/email/index.js +278 -278
- package/plugins/email/monitor.js +269 -269
- package/plugins/email/parser.js +138 -138
- package/plugins/email/reply.js +151 -151
- package/plugins/email/utils.js +124 -124
- package/plugins/feishu-plugin.js +481 -481
- package/plugins/file-system-plugin.js +826 -826
- package/plugins/install-plugin.js +199 -199
- package/plugins/python-executor-plugin.js +367 -367
- package/plugins/python-plugin-loader.js +481 -481
- package/plugins/rules-plugin.js +294 -294
- package/plugins/scheduler-plugin.js +691 -691
- package/plugins/session-plugin.js +369 -369
- package/plugins/shell-executor-plugin.js +197 -197
- package/plugins/storage-plugin.js +240 -240
- package/plugins/subagent-plugin.js +845 -845
- package/plugins/telegram-plugin.js +482 -482
- package/plugins/think-plugin.js +345 -345
- package/plugins/tools-plugin.js +196 -196
- package/plugins/web-plugin.js +606 -606
- package/plugins/weixin-plugin.js +545 -545
- package/src/capabilities/index.js +11 -11
- package/src/capabilities/skill-manager.js +609 -609
- package/src/capabilities/workflow-engine.js +1109 -1109
- package/src/core/agent-chat.js +882 -882
- package/src/core/agent.js +892 -892
- package/src/core/framework.js +465 -465
- package/src/core/index.js +19 -19
- package/src/core/plugin-base.js +219 -219
- package/src/core/plugin-manager.js +863 -863
- package/src/core/provider.js +114 -114
- package/src/core/sub-agent-config.js +264 -264
- package/src/core/system-prompt-builder.js +120 -120
- package/src/core/tool-registry.js +517 -517
- package/src/core/tool-router.js +297 -297
- package/src/executors/executor-base.js +58 -58
- package/src/executors/mcp-executor.js +741 -741
- package/src/index.js +25 -25
- package/src/utils/circuit-breaker.js +301 -301
- package/src/utils/error-boundary.js +363 -363
- package/src/utils/error.js +374 -374
- package/src/utils/event-emitter.js +97 -97
- package/src/utils/id.js +133 -133
- package/src/utils/index.js +217 -217
- package/src/utils/logger.js +181 -181
- package/src/utils/plugin-helpers.js +90 -90
- package/src/utils/retry.js +122 -122
- package/src/utils/sandbox.js +292 -292
- package/test/tool-registry-validation.test.js +218 -218
- package/website/script.js +136 -136
- package/foliko-1.0.75.tgz +0 -0
package/src/utils/sandbox.js
CHANGED
|
@@ -1,292 +1,292 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 安全沙箱工具
|
|
3
|
-
* 用于替代 new Function() 执行不可信代码
|
|
4
|
-
* 提供安全的代码执行环境,限制对系统资源的访问
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { VM, VMScript } = require('vm2')
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 创建安全的沙箱上下文
|
|
11
|
-
* @param {Object} customContext - 自定义上下文变量
|
|
12
|
-
* @param {Object} options - 配置选项
|
|
13
|
-
* @returns {Object} 沙箱上下文
|
|
14
|
-
*/
|
|
15
|
-
function createSandboxContext(customContext = {}, options = {}) {
|
|
16
|
-
const {
|
|
17
|
-
timeout = 5000, // 超时时间(毫秒)
|
|
18
|
-
allowSync = false, // 是否允许同步执行
|
|
19
|
-
mockConsole = true // 是否模拟 console
|
|
20
|
-
} = options
|
|
21
|
-
|
|
22
|
-
// 创建安全的 console 对象
|
|
23
|
-
const safeConsole = mockConsole ? {
|
|
24
|
-
log: (...args) => { /* 静默执行,阻止日志泄露 */ },
|
|
25
|
-
error: (...args) => { /* 静默执行 */ },
|
|
26
|
-
warn: (...args) => { /* 静默执行 */ },
|
|
27
|
-
info: (...args) => { /* 静默执行 */ },
|
|
28
|
-
debug: (...args) => { /* 静默执行 */ }
|
|
29
|
-
} : console
|
|
30
|
-
|
|
31
|
-
return {
|
|
32
|
-
// 用户提供的上下文
|
|
33
|
-
...customContext,
|
|
34
|
-
// 安全的 console
|
|
35
|
-
console: safeConsole,
|
|
36
|
-
// 安全的 Math 对象
|
|
37
|
-
Math,
|
|
38
|
-
// 安全的 JSON 对象
|
|
39
|
-
JSON: {
|
|
40
|
-
parse: JSON.parse,
|
|
41
|
-
stringify: JSON.stringify
|
|
42
|
-
},
|
|
43
|
-
// 安全的 Array 对象(限制方法)
|
|
44
|
-
Array: {
|
|
45
|
-
isArray: Array.isArray,
|
|
46
|
-
from: Array.from,
|
|
47
|
-
of: Array.of
|
|
48
|
-
},
|
|
49
|
-
// 安全的 String 对象
|
|
50
|
-
String: {
|
|
51
|
-
fromCharCode: String.fromCharCode,
|
|
52
|
-
fromCodePoint: String.fromCodePoint,
|
|
53
|
-
raw: String.raw
|
|
54
|
-
},
|
|
55
|
-
// 安全的 Number 对象
|
|
56
|
-
Number: {
|
|
57
|
-
isNaN: Number.isNaN,
|
|
58
|
-
isFinite: Number.isFinite,
|
|
59
|
-
parseInt: Number.parseInt,
|
|
60
|
-
parseFloat: Number.parseFloat
|
|
61
|
-
},
|
|
62
|
-
// 安全的 Boolean 对象
|
|
63
|
-
Boolean,
|
|
64
|
-
// 安全的 Object 对象
|
|
65
|
-
Object: {
|
|
66
|
-
keys: Object.keys,
|
|
67
|
-
values: Object.values,
|
|
68
|
-
entries: Object.entries,
|
|
69
|
-
assign: Object.assign,
|
|
70
|
-
create: Object.create,
|
|
71
|
-
freeze: Object.freeze
|
|
72
|
-
},
|
|
73
|
-
// 安全的 Date 对象
|
|
74
|
-
Date: {
|
|
75
|
-
now: Date.now
|
|
76
|
-
},
|
|
77
|
-
// 安全的 RegExp 对象
|
|
78
|
-
RegExp,
|
|
79
|
-
// 安全的 Error 对象
|
|
80
|
-
Error,
|
|
81
|
-
// 安全的 Promise 对象
|
|
82
|
-
Promise,
|
|
83
|
-
// 安全的 Set 对象
|
|
84
|
-
Set,
|
|
85
|
-
// 安全的 Map 对象
|
|
86
|
-
Map,
|
|
87
|
-
// 安全的 WeakMap 对象
|
|
88
|
-
WeakMap,
|
|
89
|
-
// 安全的 WeakSet 对象
|
|
90
|
-
WeakSet,
|
|
91
|
-
// 安全的 Symbol
|
|
92
|
-
Symbol,
|
|
93
|
-
// 安全的 Proxy
|
|
94
|
-
Proxy,
|
|
95
|
-
// 安全的 Reflect
|
|
96
|
-
Reflect
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* 在沙箱中执行异步代码
|
|
102
|
-
* @param {string} code - 要执行的代码
|
|
103
|
-
* @param {Object} context - 上下文变量
|
|
104
|
-
* @param {Object} options - 配置选项
|
|
105
|
-
* @returns {Promise<any>} 执行结果
|
|
106
|
-
*/
|
|
107
|
-
async function runInSandbox(code, context = {}, options = {}) {
|
|
108
|
-
const { timeout = 5000 } = options
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
const vm = new VM({
|
|
112
|
-
timeout,
|
|
113
|
-
sandbox: createSandboxContext(context, options),
|
|
114
|
-
eval: false,
|
|
115
|
-
wasm: false
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
// 包装代码为异步函数
|
|
119
|
-
const wrappedCode = `(async () => { ${code} })()`
|
|
120
|
-
return await vm.run(wrappedCode)
|
|
121
|
-
} catch (error) {
|
|
122
|
-
throw new Error(`Sandbox execution error: ${error.message}`)
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* 在沙箱中执行表达式(同步)
|
|
128
|
-
* @param {string} expression - 要执行的表达式
|
|
129
|
-
* @param {Object} context - 上下文变量
|
|
130
|
-
* @param {Object} options - 配置选项
|
|
131
|
-
* @returns {any} 执行结果
|
|
132
|
-
*/
|
|
133
|
-
function evaluateInSandbox(expression, context = {}, options = {}) {
|
|
134
|
-
const { timeout = 5000 } = options
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
const vm = new VM({
|
|
138
|
-
timeout,
|
|
139
|
-
sandbox: createSandboxContext(context, options),
|
|
140
|
-
eval: false,
|
|
141
|
-
wasm: false
|
|
142
|
-
})
|
|
143
|
-
|
|
144
|
-
return vm.run(expression)
|
|
145
|
-
} catch (error) {
|
|
146
|
-
throw new Error(`Sandbox evaluation error: ${error.message}`)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* 安全执行脚本(用于工作流中的用户脚本)
|
|
152
|
-
* @param {string} script - 脚本代码
|
|
153
|
-
* @param {Object} context - 上下文变量
|
|
154
|
-
* @param {Object} options - 配置选项
|
|
155
|
-
* @returns {Promise<any>} 执行结果
|
|
156
|
-
*/
|
|
157
|
-
async function runScriptSafely(script, context = {}, options = {}) {
|
|
158
|
-
const { timeout = 10000 } = options
|
|
159
|
-
|
|
160
|
-
try {
|
|
161
|
-
const vm = new VM({
|
|
162
|
-
timeout,
|
|
163
|
-
sandbox: createSandboxContext(context, options),
|
|
164
|
-
eval: false,
|
|
165
|
-
wasm: false
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
// 将脚本包装在异步 IIFE 中
|
|
169
|
-
const wrappedCode = `
|
|
170
|
-
(async () => {
|
|
171
|
-
const { input, input_data, variables, previousResult, console } = context;
|
|
172
|
-
${script}
|
|
173
|
-
})()
|
|
174
|
-
`
|
|
175
|
-
|
|
176
|
-
return await vm.run(wrappedCode)
|
|
177
|
-
} catch (error) {
|
|
178
|
-
throw new Error(`Script execution error: ${error.message}`)
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* 安全执行工作流定义
|
|
184
|
-
* @param {string} workflowCode - 工作流代码
|
|
185
|
-
* @param {Object} engine - 工作流引擎
|
|
186
|
-
* @param {Object} options - 配置选项
|
|
187
|
-
* @returns {any} 执行结果
|
|
188
|
-
*/
|
|
189
|
-
function runWorkflowSafely(workflowCode, engine, options = {}) {
|
|
190
|
-
const { timeout = 5000 } = options
|
|
191
|
-
|
|
192
|
-
try {
|
|
193
|
-
const vm = new VM({
|
|
194
|
-
timeout,
|
|
195
|
-
sandbox: {
|
|
196
|
-
engine,
|
|
197
|
-
console: {
|
|
198
|
-
log: () => {},
|
|
199
|
-
error: () => {},
|
|
200
|
-
warn: () => {},
|
|
201
|
-
info: () => {}
|
|
202
|
-
},
|
|
203
|
-
Math,
|
|
204
|
-
JSON,
|
|
205
|
-
Promise,
|
|
206
|
-
Array,
|
|
207
|
-
Object,
|
|
208
|
-
Date,
|
|
209
|
-
RegExp,
|
|
210
|
-
Error,
|
|
211
|
-
Symbol,
|
|
212
|
-
Map,
|
|
213
|
-
Set
|
|
214
|
-
},
|
|
215
|
-
eval: false,
|
|
216
|
-
wasm: false
|
|
217
|
-
})
|
|
218
|
-
|
|
219
|
-
return vm.run(`(function(engine) { return (${workflowCode}) })(engine)`)
|
|
220
|
-
} catch (error) {
|
|
221
|
-
throw new Error(`Workflow execution error: ${error.message}`)
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* 安全执行工作流加载脚本
|
|
227
|
-
* @param {string} content - 文件内容
|
|
228
|
-
* @param {Object} options - 配置选项
|
|
229
|
-
* @returns {Object} module.exports
|
|
230
|
-
*/
|
|
231
|
-
function runWorkflowFileSafely(content, options = {}) {
|
|
232
|
-
const { timeout = 10000 } = options
|
|
233
|
-
|
|
234
|
-
try {
|
|
235
|
-
const vm = new VM({
|
|
236
|
-
timeout,
|
|
237
|
-
sandbox: {
|
|
238
|
-
module: { exports: {} },
|
|
239
|
-
exports: {},
|
|
240
|
-
require: () => { throw new Error('require is not allowed in sandbox') },
|
|
241
|
-
process: {
|
|
242
|
-
env: {},
|
|
243
|
-
cwd: () => '/'
|
|
244
|
-
},
|
|
245
|
-
console: {
|
|
246
|
-
log: () => {},
|
|
247
|
-
error: () => {},
|
|
248
|
-
warn: () => {},
|
|
249
|
-
info: () => {}
|
|
250
|
-
},
|
|
251
|
-
__dirname: '/',
|
|
252
|
-
__filename: '/workflow.js',
|
|
253
|
-
Math,
|
|
254
|
-
JSON,
|
|
255
|
-
Promise,
|
|
256
|
-
Array,
|
|
257
|
-
Object,
|
|
258
|
-
Date,
|
|
259
|
-
RegExp,
|
|
260
|
-
Error,
|
|
261
|
-
Symbol,
|
|
262
|
-
Map,
|
|
263
|
-
Set
|
|
264
|
-
},
|
|
265
|
-
eval: false,
|
|
266
|
-
wasm: false
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
const wrappedCode = `
|
|
270
|
-
(function(module, exports, require, process, console, __dirname, __filename) {
|
|
271
|
-
${content}
|
|
272
|
-
})
|
|
273
|
-
`
|
|
274
|
-
|
|
275
|
-
const fn = vm.run(wrappedCode)
|
|
276
|
-
const moduleObj = { exports: {} }
|
|
277
|
-
fn(moduleObj, moduleObj.exports, () => {}, { env: {}, cwd: () => '/' }, { log: () => {}, error: () => {}, warn: () => {}, info: () => {} }, '/', '/workflow.js')
|
|
278
|
-
|
|
279
|
-
return moduleObj.exports.default || moduleObj.exports
|
|
280
|
-
} catch (error) {
|
|
281
|
-
throw new Error(`Workflow file execution error: ${error.message}`)
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
module.exports = {
|
|
286
|
-
createSandboxContext,
|
|
287
|
-
runInSandbox,
|
|
288
|
-
evaluateInSandbox,
|
|
289
|
-
runScriptSafely,
|
|
290
|
-
runWorkflowSafely,
|
|
291
|
-
runWorkflowFileSafely
|
|
292
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 安全沙箱工具
|
|
3
|
+
* 用于替代 new Function() 执行不可信代码
|
|
4
|
+
* 提供安全的代码执行环境,限制对系统资源的访问
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { VM, VMScript } = require('vm2')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 创建安全的沙箱上下文
|
|
11
|
+
* @param {Object} customContext - 自定义上下文变量
|
|
12
|
+
* @param {Object} options - 配置选项
|
|
13
|
+
* @returns {Object} 沙箱上下文
|
|
14
|
+
*/
|
|
15
|
+
function createSandboxContext(customContext = {}, options = {}) {
|
|
16
|
+
const {
|
|
17
|
+
timeout = 5000, // 超时时间(毫秒)
|
|
18
|
+
allowSync = false, // 是否允许同步执行
|
|
19
|
+
mockConsole = true // 是否模拟 console
|
|
20
|
+
} = options
|
|
21
|
+
|
|
22
|
+
// 创建安全的 console 对象
|
|
23
|
+
const safeConsole = mockConsole ? {
|
|
24
|
+
log: (...args) => { /* 静默执行,阻止日志泄露 */ },
|
|
25
|
+
error: (...args) => { /* 静默执行 */ },
|
|
26
|
+
warn: (...args) => { /* 静默执行 */ },
|
|
27
|
+
info: (...args) => { /* 静默执行 */ },
|
|
28
|
+
debug: (...args) => { /* 静默执行 */ }
|
|
29
|
+
} : console
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
// 用户提供的上下文
|
|
33
|
+
...customContext,
|
|
34
|
+
// 安全的 console
|
|
35
|
+
console: safeConsole,
|
|
36
|
+
// 安全的 Math 对象
|
|
37
|
+
Math,
|
|
38
|
+
// 安全的 JSON 对象
|
|
39
|
+
JSON: {
|
|
40
|
+
parse: JSON.parse,
|
|
41
|
+
stringify: JSON.stringify
|
|
42
|
+
},
|
|
43
|
+
// 安全的 Array 对象(限制方法)
|
|
44
|
+
Array: {
|
|
45
|
+
isArray: Array.isArray,
|
|
46
|
+
from: Array.from,
|
|
47
|
+
of: Array.of
|
|
48
|
+
},
|
|
49
|
+
// 安全的 String 对象
|
|
50
|
+
String: {
|
|
51
|
+
fromCharCode: String.fromCharCode,
|
|
52
|
+
fromCodePoint: String.fromCodePoint,
|
|
53
|
+
raw: String.raw
|
|
54
|
+
},
|
|
55
|
+
// 安全的 Number 对象
|
|
56
|
+
Number: {
|
|
57
|
+
isNaN: Number.isNaN,
|
|
58
|
+
isFinite: Number.isFinite,
|
|
59
|
+
parseInt: Number.parseInt,
|
|
60
|
+
parseFloat: Number.parseFloat
|
|
61
|
+
},
|
|
62
|
+
// 安全的 Boolean 对象
|
|
63
|
+
Boolean,
|
|
64
|
+
// 安全的 Object 对象
|
|
65
|
+
Object: {
|
|
66
|
+
keys: Object.keys,
|
|
67
|
+
values: Object.values,
|
|
68
|
+
entries: Object.entries,
|
|
69
|
+
assign: Object.assign,
|
|
70
|
+
create: Object.create,
|
|
71
|
+
freeze: Object.freeze
|
|
72
|
+
},
|
|
73
|
+
// 安全的 Date 对象
|
|
74
|
+
Date: {
|
|
75
|
+
now: Date.now
|
|
76
|
+
},
|
|
77
|
+
// 安全的 RegExp 对象
|
|
78
|
+
RegExp,
|
|
79
|
+
// 安全的 Error 对象
|
|
80
|
+
Error,
|
|
81
|
+
// 安全的 Promise 对象
|
|
82
|
+
Promise,
|
|
83
|
+
// 安全的 Set 对象
|
|
84
|
+
Set,
|
|
85
|
+
// 安全的 Map 对象
|
|
86
|
+
Map,
|
|
87
|
+
// 安全的 WeakMap 对象
|
|
88
|
+
WeakMap,
|
|
89
|
+
// 安全的 WeakSet 对象
|
|
90
|
+
WeakSet,
|
|
91
|
+
// 安全的 Symbol
|
|
92
|
+
Symbol,
|
|
93
|
+
// 安全的 Proxy
|
|
94
|
+
Proxy,
|
|
95
|
+
// 安全的 Reflect
|
|
96
|
+
Reflect
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* 在沙箱中执行异步代码
|
|
102
|
+
* @param {string} code - 要执行的代码
|
|
103
|
+
* @param {Object} context - 上下文变量
|
|
104
|
+
* @param {Object} options - 配置选项
|
|
105
|
+
* @returns {Promise<any>} 执行结果
|
|
106
|
+
*/
|
|
107
|
+
async function runInSandbox(code, context = {}, options = {}) {
|
|
108
|
+
const { timeout = 5000 } = options
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
const vm = new VM({
|
|
112
|
+
timeout,
|
|
113
|
+
sandbox: createSandboxContext(context, options),
|
|
114
|
+
eval: false,
|
|
115
|
+
wasm: false
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
// 包装代码为异步函数
|
|
119
|
+
const wrappedCode = `(async () => { ${code} })()`
|
|
120
|
+
return await vm.run(wrappedCode)
|
|
121
|
+
} catch (error) {
|
|
122
|
+
throw new Error(`Sandbox execution error: ${error.message}`)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 在沙箱中执行表达式(同步)
|
|
128
|
+
* @param {string} expression - 要执行的表达式
|
|
129
|
+
* @param {Object} context - 上下文变量
|
|
130
|
+
* @param {Object} options - 配置选项
|
|
131
|
+
* @returns {any} 执行结果
|
|
132
|
+
*/
|
|
133
|
+
function evaluateInSandbox(expression, context = {}, options = {}) {
|
|
134
|
+
const { timeout = 5000 } = options
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const vm = new VM({
|
|
138
|
+
timeout,
|
|
139
|
+
sandbox: createSandboxContext(context, options),
|
|
140
|
+
eval: false,
|
|
141
|
+
wasm: false
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
return vm.run(expression)
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw new Error(`Sandbox evaluation error: ${error.message}`)
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* 安全执行脚本(用于工作流中的用户脚本)
|
|
152
|
+
* @param {string} script - 脚本代码
|
|
153
|
+
* @param {Object} context - 上下文变量
|
|
154
|
+
* @param {Object} options - 配置选项
|
|
155
|
+
* @returns {Promise<any>} 执行结果
|
|
156
|
+
*/
|
|
157
|
+
async function runScriptSafely(script, context = {}, options = {}) {
|
|
158
|
+
const { timeout = 10000 } = options
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
const vm = new VM({
|
|
162
|
+
timeout,
|
|
163
|
+
sandbox: createSandboxContext(context, options),
|
|
164
|
+
eval: false,
|
|
165
|
+
wasm: false
|
|
166
|
+
})
|
|
167
|
+
|
|
168
|
+
// 将脚本包装在异步 IIFE 中
|
|
169
|
+
const wrappedCode = `
|
|
170
|
+
(async () => {
|
|
171
|
+
const { input, input_data, variables, previousResult, console } = context;
|
|
172
|
+
${script}
|
|
173
|
+
})()
|
|
174
|
+
`
|
|
175
|
+
|
|
176
|
+
return await vm.run(wrappedCode)
|
|
177
|
+
} catch (error) {
|
|
178
|
+
throw new Error(`Script execution error: ${error.message}`)
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 安全执行工作流定义
|
|
184
|
+
* @param {string} workflowCode - 工作流代码
|
|
185
|
+
* @param {Object} engine - 工作流引擎
|
|
186
|
+
* @param {Object} options - 配置选项
|
|
187
|
+
* @returns {any} 执行结果
|
|
188
|
+
*/
|
|
189
|
+
function runWorkflowSafely(workflowCode, engine, options = {}) {
|
|
190
|
+
const { timeout = 5000 } = options
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
const vm = new VM({
|
|
194
|
+
timeout,
|
|
195
|
+
sandbox: {
|
|
196
|
+
engine,
|
|
197
|
+
console: {
|
|
198
|
+
log: () => {},
|
|
199
|
+
error: () => {},
|
|
200
|
+
warn: () => {},
|
|
201
|
+
info: () => {}
|
|
202
|
+
},
|
|
203
|
+
Math,
|
|
204
|
+
JSON,
|
|
205
|
+
Promise,
|
|
206
|
+
Array,
|
|
207
|
+
Object,
|
|
208
|
+
Date,
|
|
209
|
+
RegExp,
|
|
210
|
+
Error,
|
|
211
|
+
Symbol,
|
|
212
|
+
Map,
|
|
213
|
+
Set
|
|
214
|
+
},
|
|
215
|
+
eval: false,
|
|
216
|
+
wasm: false
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
return vm.run(`(function(engine) { return (${workflowCode}) })(engine)`)
|
|
220
|
+
} catch (error) {
|
|
221
|
+
throw new Error(`Workflow execution error: ${error.message}`)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* 安全执行工作流加载脚本
|
|
227
|
+
* @param {string} content - 文件内容
|
|
228
|
+
* @param {Object} options - 配置选项
|
|
229
|
+
* @returns {Object} module.exports
|
|
230
|
+
*/
|
|
231
|
+
function runWorkflowFileSafely(content, options = {}) {
|
|
232
|
+
const { timeout = 10000 } = options
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
const vm = new VM({
|
|
236
|
+
timeout,
|
|
237
|
+
sandbox: {
|
|
238
|
+
module: { exports: {} },
|
|
239
|
+
exports: {},
|
|
240
|
+
require: () => { throw new Error('require is not allowed in sandbox') },
|
|
241
|
+
process: {
|
|
242
|
+
env: {},
|
|
243
|
+
cwd: () => '/'
|
|
244
|
+
},
|
|
245
|
+
console: {
|
|
246
|
+
log: () => {},
|
|
247
|
+
error: () => {},
|
|
248
|
+
warn: () => {},
|
|
249
|
+
info: () => {}
|
|
250
|
+
},
|
|
251
|
+
__dirname: '/',
|
|
252
|
+
__filename: '/workflow.js',
|
|
253
|
+
Math,
|
|
254
|
+
JSON,
|
|
255
|
+
Promise,
|
|
256
|
+
Array,
|
|
257
|
+
Object,
|
|
258
|
+
Date,
|
|
259
|
+
RegExp,
|
|
260
|
+
Error,
|
|
261
|
+
Symbol,
|
|
262
|
+
Map,
|
|
263
|
+
Set
|
|
264
|
+
},
|
|
265
|
+
eval: false,
|
|
266
|
+
wasm: false
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
const wrappedCode = `
|
|
270
|
+
(function(module, exports, require, process, console, __dirname, __filename) {
|
|
271
|
+
${content}
|
|
272
|
+
})
|
|
273
|
+
`
|
|
274
|
+
|
|
275
|
+
const fn = vm.run(wrappedCode)
|
|
276
|
+
const moduleObj = { exports: {} }
|
|
277
|
+
fn(moduleObj, moduleObj.exports, () => {}, { env: {}, cwd: () => '/' }, { log: () => {}, error: () => {}, warn: () => {}, info: () => {} }, '/', '/workflow.js')
|
|
278
|
+
|
|
279
|
+
return moduleObj.exports.default || moduleObj.exports
|
|
280
|
+
} catch (error) {
|
|
281
|
+
throw new Error(`Workflow file execution error: ${error.message}`)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
module.exports = {
|
|
286
|
+
createSandboxContext,
|
|
287
|
+
runInSandbox,
|
|
288
|
+
evaluateInSandbox,
|
|
289
|
+
runScriptSafely,
|
|
290
|
+
runWorkflowSafely,
|
|
291
|
+
runWorkflowFileSafely
|
|
292
|
+
}
|