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());