Re: [Caja] An experiment and some questions
"Andrea Campi" <[email protected]>
| Newsgroups | gmane.comp.lang.e.general |
|---|---|
| Message-ID | <[email protected]> |
Hi, I don't have any answer really, but I was reasoning about similar lines, so here's more food for thought. On Feb 7, 2008 1:55 AM, <[email protected]> wrote: > I have been experimenting with writing the rewriter rules in JavaScript. I > will put that on hold for the moment while I take care of the other issues > but this raises a question. Is there a standard mechanism whereby a Caja > module can import another Caja module in a capability safe manner? > ... > * What, if any, is or should be the equivalent functionality in Caja? Should > an importing module import another into the same ___OUTERS___, or should the > ___OUTERS___ for the imported one be "cleanroom" isolated? Re-reading Mark's thesis, I wondered again about modules vs plugins. We conflate the two together, but wouldn't it be useful to keep the distinction? To recap, the Caja spec defines a module as "A package of Caja source code to be cajoled together" (and as a consequence, the cajoled output too, I would say). Furthermore, "Each instantiation of a Caja module is a separate plugin." But in fact, loadModule also instances a plugin, by calling myNewModuleHandler.handle(). Simply splitting the task would recover the distinction, and also allow a container to instance the same module twice, with different outers, without having to reload the module--which is particularly interesting if you factor in loading from the internet and JavaScript cajoling: function loadModule(module) { return primFreeze(simpleFunc(module)); } function loadModuleFromURL(url) { var module = ... // load and cajole return primFreeze(simpleFunc(module)); } function newInstance(module) { callPub(myNewModuleHandler, 'handle', [module]); } (Of course one can always build convenience functions to merge two steps into one--load a module and instance a plugin in one shot.) Now that I think of it, the only reason for having a module handler at all is that a caja module auto-loads its own instances. Changing code like this would actually allow for much simpler code, since newInstance could simply pass an outer environment as an argument. Your question about the "sub-environment" is interesting and I was reasoning on that too (looks similar in purpose to the arena out of section 11.3 of Mark's thesis, although there are differences). In general, both would be useful, as in some case you may be loading a friendly helper, and in others you may be dealing with untrusted code. Leaving the choice to the implementor may sound risky, but the fact is that even if you force the safer alternative (creating an arena) can be defeated by pushing too much authority into it. As such, you cannot really protect people from themselves. What I was trying to do is come up with a complete set of primitives for manipulating environments that provides safe and coincise idioms. As I wrote before, I really don't like the way outers are populated, I'd prefer (and I have proposed an implementation) something like: // loading a module doesn't instance a plugin <script src="aModule.js"></script> <script src="anotherModule.js"></script> <script src="untrustedModule.js"></script> <script> // create a per-plugin outers cloned from the shared outers createScope(sharedOuters, function(outers) { // get() is from my CajaCatalog package and allows you to retrieve them by // name instead of having to keep track manually createPlugin(get('aModule', outers); createPlugin(get('anotherModule', outers); }); createScope(sharedOuters, function(outers) { createPlugin(get('aModule', outers); // create an empty scope, and only endow it with a safe proxy // (defined by aModule) var sandbox = createScope(null, function(outers2) { outers2.aModule = aModuleProxy; createPlugin(get('untrustedModule', outers2); }); // or we can clone our own outers var sandbox2 = createScope(outers, function(outers2) { outers2.untrustedModule = sandbox.untrustedModule; createPlugin(get('anotherModule', outers2); }); }); </script> This is a contrived example, but it does show how easy and elegant it can get. OTOH your question is more on how can a module load another one; in that case, createScope would have to be available to it. Which means it either needs to be part of Caja, or your module would have a dependency on a 3rd party (i.e. my CajaCatalog) module. Food for thought. Next: all of this is quite similar to Mark's description of a loader, except that it trusts the module to figure out what it needs from the environment. I started thinking how could we change to above to: createPlugin(module, ['aModule': aModule, 'anotherModule': aReadOnlyFacet ]); The reason for this is, outers strike me as still providing ambient authority, no matter how little (introducing successive cloning as above makes things worse from this point of view, since it becomes harder to ensure a well-controlled environment). Explicit binding would eliminate any such risk. The problem is that we would need a good deal of metadata to be able to do so. Maybe some of it could be extraded during cajoling, but still, a lot of work to do in this area. Thoughts? Bye, Andrea