Security Demands Simplicity (was: Private Slots)

David Bruant bruant.d at gmail.com
Fri Jan 18 03:47:31 PST 2013


Le 18/01/2013 06:47, Russell Leggett a écrit :
> On Thu, Jan 17, 2013 at 9:40 PM, Kevin Smith <khs4473 at gmail.com 
> <mailto:khs4473 at gmail.com>> wrote:
>
>     It seems as if this approach to private class members also allows
>     us to describe private methods in a convenient way.  Private
>     methods can be attached to the _prototype_ of the private field
>     object, thus avoiding per-instance allocation.  Of course, the
>     correct "this" value has to be used in the expansion when calling
>     the private method, but this approach appears to be compatible
>     with mixins (whereas private symbols are not).
>
>     https://gist.github.com/4561871
>
>     Thoughts?
>
>
> I've been on the fence with the debate, but I'll admit that this 
> proposal is really winning me over. I don't know if it's too late to 
> get this syntax in, but it would be a major win for me.
syntax details aside (especially with Domenic improvements), I agree.

> I like this a lot more than private symbols.
Assuming the only valid use case for private symbols is classes, I agree

> It actually feels a lot like deconstructing an abstract data type or 
> pattern matching a case class in scala. There is something nice about 
> keeping all that extra stuff off the actual object. I'm not sure if 
> I'd still like it as much without the syntax, but maybe I would now.
>
> I have do have a few questions on this, though:
>
> 1. How does this interact with proxies? I'm guessing that a proxy will 
> not map correctly and therefore make it inaccessible. Personally, I'm 
> ok with that.
It does not interact that well because of the this-binding. Classes have 
been long expected, so will be used, so proxies have to work well with them.

     class Purse {
         private balance;

         constructor(balance = 0) {
             private.balance = balance;
         }

          getBalance() { return balance; }
     }

     var p = new Purse(6);
     var pp = new Proxy(p, {});
     console.log(pp.getBalance());

We should be able to expect p and pp to act the same in all 
circumstances. With Kevin's expansion, pp.getBalance() throws a 
TypeError, because "amp.get(this)" is not an object.
Proxy authors can work around that by returning functions bound to the 
target, but this is not free obviously (create as much bound functions 
as there are of (instance, method) pair).

The interaction between private syntax and proxies has the following 
components:
1) Do the proxy and the target act the same regarding private properties?
The answer is yes with whitelisted private symbols, no with naive 
weakmap-expanded private syntax (I explain non-naive below)
I think the answer should be yes here.

2) Does the proxy has a word to say about the access to the private 
property?
It's yes with private symbols (different trap if whitelisted or not).
The answer is yes for weakmap-expanded private syntax, but with some 
explanation. The proxy can't know about the private property, however, 
every access to something private has to be performed through something 
public (public accessor or method). Indeed, the class encapsulate access 
to private state (this isn't true of private symbols in general). Since 
the proxy can cut communication of public accesses, it can also cut 
accesses to private properties. I think that this additional simplicity 
weighs in favor of the removal of private symbols.

(I had a third point in mind and I forgot it...)


Above I've talked about naive weakmap-expanded private syntax. A less 
naive version could "override" the Proxy constructor to know about proxy 
-> target associations. Access to private state wouldn't start with the 
naive "amp.get(this)", but rather with "amp.get(proxyToFinalTarget(this) 
|| this)". ("finalTarget" in case the target of the proxy is itself a 
proxy).
For native syntax, we can imagine this setup exists before any code 
runs. The transpiler story is a bit less clear to me. I see different 
ways of writing class transpilers with different properties:
1) make classes incompatible with proxies
2) share (aka "leak") the proxyToFinalTarget function to transpiled classes
3) bring the full transpiler in the runtime so that classes can work 
with proxies (only the transpiler has access to proxyToFinalTarget)
I think different users in different contexts all have a solution to 
their need.

> 2. Can I use private as a normal variable? Can it be bound to a new 
> variable, passed as an argument, or returned from a function?
> constructor(balance = 0) {
>         let p = private;
> p.checkNum(amount);
> p.balance = balance;
>     }
> I would understand not going this route, but it definitely restricts 
> access very tightly where private member or manually using a weakmap 
> would allow it. Perhaps that edge case can just be handled by falling 
> back to manually using a weakmap.
Mark's point about private symbol being mostly useful in the context of 
class convinced me that pretty much every other context can work with 
WeakMaps.

No opinion on your third point.

David
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130118/5090e6bc/attachment.html>


More information about the es-discuss mailing list