Proxying is a fine approach theoretically -- in fact, capability-based security is built on proxying in theory. But the performance will be disappointing, taking either a lot of bandwidth (to sync upfront) or having high latency (to proxy on-demand).
After thinking about it a few days, I think I've come up with a capability-based approach that is almost as easy to use as my original "make get and set public" suggestion, but defends against probing. You seem pretty set on doing things the way you're doing them (and as a fellow opinionated system designer I can't blame you for that), but just for the sake of sharing ideas, here's my approach:
- Within a single physical store, you can create multiple logical stores. They behave exactly as if they were independent stores, but they are backed by the same physical storage, so identical blobs can be shared. These sub-stores are cheap and so can be created and deleted rapidly.
- Each sub-store is independently access-controlled. I'd use capability-based authorization but you could do identity-based as well. If you have read access to a store, you can read *any* blob in the store. If you have write access, you can write any blob -- but the hash has to be valid, of course.
- If you have read access to one store and write to another, you can sync content from the former store to the latter. Syncing a blob implies syncing all blobs that it references transitively. Nothing actually gets copied, of course; the store just updates lists of which blobs are accessible from which sub-stores. (As an optimization, this sync can happen lazily as the tree is actually traversed. In this case, trying to jump directly to the root to a deep leaf without accessing the intermediate blobs wouldn't work, but no reasonable use case would do that anyway.)
So, to share with someone, you create a new sub-store for things to be shared with them, and then you sync stuff into it.
- It's not necessary for URLs to express the full path to the target, because the URL identifies which sub-store is being used, and the system knows which blobs are visible in which stores.
- Access to a sub-store is revocable by the usual means for whatever authorization system it uses.
- Delegating access to a sub-object can be done by creating a new sub-store and syncing that object into it.
- Shared objects can be composed in their sub-store, or by syncing them into another sub-store.
Basically, it's semantically the same as the proxying approach you suggest, but without all the inefficiency. It may sound a little weird at first, but if you think about it, syncing is already a fundamental part of the camlistore model. If you can effectively accomplish higher-level tasks in terms of an operation you already have, rather than build a whole new system for it, why not do it? Kill two birds with one stone, etc.