我想在Node中运行一些看起来像这样的不受信任的代码:
for (var i = 0; i < 5; i++){
green_led(1);
sleep(500);
green_led(0);
sleep(500);
}
使用光纤,我得到了预期的同步行为:
var Fiber = require('fibers');
function sleep(ms){
var fiber = Fiber.current;
setTimeout(function(){ fiber.run(); }, ms);
Fiber.yield();
}
function green_led(active){
//...
}
Fiber(function(){
for (var i = 0; i < 5; i++){
green_led(1);
sleep(500);
green_led(0);
sleep(500);
}
}).run();
困难在于如何将代码沙盒化。必须使用Fibers使其变得非常复杂。我不太确定如何开始。我如何使用vm2将以上沙盒保存?例如,以下显然不起作用:
var code = "\
for (var i = 0; i < 5; i++){\
green_led(1);\
sleep(500);\
green_led(0);\
sleep(500);\
}\
";
function sleep(ms){
var fiber = Fiber.current;
setTimeout(function(){ fiber.run(); }, ms);
Fiber.yield();
}
function green_led(active){
//...
}
Fiber(function(){
vm.run(code);
}).run();
(因为
green_led
和sleep
对VM中的沙盒代码不可见,所以该方法将无效)。应该怎么做?要么...
也许一切都应该在VM内部运行,包括Fibers和
green_led
的实现等?还是最好让虚拟机运行的代码最少,而以某种方式将白名单/代理
green_led
和sleep
列入白名单?在灰色物质上并不是一件容易的事,首先很难理解Fibers是如何工作的! 最佳答案
实际上很简单。
var Fiber = require('fibers');
const {VM} = require('vm2');
const vm = new VM({
sandbox: {
green_led: green_led,
sleep: sleep
}
});
function sleep(ms){
var fiber = Fiber.current;
setTimeout(function(){ fiber.run(); }, ms);
Fiber.yield();
}
function green_led(active){
//...
}
vm.run(
`Fiber(function(){
for (var i = 0; i < 5; i++){
green_led(1);
sleep(500);
green_led(0);
sleep(500);
}
}).run()`
);
上面的方法通过沙箱对象传入对
Fiber
以及其他函数sleep
和green_led
的引用。这可以通过其他方式完成。例如,可以在传递给sleep
的字符串中定义green_led
和vm.run()
,而vm本身可以像这样:include
fibers
:const {NodeVM} = require('vm2');
var vm = new NodeVM({
require: {
external: true,
}
});
vm.run(
`
var Fiber = require("fibers");
function sleep(ms){
var fiber = Fiber.current;
setTimeout(function(){ fiber.run(); }, ms);
Fiber.yield();
}
function green_led(active){
//...
}
Fiber(function(){
for (var i = 0; i < 5; i++){
green_led(1);
sleep(500);
green_led(0);
sleep(500);
}
}).run()`
);
按照the documentation,注意
VM
和NodeVM
之间的区别。在上述两种方法中,只有第一种可以使用超时功能。同样,第二种方法也不免while (true) {}
等。