The basic issue is that a proxy can’t just intercept operations involving private names naively, since that would allow a malicious proxy to steal private names, e.g.:
let n = new Name() obj[n] // if obj is a proxy, the proxy handler sees: handler.get(target, n, obj)
Here’s another problematic case described by Sam Tobin-Hochstadt.
An earlier design discussed at the July TC39 meeting split up all traps into “normal” and “name” variants, where the “name” variants would need to “prove” to the proxy that they knew of the intercepted private name, given its “public” part. This lead to some concern about the overhead required to transparently deal with names and lead us to explore some alternative designs, one of which is detailed below:
var whitelist = new WeakSet() var p = Proxy(target, handler, whitelist) var n1 = new Name() var n2 = new Name() whitelist.add(n1) p[n1] // calls handler.get(target, n1, p) p[n2] // calls handler.unknownPrivateName(target)
unknownPrivateNametrap is not defined, or the trap invocation returns
true, the operation is forwarded to the target (the handler never sees the name).
false, a TypeError is thrown. This is useful for proxies that don’t want to forward operations on names they don’t know about (membranes probably want to do this)
unknownPrivateNametrap for any operation involving private names (it’s as if the whitelist is always empty).
Lookup on the whitelist
Care must be taken that a proxy can’t specify its own whitelist to interfere with the lookup of private names. To this end, the whitelist must be a built-in WeakSet, and the lookup of a private name
name occurs by calling the built-in/intrinsic
WeakSet.prototype.has method. Overriding this method will not influence private name lookup. The check is performed as if the proxy performs:
WeakSet.prototype.has.call(whitelist, name) // assuming the original definition of WeakSet.prototype.has
unknownPrivateNametrap allows the handler to define its own policy w.r.t. how to deal with unknown private names.
unknownPrivateNametrap are oblivious to private names: any operation involving a private name is just forwarded to the target, without consulting the handler.
true. An effort is underway to prototype this in Spidermonkey.
unknownPrivateNametrap to return or throw explicitly, rather than having it a return a boolean. See this es-discuss thread.
Discussion during TC39 September 2012 meeting, Boston:
WeakSet.prototype.hasis changed, proxy still calls the intrinsic one (to prevent stealing of names via an overridden method)
Proxy(target, handler, [n1, n2])), which is then coerced into (i.e. whose elements are copied into) a WeakSet. One problem with this is that updating the original array-like won’t then update the coerced WeakSet, which may be confusing.
.publicproperty of private names. If we don’t drop the
.publicproperty, don’t need the whitelist but instead just a
resolvePrivateNametrap. If we stick with the whitelist, we should not pass the
.publicproperty to the unknownPrivateName/resolvePrivateName trap.
resolvePrivateName(target, name.public) → undefined | nametrap into a simpler
unknownPrivateName(target) → booleantrap. At this point, the
.publicproperty on private names is no longer needed as far as proxies are concerned.
resolvePrivateName(target, public)trap worked as follows:
resolvePrivateNametrap is not defined, or the trap invocation returns
undefined, the operation is forwarded to the target.
resolvePrivateNametrap returns the private name corresponding to
public, the operation is trapped as if the private name were in the whitelist.