littledan / proposal-proxy-transparent

Transparent Proxies--tunneling private fields, etc.
8 stars 0 forks source link

Counter proposal to avoid a new class of proxy #4

Open caridy opened 6 years ago

caridy commented 6 years ago

This proposal is based on the SES discussion documented here: https://github.com/littledan/proposal-proxy-transparent/issues/3, it also attempt to solve most of the concerns reflected in #3.

Proposal:

const p = new Proxy(o, { unwrap: (target) => target });

By introducing a new hook called unwrap for existing proxies, the author of the proxy can control how the proxy behaves when in comes to operations that require access to internal slots, private fields and others. This hook is intended to be invoked by the engine and should return the object that should be used to extract internal slots, private fields and others "creatures".

I don't see the necessity to expose a way to hit that hook from user-land. The premise has always be that you can't really observe when an object is a proxy in user land, and that invariant should remain in place IMO.

Backward compatibility:

For this to be backward compatible, the default behavior of the hook must always return the proxy instance instead of the original target, which seems analog to choosing Proxy.transparent instead of Proxy.

Pros:

littledan commented 6 years ago

A possible tweak: We could have a {transparent: true} option. (I'm not sure if we want an observable callback for each private name read!)

caridy commented 6 years ago

{transparent: true} is not enough because shadow target requires more control. The owner of the proxy stores the original target somewhere (some folks put it on the handler if it is created per instance, others use a weakmap, etc). It has to be something that allows some computations to determine how to unwrap.

ljharb commented 6 years ago

The premise has always be that you can't really observe when an object is a proxy in user land

Currently, you can observe when any builtin is a proxy (except for arrays, and plain objects), via checking for the presence of specific internal slots.

caridy commented 6 years ago

Yes, thanks for the clarification @ljharb.

littledan commented 6 years ago

@ljharb I'm not sure what you mean; you can observe whether something is a built-in type, but I don't see how you can use that to determine whether it's a Proxy or another kind of object that's not the built-in type.

ljharb commented 6 years ago

@littledan ah, that is true - but you can determine if it's attempting to masquerade as a built-in-type (yet lacks the appropriate slots).

littledan commented 6 years ago

Not sure what you're referring to. Anyway I believe it's a design goal for Proxy to be undetectable.

ljharb commented 6 years ago

As I understand it, it's a design goal for it to be undetectable in the presence of a membrane - one that can control access to all builtins. To be truly undetectable, indeed, it would need to tunnel all internal slot access.

littledan commented 6 years ago

I'm not sure what you mean by "in the presence of a membrane". The idea is, given an object, you can't tell if it's a Proxy. Tunneling is a feature request but not a prerequisite to meet that goal.

ljharb commented 6 years ago

I don’t agree that’s the idea, otherwise internal slots would have tunneled in the first place.

Proxies to functions, in particular, are detectable via a combo of typeof and Function.prototype.toString.call.

littledan commented 6 years ago

I am not saying that a Proxy of an object is indistiguishable from its target. That is clearly not a goal, and not met by the definition of Proxy. What is a goal, I believe, is that it should be impossible to implement a Proxy.isProxy function, that, given an object, checks whether it's a Proxy. cc @erights

ljharb commented 6 years ago

Ah, indeed - and this is currently impossible for an arbitrary object, but still quite possible for an object of a subset of known alleged types.

littledan commented 6 years ago

Yes, I agree that it is possible to use a Proxy to create an object which is not an instance of a particular type (just as it is possible to do the same with object literals).

dead-claudia commented 6 years ago

Just a thought: shouldn't the second parameter just be the proxy itself, rather than some object wrapper? That way, you're not wastefully allocating an object just to choose how to unwrap. (Most handlers would just return either the target or the handler, without any real logic going on.)

caridy commented 6 years ago

@isiahmeadows those are mechanism that can be implemented in user-land, just as we do it today in membranes with shadow targets. You can tie the target or handler to the proxy instance itself, or just the closure. Either way, the default behavior is to return the proxy during unwrapping, so if you define that hook is probably because you want to do something else.

dead-claudia commented 6 years ago

@caridy Good point. So what's the second argument for, then?

caridy commented 6 years ago

Oh, jejeje! my bad, copy and paste issue, there is no second argument, the handler is the this value. I will update the description.

Igmat commented 5 years ago

Does anybody has a plans to move forward with it?

littledan commented 5 years ago

Help would be welcome here! I don't plan to push this proposal forward myself.

Igmat commented 5 years ago

@littledan, ok, I understand you. As for me it seems pretty solid proposal, how can I help? Docs, polyfill, spec?

littledan commented 5 years ago

I'm not pursuing this proposal personally because it's already gotten a bit of negative feedback. The next steps from here would be to figure out how to respond to that feedback.

At this point, it's more about working through the design issues with the people who raised the concerns. Maybe @erights can invite you to the SES call to discuss the issue. It'd also be good to discuss with implementers whether it's practical to implement these proposals.

Igmat commented 5 years ago

I would love to join SES call if it may help to adress his concerns. So @erights, are you interested?

caridy commented 5 years ago

@Igmat provide an email and we can invite you to the SES meeting on Tue.

Igmat commented 5 years ago

@caridy ichulinda@gmail.com

mhofman commented 5 years ago

I think for this unwrap approach to work for all hidden data "creatures", it needs to work for key identity tests for containers such a WeakMap.

However I'm having a hard time figuring out how that would work. @rdking and I are discussing that in https://github.com/rdking/proposal-proxy-transparency/issues/1 and I created https://github.com/mhofman/proposal-proxy-resolve-playground to help figuring out a solution.

Any ideas and other insight would be greatly appreciated :)

littledan commented 5 years ago

I don't think we could make transparent proxies have the same identity... This just gets too weird.

mhofman commented 5 years ago

I don't think we could make transparent proxies have the same identity... This just gets too weird.

I tend to agree but we need to find a way to make transparent proxies work with user implementations of hidden data. Restricting it to internal slots and other host objects isn't sufficient in my opinion.

I'm ok however restricting which kind of user implementations can handle transparent proxies. WeakMap and other containers seem like a good place to start.

For that reason I'm trying to see if @isiahmeadows / @rdking idea for a resolve trap could apply to such container, which basically means some way of having the proxy trap override what object should be used as the key in containers.