Reflect.hasOwn() ?

classic Classic list List threaded Threaded
22 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Reflect.hasOwn() ?

Axel Rauschmayer
ECMAScript 6 mostly eliminates the need to call methods generically (no need to use the array-like `arguments`, `Array.from()`, spread operator, etc.).

The only exception that comes to my mind is `{}.hasOwnProperty.call(obj, key)` (which is the only safe way to invoke this method). Would it make sense to provide that as a tool function, e.g. as `Reflect.hasOwn()`?

-- 
Dr. Axel Rauschmayer
[hidden email]
rauschma.de




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Peter van der Zee
On Sat, Jul 26, 2014 at 5:43 AM, Axel Rauschmayer <[hidden email]> wrote:
> The only exception that comes to my mind is `{}.hasOwnProperty.call(obj,
> key)` (which is the only safe way to invoke this method). Would it make
> sense to provide that as a tool function, e.g. as `Reflect.hasOwn()`?

That would make it unsafe again. Not so much from random people
polluting the global Object, but certainly unsafe from a security
perspective.

- peter
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Axel Rauschmayer
On Jul 26, 2014, at 6:02 , Peter van der Zee <[hidden email]> wrote:

On Sat, Jul 26, 2014 at 5:43 AM, Axel Rauschmayer <[hidden email]> wrote:
The only exception that comes to my mind is `{}.hasOwnProperty.call(obj,
key)` (which is the only safe way to invoke this method). Would it make
sense to provide that as a tool function, e.g. as `Reflect.hasOwn()`?

That would make it unsafe again. Not so much from random people
polluting the global Object, but certainly unsafe from a security
perspective.

With “safe”, I only meant w.r.t. overriding (e.g., `obj.hasOwnProperty('foo')` fails if `obj` has an own property whose name is `'hasOwnProperty'`).

Security-wise, how is `{}.hasOwnProperty.call()` safer than a hypothetical `Reflect.hasOwn()`?

Axel

-- 
Dr. Axel Rauschmayer
[hidden email]
rauschma.de




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Andrea Giammarchi-2
`obj.hasOwnProperty('foo')` fails with objects that do not inherit from `Object.prototype`

I'd personally +1 `Reflect.hasOwnProperty(genericObject, propertyName)` without going fancy with shortcuts if the meaning and the result should be exactly the same as `Object.prototype.hasOwnProperty.call(genericObject, propertyName)`

My $0.02


On Fri, Jul 25, 2014 at 9:13 PM, Axel Rauschmayer <[hidden email]> wrote:
On Jul 26, 2014, at 6:02 , Peter van der Zee <[hidden email]> wrote:

On Sat, Jul 26, 2014 at 5:43 AM, Axel Rauschmayer <[hidden email]> wrote:
The only exception that comes to my mind is `{}.hasOwnProperty.call(obj,
key)` (which is the only safe way to invoke this method). Would it make
sense to provide that as a tool function, e.g. as `Reflect.hasOwn()`?

That would make it unsafe again. Not so much from random people
polluting the global Object, but certainly unsafe from a security
perspective.

With “safe”, I only meant w.r.t. overriding (e.g., `obj.hasOwnProperty('foo')` fails if `obj` has an own property whose name is `'hasOwnProperty'`).

Security-wise, how is `{}.hasOwnProperty.call()` safer than a hypothetical `Reflect.hasOwn()`?

Axel

-- 
Dr. Axel Rauschmayer
[hidden email]
rauschma.de




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Tom Van Cutsem-3
In reply to this post by Axel Rauschmayer
2014-07-26 5:43 GMT+02:00 Axel Rauschmayer <[hidden email]>:
ECMAScript 6 mostly eliminates the need to call methods generically (no need to use the array-like `arguments`, `Array.from()`, spread operator, etc.).

The only exception that comes to my mind is `{}.hasOwnProperty.call(obj, key)` (which is the only safe way to invoke this method). Would it make sense to provide that as a tool function, e.g. as `Reflect.hasOwn()`?

Reflect.hasOwn was actually included in the Reflect API initially, as the dual to the Proxy "hasOwn" trap. When we decided to remove the trap, we also threw out Reflect.hasOwn (in keeping with the symmetry between these Reflect.* utilities and the Proxy traps).

The rationale to remove Reflect.hasOwn was that it could easily be simulated via (Reflect.getOwnPropertyDescriptor(obj,name) !== undefined). While this conses a throw-away property descriptor object, the overhead was deemed insignificant.

Overall, I'm leaning towards keeping the built-in Reflect API minimal. There's room for many more utility methods (Reflect.getPropertyDescriptors comes to mind) which can all be expressed as a library.

Cheers,
Tom

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Kevin Smith

The rationale to remove Reflect.hasOwn was that it could easily be simulated via (Reflect.getOwnPropertyDescriptor(obj,name) !== undefined). While this conses a throw-away property descriptor object, the overhead was deemed insignificant.


Sounds good.

Still, hanging "hasOwnProperty" off of Object.prototype was a mistake and a is constant source of irritation.  Perhaps the mistake could be rectified by hanging the same functionality directly off of Object?

    if (Object.hasOwn(obj, "foo")) doSomething();



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Mark S. Miller-2
In reply to this post by Peter van der Zee



On Fri, Jul 25, 2014 at 9:02 PM, Peter van der Zee <[hidden email]> wrote:
On Sat, Jul 26, 2014 at 5:43 AM, Axel Rauschmayer <[hidden email]> wrote:
> The only exception that comes to my mind is `{}.hasOwnProperty.call(obj,
> key)` (which is the only safe way to invoke this method). Would it make
> sense to provide that as a tool function, e.g. as `Reflect.hasOwn()`?

That would make it unsafe again. Not so much from random people
polluting the global Object, but certainly unsafe from a security
perspective.

Hi Peter, what is the security issue you are concerned about?


 

- peter
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Andrea Giammarchi-2
In reply to this post by Kevin Smith
why would you drop the specificity of the name?

would a Symbol be a valid second argument ?

and what if one day we'd like to introduce a hasOwnValue instead, as similar to Array#contains but for generic objects ?

Regards


On Sat, Jul 26, 2014 at 5:52 AM, Kevin Smith <[hidden email]> wrote:

The rationale to remove Reflect.hasOwn was that it could easily be simulated via (Reflect.getOwnPropertyDescriptor(obj,name) !== undefined). While this conses a throw-away property descriptor object, the overhead was deemed insignificant.


Sounds good.

Still, hanging "hasOwnProperty" off of Object.prototype was a mistake and a is constant source of irritation.  Perhaps the mistake could be rectified by hanging the same functionality directly off of Object?

    if (Object.hasOwn(obj, "foo")) doSomething();



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Axel Rauschmayer
In reply to this post by Tom Van Cutsem-3
Overall, I'm leaning towards keeping the built-in Reflect API minimal. There's room for many more utility methods (Reflect.getPropertyDescriptors comes to mind) which can all be expressed as a library.

After thinking about it some more, I agree w.r.t. these two examples:

* As far as I can tell, `hasOwnProperty` is mainly used to implement maps via objects. `Map` will eliminate this use case.
* `getPropertyDescriptors` is useful for cloning objects via `Object.create()`, where `Object.assign` can often be used in ES6.

-- 
Dr. Axel Rauschmayer
[hidden email]
rauschma.de




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Kevin Smith

* As far as I can tell, `hasOwnProperty` is mainly used to implement maps via objects. `Map` will eliminate this use case.

To a certain extent yes, but not completely.  Objects-as-maps will still be used quite frequently as object literals passed into functions (as an options object, for example).

I think that there is still a need here.  Since we are really interested in *keys*, what about this:

    Object.hasKey(obj, someKey);

which would be a more ergonomic and efficient way of saying:

    Object.keys(obj).some(key => key === someKey)

?

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Axel Rauschmayer
On Jul 26, 2014, at 20:36 , Kevin Smith <[hidden email]> wrote:

* As far as I can tell, `hasOwnProperty` is mainly used to implement maps via objects. `Map` will eliminate this use case.

To a certain extent yes, but not completely.  Objects-as-maps will still be used quite frequently as object literals passed into functions (as an options object, for example).

I think that there is still a need here.

Yes, but it’s much less urgent.

Since we are really interested in *keys*, what about this:

    Object.hasKey(obj, someKey);

Ah, good point! I hadn’t thought of symbols as property keys.

which would be a more ergonomic and efficient way of saying:

    Object.keys(obj).some(key => key === someKey)

Did you mean `Reflect.ownKeys()`? How about:

```js
Reflect.ownKeys(obj).indexOf(someKey) >= 0
```

Or, maybe in ES7:

```js
Reflect.ownKeys(obj).contains(someKey)
```

-- 
Dr. Axel Rauschmayer
[hidden email]
rauschma.de




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Kevin Smith

Did you mean `Reflect.ownKeys()`?

I meant Object.keys.  That will eliminate the inconsistency between Object.keys usage and hasOwnProperty usage that crops up sometimes:


When dealing with objects-as-maps, it's usually just the key-ness that you're interested in, not whether the property is inherited or not.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Kevin Smith


I meant Object.keys.  That will eliminate the inconsistency between Object.keys usage and hasOwnProperty usage that crops up sometimes:

Nevermind.  Brain-stall.  Sorry about the noise.


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Boris Zbarsky
In reply to this post by Tom Van Cutsem-3
On 7/26/14, 5:33 AM, Tom Van Cutsem wrote:
> The rationale to remove Reflect.hasOwn was that it could easily be
> simulated via (Reflect.getOwnPropertyDescriptor(obj,name) !==
> undefined). While this conses a throw-away property descriptor object,
> the overhead was deemed insignificant.

That depends on how much work an implementation has to perform to
produce the value of a value property, doesn't it.

In the case of some DOM objects that work can be fairly significant
(e.g. O(N) in size of the document).

On the other hand, maybe performance of Reflect.* is just not that critical.

-Boris
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Tab Atkins Jr.
In reply to this post by Kevin Smith
On Sat, Jul 26, 2014 at 11:36 AM, Kevin Smith <[hidden email]> wrote:
>> * As far as I can tell, `hasOwnProperty` is mainly used to implement maps
>> via objects. `Map` will eliminate this use case.
>
> To a certain extent yes, but not completely.  Objects-as-maps will still be
> used quite frequently as object literals passed into functions (as an
> options object, for example).

In that case, though, you don't want to use `hasOwnProperty`; you want
to allow property bags to express properties on the proto (for
example, as getters).  So this particular use-case of objects-as-maps
is irrelevant for the question at hand.

> I think that there is still a need here.  Since we are really interested in
> *keys*, what about this:
>
>     Object.hasKey(obj, someKey);
>
> which would be a more ergonomic and efficient way of saying:
>
>     Object.keys(obj).some(key => key === someKey)

This is identical to `obj.key !== undefined`, unless you're allowing
undefined to be passed explicitly as a valid argument for some reason.

~TJ
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Peter van der Zee
In reply to this post by Mark S. Miller-2
On Sat, Jul 26, 2014 at 5:14 PM, Mark S. Miller <[hidden email]> wrote:
> Hi Peter, what is the security issue you are concerned about?

Unless `Reflect` is completely sealed out of the box, you can never
know whether properties on it are the actual built-ins. That's all.

- peter
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

David Bruant-5
Le 27/07/2014 13:35, Peter van der Zee a écrit :
> On Sat, Jul 26, 2014 at 5:14 PM, Mark S. Miller <[hidden email]> wrote:
>> Hi Peter, what is the security issue you are concerned about?
> Unless `Reflect` is completely sealed out of the box, you can never
> know whether properties on it are the actual built-ins. That's all.
You can deeply freeze it yourself before any other script accesses it.

Even without doing so, let's say Reflect is not sealed.
If you change it yourself (by code you wrote or imported), you know what
to expect (or you didn't audit code you import, but them, you also know
you can only expect the worst).
If you don't change Reflect yourself, then it's third-party code which
is. But then, why did you let this third-party code access to the
capability of modifying the built-ins?
You could set up a proxy in your own domain, fetch thrid-party scripts
from there and serve them to your own domain confined (with Caja or else).

My point being that there are ways to prevent any non-trusted scripts
from modifying Reflect (assuming you stay away from script@src which
doesn't allow any form of confinment on the imported script)


For ES6, I'm not clear yet on how the module loader will work with
regards to cross-domain scripts. I believe part of the web platform
security model relies on a page not being able to read the content of
thrid-party scripts it imports via script@src (IIRC because some
websites send private data based on cookies in such scripts, so being
able to read the content of such scripts would lead to terrible data
leakage).
Does the module loader preserves such a guarantee?

David
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Peter van der Zee
On Sun, Jul 27, 2014 at 1:57 PM, David Bruant <[hidden email]> wrote:
> You can deeply freeze it yourself before any other script accesses it.

That's already assuming you are first. You may not be without your
knowledge (ISP injection, virus hijack, garden gnomes, etc). At this
point you'll be too late.

> My point being that there are ways to prevent any non-trusted scripts from modifying Reflect

And I guess I'm saying, "no, there isn't".

It'd be nice if there was some kind of mechanic of detecting/ensuring
that some built-in is indeed a built-in. That would take away all of
this pain. Maybe including a system module could fix this issue. I
doubt I'm the first here to mention that though.

- peter
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Mark S. Miller-2
Although there is some interesting work in trying to obtain security relevant guarantees from a script that isn't first, where a malicious script may instead have been first (link please if anyone has it), this work did not seem practical to me. 

My POV: A realm starts out pervasively malleable. It can only provide practical protection to some scripts within the realm from other scripts in that realm if the first script loaded into that realm is not harmful to this cause, and if a script supportive of that cause (like initSES.js) is loaded before any scripts that may be harmful to that cause.




On Sun, Jul 27, 2014 at 5:19 AM, Peter van der Zee <[hidden email]> wrote:
On Sun, Jul 27, 2014 at 1:57 PM, David Bruant <[hidden email]> wrote:
> You can deeply freeze it yourself before any other script accesses it.

That's already assuming you are first. You may not be without your
knowledge (ISP injection, virus hijack, garden gnomes, etc). At this
point you'll be too late.

> My point being that there are ways to prevent any non-trusted scripts from modifying Reflect

And I guess I'm saying, "no, there isn't".

It'd be nice if there was some kind of mechanic of detecting/ensuring
that some built-in is indeed a built-in. That would take away all of
this pain. Maybe including a system module could fix this issue. I
doubt I'm the first here to mention that though.

- peter



--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Reflect.hasOwn() ?

Peter van der Zee
On Sun, Jul 27, 2014 at 6:14 PM, Mark S. Miller <[hidden email]> wrote:
> Although there is some interesting work in trying to obtain security
> relevant guarantees from a script that isn't first, where a malicious script
> may instead have been first (link please if anyone has it), this work did
> not seem practical to me.

I'm not familiar with actual deep research in this area for JS.

Seems to me like a syntactic way of including a module that's
guaranteed to be a system module (completely sealed of the shelf)
would circumvent a lot of these problems. For example, a module that
gives you a fresh default global object with all the built-ins
guaranteed unchanged. Since the syntax can't really be affected by an
earlier script and the language could define a hardcoded system
module, this kind of approach seems viable to me. But we're digressing
from the topic.

- peter
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
12