Re: Joins on capabilities that have passed through different membranes

David Bruant <[email protected]> Tue, 5 Jan 2016 13:41:38 +0100
Newsgroups gmane.comp.capabilities.general
Message-ID <[email protected]>
Le 05/01/2016 02:53, Kenton Varda a =E9crit :
> Hi Mark and cap-talk,
>
> I'm interested to know if you've thought about the following problem:
>
> You want to perform a join on two capabilities A and B, which were =

> obtained from Alice and Bob respectively.
Can you provide a concrete example of why one would want to perform the =

join instead of just using the two capabilities separately?

If you obtained two capabilities from two different parties, it seems =

non-intuitive (to me at least) to want to merge them. You obtained a =

capability from Alice and can do some things with it, you obtained a =

capability from Bob and can do some things, why trying to merge them =

(especially if you do not have prior knowledge that they may point to =

the same underlying object)?

(assuming the join makes sense in the rest of my response)

> Semantically, the two capabilities point to the same object, in that =

> the messages passed to either one are ultimately routed to the same =

> place. However, the two capabilities have different conditions under =

> which they become revoked, because the original creator of the =

> capability wanted to maintain the ability to revoke Alice's and Bob's =

> access independently. Therefore, capabilities A and B are not really =

> pointing to the same object. So, what happens when you join them?
>
> The naive answer seems to be "they can't be joined because they're not =

> the same". However, this answer seems highly problematic in practice.
>
> It seems to me that it is necessary to separate the notion of the =

> endpoint object to which the capabilities point from the notion of =

> restrictions/requirements added on top of them (where cap A has the =

> requirement "Alice's access has not been revoked" and cap B has the =

> requirement "Bob's access has not been revoked"). When joining two =

> capabilities -- as long as the endpoint is the same, then the =

> requirements must be "merged".
>
> "Merging" requirements could either mean taking the intersection (the =

> joined capability is revoked if either original capability is revoked) =

> or the union (the joined capability is revoked if *both* inputs are =

> revoked).
or anything in between as suggested by others.

In your message, you're refering to the revokation policy, but =

attenuation is also something that wants to be merged when joining.

Without loss of generality, it looks like merging code needs to be added =

to the mix.

In initial context:
```
var O =3D {...}; // original capability, "same original object"

var capPolicyForAlice =3D {...};
var capPolicyForBob =3D {...};

var A =3D makeCapForAlice(O, capPolicyForAlice);
var B =3D makeCapForBob(O, capPolicyForBob);

// send A to Alice
// send B to Bob
```

in your context:
```
var A; // capability for O received from Alice
var B; // capability for O received from Bob

var M =3D merge(A, B);
```

Without more information, merge can only perform an intersection or =

union of capPolicyForAlice and capPolicyForBob (assuming there even =

exists an "intesect" or "unite" function that does something sensible =

with these objects?)

Still, the code as written above does not tell where the merge function =

comes from. Let's assume it comes from the initial context (maybe =

travelled through Alice or Bob?). But at least, I don't think there is a =

reason to assume there exists a global (and generic) merge function.
So there might need to be code that decides how the merge should happen. =

At first guess, I'd say a reducer function attached to each policy.

The code in the initial context would then look lik something like:
```
var O =3D {...}; // original capability, "same original object"

var capToPolicy =3D new WeakMap();

var capPolicyForAlice =3D {reduce(otherPolicy){
     return combine(this, otherPolicy);
     // combine can be intesect, union, or something else
}, ...};
var capPolicyForBob =3D {reduce(otherPolicy){
     return combine(this, otherPolicy);
}, ...};

var A =3D makeCap(O, capPolicyForAlice);
capToPolicy.set(A, capPolicyForAlice);
var B =3D makeCap(O, capPolicyForBob);
capToPolicy.set(B, capPolicyForBob);

function merge(o1, o2){
     var capPolicy1 =3D capToPolicy.get(o1);
     var capPolicy2 =3D capToPolicy.get(o2);

     if(!capPolicy1 || !capPolicy2)
         throw new Error('no idea how to merge these')

     var mergeCapPolicy =3D capPolicy1.reduce(capPolicy2); // this is =

asymetric

     return makeCap(O, mergeCapPolicy);
}


// send A to Alice
// send B to Bob
```

With this "architecture", it's possible to join two caps leading to the =

same object (... maybe I should have made nested weakmaps with the cap =

target as first key, but you get the point) by merging their =

revokation/attenuation requirements with arbitrary flexibility, but it's =

only possible if someone in the chain has access to the policies that =

need to be merged.

The reduce functions are given access to other cap policies at merge =

time. It worries me a bit, but at the same time, they do need these =

policies to perform the merge so it doesn't seem like abusive authority.

David