6

How do I manage it to place variables and run code inside Sandbox() through Run()?

function Sandbox() {
    this.test = 'insandbox';
}

Sandbox.prototype.Run = function(src) {
    eval.call(this, src);
};

Sandbox.prototype.getvar = function(name) {
    return this[name];
};

var bx = new Sandbox();
bx.Run('var x = 1;');
print(bx.getvar('test'))
print(bx.getvar('x'))        // undefined
print(x)

Please no answers regarding eval() is insecure and I shouldn't use it. Please no answers regarding the use of setters/getters.

Thanks for reading!

calquin
  • 421
  • 1
  • 4
  • 10

3 Answers3

3

This might not be what you're looking for but what if instead of passing a string to your sandbox you pass a function. This even allows the possibility of using eval for source files.

Your code would work like this:

...

Sandbox.prototype.Run = function(fn){
    fn.call(this);
}

var bx = new Sandbox();
bx.run(function(){
    this.x = 1;
});
bx.getVar("x") // 1

then if you wanted to use eval all you would have to is write a function to append the function syntax

/* source.js */
this.x = 1;
this.blah = "Hello, World!";

With:

Sandbox.prototype.evaluate = function(src){
     return eval("function(){" + src + "}");
}

bx.Run(Sandbox.evaluate(src));
bx.getVar("x") // 1
bx.getVar("blah") // "Hello, World!"

Also with this method you can pass the sand-boxed code objects and functions to use by passing them to the function which will simulate an entirely new pseudo-environment to work with.

Edit: I did a little research on the perfect answer to your question which is

Can I iterate over the variables declared in a local scope?

And the answer is no (StackOverflow). It looks like it's a limitation of javascript at the moment. Hopefully something like this will emerge in the new spec.

My idea at the moment would be to eval the source to make all the var statements go to the window object which, with some effort, could be iterated over and added to the Sandbox object manually.

Like this Warning: horribly simplified

(function(){
    var src = get_source_file();
    eval(src);
    iterate_over_each_newly_created_window_property(function(property, value){
         bx[property] = value;
         window[property] = undefined;
    });
})();

Edit 2: MY IDEA WORKS =)

function Sandbox(){
    return this;
}
Sandbox.prototype.run = function(src){
    // Take a snapshopt of the window object before
    var before = {};
    var prop;
    for(prop in window){
        before[prop] = true;
    }
    // Then evaluate the source
    window.eval(src);
    // Then see what changed
    var changed = [];
    for(prop in window){
        if(!before[prop]){
            // Add to the sandbox object
            this[prop] = window[prop];
            delete window[prop];
        }
    }
}
var bx = new Sandbox();
bx.run("var x = 'Hello, World!';");
alert(bx.x);

A working example (jsFiddle)

function Sandbox(){
this.keys = [];
this.values = [];
    return this;
}
Sandbox.prototype.eval = function(src){
    var before = {}, prop, fn;
    // Take a snapshopt of the window object before
    src = "function(" + this.keys.join(",") + "){" + src + "}";
    src = src.replace(/var/g, "");
    /* I'm not a wisard at regex so a better one should be used avoid this bug
    var x, y, z; */
    for(prop in window){
        before[prop] = true;
    }
    // Then evaluate the source
    fn = window.eval(src);
    fn.apply(window, this.values);
    // Then see what changed
    for(prop in window){
        if(!before[prop]){
            // Add to the sandbox object
            this.keys.push(prop);
            this.values.push(window[prop]);
            this[prop] = window[prop];
            delete window[prop];
        }
    }
}
var bx = new Sandbox();
bx.eval("var x = 1;");
bx.eval("var y = x;");
alert(bx.x);
alert(bx.y);

Edit 3: Fixed bug to your specifications

Now I know there are bugs in it and some functions that might make it go haywire. Now it's your job to clean up the code for real use. I gave you conceptually how it can be done.

Community
  • 1
  • 1
  • This is not what I can use in my situation but thanks for your support! – calquin Aug 11 '11 at 03:11
  • No, those variables should be placed inside the Sandbox object. – calquin Aug 11 '11 at 03:28
  • This is not that bad! :-) I was just thinking about using with() for that purpose. I will def. look over that approach, perhaps we can fine tune it a bit more. I do not like that window.eval() ;-) – calquin Aug 11 '11 at 04:19
2

This should work:

...

Sandbox.prototype.run = function(src) {
    eval(src);
};

...

bx.run('this.x = 1;');

...
Jordão
  • 55,340
  • 13
  • 112
  • 144
  • bx.getvar('x') will result in undefined. i would like not to need the use 'this' in the expression for Run(). – calquin Aug 11 '11 at 01:56
  • 1
    You need to use `this` if you want it to work. `var` creates a local variable that's not associated with the instance of `Sandbox`. – Jordão Aug 11 '11 at 02:00
  • Yes this works. Thank you. But I can not add this to every expression because I don't know what exact kind of expression is used every time for Run(). – calquin Aug 11 '11 at 02:13
  • But isn't it possible to set a local variable and use getvar() to return the local variable? – calquin Aug 11 '11 at 02:47
  • No, the local variable is gone as soon as its scope ends. And that scope is not part of the `getvar` method. – Jordão Aug 11 '11 at 02:48
1

you could use a closure

Sandbox.prototype.Run = function(src) {
    (function(_src){
        eval.call(this, _src);
    })(src);
};
Ilia Choly
  • 18,070
  • 14
  • 92
  • 160