Object literal condom using prototype

Pass the sandbox to an untrusted data source, rather than the original object. Could be made better by freezing and locking down the original object.

by danShumway

JavaScript

function getPropertyDescriptor(obj, name) {
  return Object.getOwnPropertyDescriptor(obj, name) || getPropertyDescriptor(obj.__proto__, name);
}

function sandbox(obj) {
	if (typeof obj !== 'object') {
  	throw new Error('Sandbox is only meant to be used on objects');
  }

  var child = Object.create(obj);

  //Very purposefully iterate over inherited properties
  for (key in obj) {
    let type = typeof obj[key];
    let descriptor = getPropertyDescriptor(obj, key);

    if (type === 'function') {
      throw new Error('sandbox is not meant to be used with methods');
    }
    
    if (descriptor.get || descriptor.set) {
      throw new Error('Sandbox is not meant to be used with getters/setters');
    }

    if (type === 'object') {
      child[key] = sandbox(obj[key]);
    }
  }
  
  return child;
}

var parent = {
	foo : { bar : 'bar' },
  list : ['a', 'b', 'c'],
  func : { foo : function () {} }
};
var child = sandbox(parent);

child.foo.bar = 'rab'
console.log(child.foo.bar, parent.foo.bar);

child.foo = 'oof';
console.log(child.foo, parent.foo);