I'm trying to run trusted JS code in an "isolated" context. Basically came up with this method:
function limitedEval(src, context) {
return (function() {
with(this) {
return eval(src)
}
}).call(context)
}
This works great, however when the script is using the var
keyword it is stored in the execution context as opposed to the provided context in the with statement (which I understand is by design). So for example, the following code doesn't work:
var ctx = {};
limitedEval('var foo = "hello"', ctx);
limitedEval('alert(foo)', ctx); // error: foo is undefined
I'd like to be able to call limitedEval() multiple times and reuse the context. Is that possible?
This seems like a very interesting problem. The problem with your code is that you generate new function every time you execute limitedEval
. This means that whatever variables you create using var
keyword, will only exist within the context of that function. What you really need is to have 1 function per context and reuse that function's context. The most obvious way to do that is by using generators. Generators are essentially functions that can be paused and then restarted.
// IIFE to store gen_name
var limitedEval = function() {
// Symbol for generator property so we don't pollute `ctx` namespace
var gen_name = Symbol();
return function limitedEval(src, context) {
if(!(gen_name in context)) {
// Generator that will run eval and pause til getting the next source code
var generator = function * () {
with(this) {
while(true) {
yield eval( yield );
}
}
};
context[gen_name] = generator.call(context);
// Initially, we need to execute code until reaching the first `yield`
context[gen_name].next();
}
// First, send the source to the `eval`
context[gen_name].next( src );
// Second, get the `eval` result
return context[gen_name].next().value;
};
}();
And now you can call
var ctx = {};
limitedEval('var foo = "hello"', ctx);
limitedEval('alert(foo);', ctx);
Every limitedEval
call will now reuse whatever generator function it will find on the provided ctx
object. If the function doesn't exist, it will create it and put it on the ctx
object. Because you now have only one function per ctx
, it will reuse the function's context when creating variables with var
keyword. Note: you will not be able to look up those variables via the ctx
object, because they will only exist within the function's context.
I'm not entirely sure if you can achieve the same result without using generators.
Edit: others made great suggestions so I replaced randomly generated property with Symbol
and did with(this)
instead of with(context)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With