I have this turn-based NodeJs gaming app in which developers (anyone) can submit a player-robot. My NodeJS app will load all players and let them play against each other. Becaus
Don't do this yourself. Use an existing library. There are quite a few issues you have to deal with if you were to write it yourself. For example: How do you handle a user writing a never ending for-loop?
How to run untrusted code serverside?
If you are planning on writing it yourself then yes, you will need the vm
module.
By passing in an empty "sandbox" you have removed all global variables.
script.runInNewContext({});
Next you'll need to figure out how you want to handle the never ending for-loop. You'll have to create a new process to handle this scenario. Do you create 1 process to manage ALL untrusted code? If you do then you'll have to kill ALL untrusted code if a single script hangs. Do you create a new process for each untrusted code? If you do then you won't be happy with performance. Creating a new process can take a second or two. You could require the child process to "notify" the main process it's still alive. If it fails to notify within 5 seconds (or whatever your threshold is, kill the process). Note: script.runInNewContext
does contain an option that lets you specify a "timeout" (if the code takes longer than X seconds - throw an exception), but the problem with that is it allows async code (according to another Stackoverflow post), although you could defend against that by not introducing setTimeout
, setInterval
, or setImmediate
into the scope. However, even if you set it to 1 second, NO other code can run during that second in that process. So if you have 1000 scripts to run, it could take up to 1000 seconds (16 minutes) to run them all. At least running each in their own process will let them run in parallel.
Here's an example of why the timeout option won't work for you:
var script = new vm.Script('move = function move(info) { for(var i = 0; i < 100000; i++) { console.log(i); } }');
var sandbox = { move: null, console: console };
var result = script.runInNewContext(sandbox, { timeout: 1 });
sandbox.move('woah');
Next you'll need to figure out how to communicate from your main process, into a child process and then into the vm. I'm not going to get into communicating between processes as you can find that pretty easily. So, by calling script.runInNewContext
you are executing the code right then and there. Which lets you set global variables:
var script = new vm.Script('move = function move(info) { console.log("test: " + info); }');
var sandbox = { move: null, console: console };
var result = script.runInNewContext(sandbox);
sandbox.move('success');