JSFiddle - React, Tailwind, and code Playground
HTML
<textarea>
alert("This is some user code being evaluated in a sandbox.");
alert("We can't access the global scope using this.\nFor example (this.document): " + this.document);
alert(XMLHttpRequest);
~function () {
alert("Unfortunately the user may still access the global scope in other functions.\nFor example (this.document): " + this.document);
}();
alert("Oh well. I guess that's as 'foolproof' as it gets.\nYou'll need to make your own window and document objects though.");
</textarea>
JavaScript
// create our own local versions of window and document with limited functionality
var locals = {
window: {
},
document: {
}
};
var that = Object.create(null); // create our own this object for the user code
var code = document.querySelector("textarea").value; // get the user code
var sandbox = createSandbox(code, that, locals); // create a sandbox
sandbox(); // call the user code in the sandbox
function createSandbox(code, that, locals) {
code = '"use strict";' + code;
var params = []; // the names of local variables
var args = []; // the local variables
var keys = Object.getOwnPropertyNames( window ),
value;
for( var i = 0; i < keys.length; ++i ) {
console.log(keys[i]);
locals[keys[i]] = null;
}
delete locals['eval'];
delete locals['arguments'];
locals['alert'] = window.alert;
for (var param in locals) {
if (locals.hasOwnProperty(param)) {
args.push(locals[param]);
params.push(param);
}
}
var context = Array.prototype.concat.call(that, params, code); // create the parameter list for the sandbox
console.log(context);
var sandbox = new (Function.prototype.bind.apply(Function, context)); // create the sandbox function
context = Array.prototype.concat.call(that, args); // create the argument list for the sandbox
return Function.prototype.bind.apply(sandbox, context); // bind the local variables to the sandbox
}