Mercurial > spidermonkey-playground
changeset 27:69622f55fcf6
Made a simple SafeWrapper membrane to mediate between trust boundaries.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Mon, 22 Jun 2009 10:59:51 -0700 |
parents | 3c3ee9206419 |
children | 64de55cd54a4 |
files | sample-module.js tcb.js |
diffstat | 2 files changed, 94 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/sample-module.js Mon Jun 22 08:59:00 2009 -0700 +++ b/sample-module.js Mon Jun 22 10:59:51 2009 -0700 @@ -5,5 +5,7 @@ } exports.foo = function foo() { - imports.print(imports.blop + " " + foo.caller + " " + boo()); + + imports.print(imports.blop + " " + foo.caller + " " + boo() + + " " + imports.print.__proto__); };
--- a/tcb.js Mon Jun 22 08:59:00 2009 -0700 +++ b/tcb.js Mon Jun 22 10:59:51 2009 -0700 @@ -75,7 +75,97 @@ // Load a sample SecurableModule and run some code in it. -var module = require("sample-module.js", {blop: "hello", print: print}); +function SafeWrapper(object) { + var existingWrapper = getWrapper(object); + if (existingWrapper) + return existingWrapper; + this._wrappee = object; + return wrap(object, this); +} + +SafeWrapper.prototype = { + _maybeWrap: function(object) { + switch (typeof(object)) { + case "object": + case "function": + if (object == null) + return null; + return new SafeWrapper(object); + case "string": + case "boolean": + case "undefined": + case "number": + return object; + default: + throw new Error("Unexpected type: " + typeof(object)); + } + }, + + convert: function(wrappee, wrapper, type) { + switch (type) { + case "function": + if (typeof(wrappee) == "function") + return wrapper; + return undefined; + case "undefined": + // TODO: Malicious getter could destroy us here. + return wrappee.toString(); + case "object": + if (typeof(wrappee) == "object") + return wrapper; + return undefined; + default: + throw new Error("unexpected type: " + type); + } + }, + + getProperty: function(wrappee, wrapper, id, defaultValue) { + if (id && id != "prototype" && id[0] != "_") { + if (defaultValue === undefined) { + defaultValue = lookupProperty(wrappee, id); + } + return this._maybeWrap(defaultValue); + } + return undefined; + }, + + setProperty: function() { + throw new Error("Can't set properties on this object."); + }, + + delProperty: function() { + throw new Error("Can't delete properties on this object."); + }, + + _callOrConstruct: function(wrapee, wrapper, thisObj, args) { + if (typeof(this._wrappee) == "function") { + var wrappedArgs = []; + for (var i = 0; i < args.length; i++) + wrappedArgs.push(this._maybeWrap(args[i])); + var result; + try { + // TODO: What if the wrappee has a malicious getter for + // apply()? + result = this._wrappee.apply(this._maybeWrap(thisObj), wrappedArgs); + } catch (e) { + throw this._maybeWrap(e); + } + return this._maybeWrap(result); + } + }, + + construct: function() { + return this._callOrConstruct.apply(this, arguments); + }, + + call: function() { + return this._callOrConstruct.apply(this, arguments); + } +}; + +var module = require("sample-module.js", {blop: "hello", + print: new SafeWrapper(print)}); +module = new SafeWrapper(module); (function() { print("module.foo() is " + module.foo());