Mutable Proto
I would like to see Object.setPrototypeOf(object, proto) too and a disappeared proto 'till now breaking too much.
It would be much easier to implement all shenanigans via Object.defineProperty(Object.prototype, 'proto', {whatever}); rather than fix current non-standard proto ...
+1
I certainly agree, but it has been decided otherwhise by the TC39 members and I doubt they’re willing to revert their decision.
De : Andrea Giammarchi Envoyé : 18 mars 2013 17:08 À : Nathan Wall Cc : es-discuss at mozilla.org Objet : Re: Mutable Proto
I would like to see Object.setPrototypeOf(object, proto) too and a disappeared proto 'till now breaking too much.
It would be much easier to implement all shenanigans via Object.defineProperty(Object.prototype, 'proto', {whatever}); rather than fix current non-standard proto ...
+1
On Mon, Mar 18, 2013 at 9:04 AM, Nathan Wall <nathan.wall at live.com> wrote:
A previous thread [1] brought to my attention the fact that objects which don't inherit from Object.prototype won't have mutable proto. This was something I had missed and breaks some scripts I'm currently using because I have objects which I don't want to inherit from Object.prototype but for which I do want to have mutable proto.
Testing in Firefox Nightly I found this workaround:
var x = { }, y = { foo: 'bar' };
x.__proto__ = y;
console.log(1, x.foo);
// => 1 'bar'
x.__proto__ = null;
console.log(2, x.foo);
// => 2 undefined
x.__proto__ = y;
console.log(3, x.foo);
// => 3 undefined
var _setPrototype = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set,
setPrototypeOf = Function.prototype.call.bind(_setPrototype);
setPrototypeOf(x, y);
console.log(4, x.foo);
// => 4 'bar'
Is this workaround a temporary bug in Firefox's current implementation? Or will this be the spec'ed behavior for ES6? Can we use such a method to mutate prototype on objects which don't inherit from Object.prototype?
+1!
It would be great if someone will explain in detail why Object.setPrototypeOf is no go.
We definitely need mutable prototype, but having it via proto really breaks the language.
Any function that blindly extends object with provided hash is affected e.g. extend(obj, { proto: Error.prototype }). Additionally it means that we need to serialize any user input which eventually may be used as key on a dictionary e.g. data[userDefinedName]. That's bad, and it's hard for me to believe we can't do it better.
François REMY-3 wrote:
I certainly agree, but it has been decided otherwhise by the TC39 members and I doubt they’re willing to revert their decision.
De : Andrea Giammarchi Envoyé : 18 mars 2013 17:08 À : Nathan Wall Cc : es-discuss at mozilla.org Objet : Re: Mutable Proto
I would like to see Object.setPrototypeOf(object, proto) too and a disappeared proto 'till now breaking too much.
It would be much easier to implement all shenanigans via Object.defineProperty(Object.prototype, 'proto', {whatever}); rather than fix current non-standard proto ...
+1
On Mon, Mar 18, 2013 at 9:04 AM, Nathan Wall <nathan.wall at live.com> wrote:
A previous thread [1] brought to my attention the fact that objects which don't inherit from Object.prototype won't have mutable proto. This was something I had missed and breaks some scripts I'm currently using because I have objects which I don't want to inherit from Object.prototype but for which I do want to have mutable proto.
Testing in Firefox Nightly I found this workaround:
var x = { }, y = { foo: 'bar' }; x.__proto__ = y; console.log(1, x.foo); // => 1 'bar' x.__proto__ = null; console.log(2, x.foo); // => 2 undefined x.__proto__ = y; console.log(3, x.foo); // => 3 undefined var _setPrototype = Object.getOwnPropertyDescriptor(Object.prototype,
'proto').set, setPrototypeOf = Function.prototype.call.bind(_setPrototype); setPrototypeOf(x, y); console.log(4, x.foo); // => 4 'bar'
Is this workaround a temporary bug in Firefox's current implementation? Or will this be the spec'ed behavior for ES6? Can we use such a method to mutate prototype on objects which don't inherit from Object.prototype?
[1] esdiscuss/2013-March/029176
es-discuss mailing list es-discuss at mozilla.org, mail.mozilla.org/listinfo/es-discuss
es-discuss mailing list es-discuss at mozilla.org, mail.mozilla.org/listinfo/es-discuss
Mariusz Nowak
On Wed, Mar 20, 2013 at 5:51 AM, Mariusz Nowak < medikoo+mozilla.org at medikoo.com> wrote:
+1!
It would be great if someone will explain in detail why Object.setPrototypeOf is no go.
This was recorded as the resolution of record in January 2013 rwldrn/tc39-notes/blob/master/es6/2013-01/jan-29.md#45-why-standardizing-on-proto-and-not-definegsetter-lookupgsetter, specifically: esdiscuss/2012-May/022904
Mariusz Nowak wrote:
+1!
It would be great if someone will explain in detail why Object.setPrototypeOf is no go.
We've been over this many times, e.g. at
To recap,
-
proto is out in the field, a de-facto standard on "mobile", and not going away. Adding another API doesn't help, it hurts.
-
SES and other secure subsets want same-frame (global object, "realm") mashups of code that may use proto and code that must not, but Object.setPrototypeOf is a per-frame capability that would have to be removed, breaking the former class of code.
Any function that blindly extends object with provided hash is affected e.g. extend(obj, { proto: Error.prototype }).
No, that depends on how extend works. If it uses Object.defineProperty or equivalent, then nothing is broken and the setter on Object.prototype for proto is not run.
Additionally it means that we need to serialize any user input which eventually may be used as key on a dictionary e.g. data[userDefinedName].
Only if you use assignment into an object that delegates to Object.prototype, but see (1) above: this hazard already exists. Don't do that; JSON doesn't, and Object.create(null) gives a way to create dictionaries.
Yes, the problems you cite are real, but they are already part of the de-facto proto standard (1). Beyond that, Object.setPrototypeOf is a mistake due to (2).
I didn't get a direct response to my question about mutating proto on objects which don't inherit from Object.prototype, but I'm inferring from [1] that it won't be possible. I find this unfortunate, but I realize this issue has seen a lot of discussion in the past and there are reasons for the current decision. I will see how I can make my code cope with reality.
Nathan
Le 20/03/2013 16:36, Nathan Wall a écrit :
I didn't get a direct response to my question about mutating proto on objects which don't inherit from Object.prototype, but I'm inferring from [1] that it won't be possible. I find this unfortunate, but I realize this issue has seen a lot of discussion in the past and there are reasons for the current decision. I will see how I can make my code cope with reality.
Could you describe how you use proto on objects not inheriting from Object.prototype?
From what I know there are 2 main use cases:
-
object as map changing the prototype enable changing different "default values". I guess any solution to that problem either looses the object syntax (maybe unless using proxies) like using an ES6 Map or has non-trivial runtime cost. Or the code needs to be reorganized so that the object is always created after the prototype (using Object.create for instance)
-
Subclassing ES6 will have classes with inheritance. That's mostly syntax sugar on top of what's already possible, but that works.
Do you have a use case that belongs in neither of these categories?
Le 20/03/2013 16:15, Brendan Eich a écrit :
To recap,
proto is out in the field, a de-facto standard on "mobile", and not going away. Adding another API doesn't help, it hurts.
SES and other secure subsets want same-frame (global object, "realm") mashups of code that may use proto and code that must not, but Object.setPrototypeOf is a per-frame capability that would have to be removed, breaking the former class of code.
(...)
Yes, the problems you cite are real, but they are already part of the de-facto proto standard (1).
Agreed. From the spec/implementor point of view, proto has to be added as de-facto standard because it is used. From the developer point of view, it is not because it's in the language that it's a good idea to use it. Quite the opposite, I'd like to reiterate that devs should make "delete Object.prototype.proto" the second line of their code (first line is "use strict";). Devs shouldn't make the mistake to think that proto in the standard makes it a good or legitimate feature.
proto in ES6 is yet another ECMAScript Regret [1]
David
[1] DavidBruant/ECMAScript-regrets (I haven't found much time to write more, but issues are more interesting to read than just the part that's been written down)
I don't understand where is the problem ... any library that uses proto can and should be updated with a shim waiting for next version of JS to support it.
Object.setPrototypeOf = function (object, proto) { object.proto = proto; return object; };
That does not look bad at all to me, educate developers out there that proto is harmful and forbidden 'cause saying "we can't do much is already used" doesn't mean is OK to use it, same as polluting Object.prototype, still possible, nobody does it (not in an old fashioned way at least)
Best
Le 20/03/2013 19:04, Andrea Giammarchi a écrit :
I don't understand where is the problem ... any library that uses proto can and should be updated with a shim waiting for next version of JS to support it.
Which library? What are the inconsistencies between the current proto draft spec and how libraries use proto today? Please be very specific; that's quite relevant when doing a de facto standard so it's important to know.
Object.setPrototypeOf = function (object, proto) { object.proto = proto; return object; };
That does not look bad at all to me, educate developers out there that proto is harmful and forbidden 'cause saying "we can't do much is already used" doesn't mean is OK to use it, same as polluting Object.prototype, still possible, nobody does it (not in an old fashioned way at least)
What's your point here? I don't understand why Object.setPrototypeOf should be added or shimmed if the best practice is to avoid using proto.
I think zepto is using that to modify runtime NodeList results after querySelectorAll but in any case it was not me saying that proto is used already. I use it only to shim getPrototypeOf to be honest and I don't think is a good idea to use it at all.
My point is that Object.setPrototypeOf does not need a property loads of shenanigans as proto is so that no Object.prototype.proto would ever exist anywhere.
I don't even know why that existed in first place,to be honest ... so do not use it, pass through Object.setPrototypeOf, same as you would suggest pass through Object.defineProperty instead of using Object.prototype.defineGetter defineSetters, both "de facto standards" some time ago.
So, reverting the question, what is your point saying that proto is better than Object.setPrototypeOf ?
David Bruant wrote:
Le 20/03/2013 16:36, Nathan Wall a écrit :
I didn't get a direct response to my question about mutating proto on objects which don't inherit from Object.prototype, but I'm inferring from [1] that it won't be possible. I find this unfortunate, but I realize this issue has seen a lot of discussion in the past and there are reasons for the current decision. I will see how I can make my code cope with reality. Could you describe how you use proto on objects not inheriting from Object.prototype?
From what I know there are 2 main use cases:
object as map changing the prototype enable changing different "default values". I guess any solution to that problem either looses the object syntax (maybe unless using proxies) like using an ES6 Map or has non-trivial runtime cost. Or the code needs to be reorganized so that the object is always created after the prototype (using Object.create for instance)
Subclassing ES6 will have classes with inheritance. That's mostly syntax sugar on top of what's already possible, but that works.
Do you have a use case that belongs in neither of these categories?
Hi David.
I would add (3) Integrity/Security. When you don't want mucking with Object.prototype
to be able to influence a script.
My current use-case has to do with shimming private properties into ES5. It may be something I want to continue doing in ES6 depending on how private properties are implemented in ES6. The full working library is available at Nathan-Wall/Secrets
Let me explain the relevant portions for why I want mutable proto on objects which don't inherit from Object.prototype.
Take this simple, highly contrived example:
var apple, grannySmith; (function() { var priv = createSecret();
apple = { get foodType() { return priv(this).foodType; }, get color() { return priv(this).color; }, toString: function() { return this.color + ' ' + this.foodType; } };
priv(apple).foodType = 'fruit'; priv(apple).color = 'red';
grannySmith = Object.create(apple);
priv(grannySmith).color = 'green'; })();
apple.toString(); // => 'red fruit' grannySmith.toString(); // => 'green fruit'
In ES5 Secrets works by overriding Object.getOwnPropertyNames
to hide a secret property. In ES6, this could work using makePrivate
, WeakMaps, or whatever mechanisms are available to create private state.
priv
is a function which returns an object which represents the private state of any object.
The important part is that in order for the above to work, secrets need to respect prototypal inheritance. When grannySmith.toString
is called, it calls grannySmith.foodType
, which accesses the "private" foodType
property. Since grannySmith
doesn't have a foodType
property on its private object, it should look up the inheritance chain for apple
's foodType
private property.
The following code snip shows how this is set up for the non-mutable proto case:
(In the following code create = Object.create
and getPrototypeOf = Object.getPrototypeOf
.)
function createSecret() {
var id = nextUniqueId();
return function secret(obj) {
var S, proto, protoS, protoSTest,
// This function generates an object which is stored on a hidden property of obj
.
secrets = Secrets(obj)
if (secrets) {
// The id is used to distinguish between different secret functions.
S = secrets[id];
if (!S) {
proto = getPrototypeOf(obj);
// Create a new object which inherits from the secret of obj's prototype.
secrets[id] = S = create(proto ? secret(proto) : null);
}
return S;
} else
// The object may have been frozen in another frame.
throw new Error('This object doesn't support secrets.');
};
}
As you can see, the private objects inherit from other private objects which eventually inherit from null. For instance:
var A = { }; var B = Object.create(A); var C = Object.create(B);
var priv = createSecret(); var privC = priv(C);
C's prototype chain looks like:
null -> Object.prototype -> A -> B -> C
so privC's prototype chain looks like:
null -> priv(Object.prototype) -> priv(A) -> priv(B) -> priv(C)
where priv(X)
is the private object used to store the private state of X.
In order to get this to work for mutable proto, the private objects need to change their prototypes whenever the public object changes its prototype.
var D = { }; C.proto = D; // C's new prototype chain: // null -> Object.prototype -> D -> C
So we need to change priv(C)'s prototype chain to match.
But priv(C) should not inherit from Object.prototype for two reasons. (1) Because it should really inherit from priv(Object.prototype), the private object which represents the private state of Object.prototype, and (2) for security reasons, so that someone can't define a setter on Object.prototype to retrieve properties that are intended to be private. You shouldn't be able to set properties on priv(Object.prototype) unless you have access to the priv
function.
Going back to the apple example, the following is a potential attack if priv(apple) inherits from Object.prototype:
Object.defineProperty(Object.prototype, 'foodType', { set: function(value) { tellTheWorld('Setting foodType to ' + value); } });
Here's an update which attempts to solve this for mutable proto.
The following code references protoIsMutable
which is either true
or false
depending on whether mutable proto has been detected in this environment. setPrototypeOf
needs to be available; a running implementation is shown under the createSecret
function.
function createSecret() {
var id = nextUniqueId();
return function secret(obj) { var secrets = Secrets(obj), S, proto, protoS, protoSTest; if (secrets) { S = secrets[id]; if (!S) { proto = getPrototypeOf(obj); secrets[id] = S = create(proto ? secret(proto) : null); } else if (protoIsMutable) { proto = getPrototypeOf(obj); protoS = getPrototypeOf(S); protoSTest = proto == null ? null : secret(proto); if (protoSTest !== protoS) setPrototypeOf(S, protoSTest); } return S; } else // The object may have been frozen in another frame. throw new Error('This object doesn't support secrets.'); };
}
var setPrototypeOf = (function() {
if (!protoIsMutable) return;
var _setProto = Object.getOwnPropertyDescriptor(Object.prototype, 'proto').set; if (_setProto) return Function.prototype.call.bind(_setProto);
// If the implementation supports mutable proto but doesn't have a proto setter, see if // mutable proto is possible on objects which don't inherit from Object.prototype. // This behavior has been observed on Chrome 25 but is believed to be fixed on a modern V8. // esdiscuss/2013-March/029244 // However, the version of V8 mentioned in the above post does not support proto setter. // It is thought that this version of V8 will not support mutable proto on objects which // don't inherit from Object.prototype. // It is also currently unknown which direction the spec will go on this issue. var A = Object.create(null), B = Object.create(null); A.test = 5; B.proto = A; if (B.test == 5) return function(obj, proto) { obj.proto = proto; };
// Unfortunately, it sounds like ES6 may be on course for this route. return function() { throw new Error( 'Mutable prototype is supported by this implementation, but it does not support mutating the prototype ' + 'of an object which doesn't inherit from Object.prototype' ); };
})();
This updated version will fail, however, for implementations which support mutable proto but don't support mutating proto on objects which don't inherit from Object.prototype
.
Nathan
On Wed, Mar 20, 2013 at 3:40 PM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:
I think zepto is using that to modify runtime NodeList results after querySelectorAll but in any case it was not me saying that proto is used already. I use it only to shim getPrototypeOf to be honest and I don't think is a good idea to use it at all.
My point is that Object.setPrototypeOf does not need a property loads of shenanigans as proto is so that no Object.prototype.proto would ever exist anywhere.
I don't even know why that existed in first place,to be honest ... so do not use it, pass through Object.setPrototypeOf, same as you would suggest pass through Object.defineProperty instead of using Object.prototype.defineGetter defineSetters, both "de facto standards" some time ago.
IE never implemented the defineGetter defineSetter but they did implement the ES5 Object meta APIs and are implementing proto for parity with browsers that currently support it—this is the big difference. This is in addition to the rationale recorded here rwldrn/tc39-notes/blob/master/es6/2013-01/jan-29.md#45
never cared about IE much on mobile and I do not care about 100% or proto support ... there is 100% of Object.prototype pollution support since ever and everybody knows that is a bad technique, specially done through direct property rather than through a descriptor.
What is the point then ? Should I feel free to shoot in my foot and in all libraries foot because I can change even Object.prototype.proto ? I don't think so and I don't understand what is anyone point here.
TC39 decided to do not even talk about proto now is the best thing ever to suggest and use because supported ... is not standard and loads of shenanigans, is an undesired property full of undesired behaviors ... and still you all are protecting it for which reason, exactly? Either you make it standard, or you get rid of it ASAP allowing developers that use it already to migrate, gracefully, through Object.setPrototypeOf ... and considering setPrototypeOf, hidePrototypeOf, and freezePrototypeOf method in ES7 ... how does that sound?
'cause otherwise we can just stop reading specs, if non standard stuff is sacre more than specs and standards or potential, better, solutions.
Best
Your writing is unclear and overlong, and full of unjustified airs of grievance -- please work on it.
To recap yet again (last time): proto is a de-facto standard we cannot defeat, whether anyone likes it or not. Adding Object.setPrototypeOf does not help, because code won't migrate to it completely so we'll be stuck with two APIs.
If against all odds, all code everywhere did magically drop proto in favor of Object.setPrototypeOf, then SES and similar subsets would be unable to protect secure code from ambient Object.setPrototypeOf usage from the insecure side on the secure side's objects, unless Object.setPrototypeOf were removed -- but that would break insecure-side code that reasonably (per your wishes) uses Object.setPrototypeOf in lieu of proto.
Now do you understand?
yes, SES, the non real world out there, needs proto ... shenanigans all over the world because of 'proto' ain't important.
Thanks to be clear on it
If against all odds, all code everywhere did magically drop proto in favor of Object.setPrototypeOf, then SES and similar subsets would be unable to protect secure code from ambient Object.setPrototypeOf usage from the insecure side on the secure side's objects, unless Object.setPrototypeOf were removed -- but that would break insecure-side code that reasonably (per your wishes) uses Object.setPrototypeOf in lieu of proto.
Well, I don't completely agree with you on this. It would be easy to protect objects using
Object.freezePrototype(o)
or
Object.definePrototypeSetter(o, function(o,p) { if(isValid(p)) return p else throw new Error('...'); }).
I would really like to know how you expect SES to secure a property that lays in the Object.prototype object and could be overriden by a malicious object to intercept your proto setter calls.
BTW, you could also redefine Object.setPrototypeOf to match your security requirements without completely removing it.
I know it's not your point of view, but if MSFT never implements proto in IE (except behind a 'compatibility' mode for sites that rely on it, in the Opera's browser.js way) and if everbody do implement Object.setPrototypeOf(...) then the few libraries using proto will end up migrating to Object.setPrototypeOf(...) or use a polyfill for proto in the case it isn't supported.
Phasing out failed experiments is possible. I don't think a browser that doesn't support <blink> or <marquee> or even document.layers would have a lot of problems to view the web as it's now, yet I remember a time where document.layers <marquee> were used quite a lot. I do think the argument used to claim proto is unfixable is somewhat wrong.
Andrea Giammarchi wrote:
yes, SES, the non real world out there, needs proto ... shenanigans all over the world because of 'proto' ain't important.
SES is deployed on major Google properties. I recall also Yahoo! but not sure if still up.
I think again you are out of line. Am I wrong?
On 3/21/2013 11:39 AM, Brendan Eich wrote:
Andrea Giammarchi wrote:
yes, SES, the non real world out there, needs proto ... shenanigans all over the world because of 'proto' ain't important.
SES is deployed on major Google properties. I recall also Yahoo! but not sure if still up.
I think again you are out of line. Am I wrong?
I don't agree with Andrea's sentiment, but this would still be
surprising to me. I would have thought that SES's use of with
to
sandbox code (it does this right?) would destroy performance to the
point of being unusable in practice.
On Thu, Mar 21, 2013 at 2:38 AM, François REMY < francois.remy.dev at outlook.com> wrote:
Phasing out failed experiments is possible. I don't think a browser that doesn't support <blink> or <marquee> or even document.layers would have a lot of problems to view the web as it's now, yet I remember a time where document.layers <marquee> were used quite a lot. I do think the argument used to claim proto is unfixable is somewhat wrong.
Whether or not a failed experiment can be phased out is an empirical question. The answer depends on Web content.
<marquee> is essential in some locales. <blink> is already a no-op visually.
I think JSC and Opera each did without mutable proto for a while and ended up implementing it for Web compatibility. So the experiment has actually been carried out at least twice. Maybe things have changed, but I wouldn't bet on it.
New things are added to the Web rapidly. Old things disappear slowly.
No 'with' required for SES AFAIK. Do you have a code.google.com link? Cc'ing Mark in case he is not reading es-discuss frequently.
On 3/21/2013 1:57 PM, Brendan Eich wrote:
No 'with' required for SES AFAIK. Do you have a code.google.com link? Cc'ing Mark in case he is not reading es-discuss frequently.
/be
Brandon Benvie wrote:
On 3/21/2013 11:39 AM, Brendan Eich wrote:
Andrea Giammarchi wrote:
yes, SES, the non real world out there, needs proto ... shenanigans all over the world because of 'proto' ain't important.
SES is deployed on major Google properties. I recall also Yahoo! but not sure if still up.
I think again you are out of line. Am I wrong? I don't agree with Andrea's sentiment, but this would still be surprising to me. I would have thought that SES's use of
with
to sandbox code (it does this right?) would destroy performance to the point of being unusable in practice.
es-discuss mailing list es-discuss at mozilla.org, mail.mozilla.org/listinfo/es-discuss
If I understand correctly, this wrapper code is used for all code executed in SES (but I may be wrong): code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/startSES.js#643
On Thu, Mar 21, 2013 at 10:04 PM, Brandon Benvie <bbenvie at mozilla.com>wrote:
On 3/21/2013 1:57 PM, Brendan Eich wrote:
No 'with' required for SES AFAIK. Do you have a code.google.com link? Cc'ing Mark in case he is not reading es-discuss frequently.
Thanks.
If I understand correctly, this wrapper code is used for all code executed in SES (but I may be wrong): code.google.com/p/** google-caja/source/browse/trunk/src/com/google/caja/ses/ startSES.js#643code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/startSES.js#643
Yes, to implement SES on ES5, ironically we need to use 'with' and therefore still need to run this bare bit of JS in sloppy mode.
In ES6 we should be able to replace all this by using loaders. SES-on-ES6 should no longer need to run any code sloppily. Once someone has an adequate loader implementation, let us know so we can try it.
Brandon Benvie wrote:
On 3/21/2013 1:57 PM, Brendan Eich wrote:
No 'with' required for SES AFAIK. Do you have a code.google.com link? Cc'ing Mark in case he is not reading es-discuss frequently.
First, it doesn't matter: my point about SES being deployed in the real world stands, whether SES uses 'with' or not.
Second, a strict mode function scoped by 'with' may not be as deoptimized as you think in all engines.
Third, I am surprised but Mark will say more, I'm sure.
On Thu, Mar 21, 2013 at 2:04 PM, Brandon Benvie <bbenvie at mozilla.com> wrote:
If I understand correctly, this wrapper code is used for all code executed in SES (but I may be wrong): code.google.com/p/** google-caja/source/browse/trunk/src/com/google/caja/ses/ startSES.js#643code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/startSES.js#643
Yes. SES requires 'with' as a means to hook into 'global' variable reads and writes; without it, it is impossible to emulate the semantics of browser global environments, such as in:
<script> var x = 1; </script> <script> x = 2; </script>
However, the SES security approach does not actually require 'with': if we did not need to intercept writes to 'global' variables, we could simply ensure that every free variable in the source is bound in the wrapper code, or in the future use loaders as MarkM just noted. We don't currently implement this potential optimization.
Correction:
On Thu, Mar 21, 2013 at 2:16 PM, Kevin Reid <kpreid at google.com> wrote:
Yes. SES requires 'with' as a means to hook into 'global' variable reads and writes; without it, it is impossible
without performing a parse and scope analysis of the code to be evaluated
On Wed, Mar 20, 2013 at 10:18 PM, Brendan Eich <brendan at mozilla.com> wrote:
Your writing is unclear and overlong, and full of unjustified airs of grievance -- please work on it.
I'll do more than that, I publicly and officially apologies for my writing plus I will step back from this ML for an undefined amount of time so you can all keep doing your best to make JavaScript awesome without me bothering at all.
Just please, don't forget that not everyone needs to interpretate ES runtime if not online IDEs or some other use case, as SES is ... but those are use cases indeed and those are not the Web and should not affect the future of a programming language that happily runs already on the server too and would like to be as unsafe as possible when needed (runtime optimized pre-compiled Function(string) is only a case, fn.caller could be another, etc) but also a better language when it is possible (i.e. Object.setPrototypeOf() deprecating the proto magic)
Last, but not least, all I've always tried to do in this ML since ever is exactly the same you all do every day: make the Web awesome, caring for all possible real use-cases I've experienced in my 12+ hands on client/server/db web development experience and all of them with JS on the front or the back end.
Well, it is quite clear to me that here, in this ML, I've failed.
Best
As far as I remember when I looked at it, there was a getfreevar function or something like this parsing the code (or I misunderstood, see [1] but don't read the proposal, it's wrong, even if I don't totally give up with the concept).
But anyway, since it will change, does it exist an official document about SES concepts (strawman or other) ?
,
[1] gist.github.com/Ayms/2995641#another-approach-can-be-cajavm-
Le 21/03/2013 22:17, Kevin Reid a écrit :
On Fri, Mar 22, 2013 at 6:03 PM, Aymeric Vitte <vitteaymeric at gmail.com>wrote:
As far as I remember when I looked at it, there was a getfreevar function or something like this parsing the code (or I misunderstood, see [1] but don't read the proposal, it's wrong, even if I don't totally give up with the concept).
Are you referring to the function atLeastFreeVarNames at < code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/atLeastFreeVarNames.js>?
It does scan the source using regular expressions to look for all possible identifiers. But it doesn't do a full parse or even lex. As a result, it picks up identifiers in comments and literal strings as well. Security only requires that the code being scanned cannot contain have a free (and therefore global) variable reference without it being included in atLeastFreeVarNames's result.
But anyway, since it will change, does it exist an official document about SES concepts (strawman or other) ?
Nothing official yet. But see
code.google.com/p/google-caja/wiki/SES, static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en//pubs/archive/37199.pdf
Le 22/03/2013 19:33, Mark S. Miller a écrit :
On Fri, Mar 22, 2013 at 6:03 PM, Aymeric Vitte <vitteaymeric at gmail.com <mailto:vitteaymeric at gmail.com>> wrote:
As far as I remember when I looked at it, there was a getfreevar function or something like this parsing the code (or I misunderstood, see [1] but don't read the proposal, it's wrong, even if I don't totally give up with the concept).
Are you referring to the function atLeastFreeVarNames at code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/atLeastFreeVarNames.js? It does scan the source using regular expressions to look for all possible identifiers. But it doesn't do a full parse or even lex. As a result, it picks up identifiers in comments and literal strings as well. Security only requires that the code being scanned cannot contain have a free (and therefore global) variable reference without it being included in atLeastFreeVarNames's result.
Yes, exactly, indeed it's not parsing but "rexexpeing".
But anyway, since it will change, does it exist an official document about SES concepts (strawman or other) ?
Nothing official yet. But see
code.google.com/p/google-caja/wiki/SES, static.googleusercontent.com/external_content/untrusted_dlcp/research.google.com/en//pubs/archive/37199.pdf
Thanks, for [1] there is a script supposed to "tame" the page, trying to use a kind of home-made Object.observe which just shadows some DOM prototype properties and assign getters/setters, unexpectedly the behavior is different in each browser, and globally this does not work at all as such, maybe the override problem, more probably when I am back to it.
[1] www.ianonym.com
,
[+google-caja-discuss]
On Sun, Mar 24, 2013 at 10:44 AM, Aymeric Vitte <vitteaymeric at gmail.com> wrote:
Le 22/03/2013 19:33, Mark S. Miller a écrit :
On Fri, Mar 22, 2013 at 6:03 PM, Aymeric Vitte <vitteaymeric at gmail.com> wrote:
As far as I remember when I looked at it, there was a getfreevar function or something like this parsing the code (or I misunderstood, see [1] but don't read the proposal, it's wrong, even if I don't totally give up with the concept).
Are you referring to the function atLeastFreeVarNames at < code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/atLeastFreeVarNames.js>? It does scan the source using regular expressions to look for all possible identifiers. But it doesn't do a full parse or even lex. As a result, it picks up identifiers in comments and literal strings as well. Security only requires that the code being scanned cannot contain have a free (and therefore global) variable reference without it being included in atLeastFreeVarNames's result.
Yes, exactly, indeed it's not parsing but "rexexpeing".
But anyway, since it will change, does it exist an official document about SES concepts (strawman or other) ?
Nothing official yet. But see
code.google.com/p/google-caja/wiki/SES
Thanks, for [1] there is a script supposed to "tame" the page, trying to use a kind of home-made Object.observe which just shadows some DOM prototype properties and assign getters/setters,
You should check out the rest of Caja, which is an integrated solution that uses
- SES to secure the JavaScript portion if on an ES5 platform
- ES5/3 to emulate ES5 and SES when on a pre-ES5 browser
- Domado to tame the DOM and browser API
- HTML and CSS rewriters that sanitize by sandboxing the scripts they encounter rather than removing them.
unexpectedly the behavior is different in each browser, and globally this does not work at all as such, maybe the override problem, more probably when I am back to it.
When used through Caja, the allowed subset of browser behaviors appear much more uniform and reliable.
- SES compensates for the override mistake with cajaVM.tamperProof < code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/repairES5.js#371>
and cajaVM.def < code.google.com/p/google-caja/source/browse/trunk/src/com/google/caja/ses/startSES.js#891
.
- ES5/3 purposely does not emulate the ES5 override mistake. This has not broken anything yet, giving us further evidence that this mistake might still be repairable.
- Domado presents a more regular browser API, compensating for many differences of the underlying platform.
- The HTML and CSS rewriters emit normalized HTML and CSS, so you don't need to worry about differences in how browsers parse the abnormal cases.
I hope these are useful for you.
Further discussion which is Caja specific and not of general interest should occur on google-caja-discuss at googlegroups.com (cc'ed).
A previous thread [1] brought to my attention the fact that objects which don't inherit from Object.prototype won't have mutable proto. This was something I had missed and breaks some scripts I'm currently using because I have objects which I don't want to inherit from Object.prototype but for which I do want to have mutable proto.
Testing in Firefox Nightly I found this workaround:
var x = { }, y = { foo: 'bar' };
x.proto = y; console.log(1, x.foo); // => 1 'bar'
x.proto = null; console.log(2, x.foo); // => 2 undefined
x.proto = y; console.log(3, x.foo); // => 3 undefined
var _setPrototype = Object.getOwnPropertyDescriptor(Object.prototype, 'proto').set, setPrototypeOf = Function.prototype.call.bind(_setPrototype); setPrototypeOf(x, y); console.log(4, x.foo); // => 4 'bar'
Is this workaround a temporary bug in Firefox's current implementation? Or will this be the spec'ed behavior for ES6? Can we use such a method to mutate prototype on objects which don't inherit from Object.prototype?
[1] esdiscuss/2013-March/029176