Define security around Window, WindowProxy, and Location properly #638

Merged
merged 1 commit into from Feb 27, 2016

Projects

None yet

7 participants

@annevk
Member
annevk commented Feb 6, 2016

This is a relative large change to the way Window, WindowProxy, and
Location objects work, at least from a standards’ perspective. This
should more closely match implementations and define all the relevant
details.

A rough summary of the changes:

  • Window indexed getters have moved to WindowProxy.
  • WindowProxy is now a JavaScript exotic object and it handles all the
    security aspects for Window so Window can become an ordinary object.
  • Cross-origin named properties for Window are now exposed (though on
    WindowProxy). This addresses #544 and
    https://www.w3.org/Bugs/Public/show_bug.cgi?id=21674 which that PR was
    intended to replace.
  • Location is now an exotic object with all its internal methods
    overridden to handle the cross-origin security aspects.
  • Location no longer uses Unforgeable on the interface, allowing that
    to be removed from IDL. (It moved to all of its properties instead and
    the remaining details are defined through prose.)

This should also address these bugs:

@annevk
Member
annevk commented Feb 6, 2016

Things I need to look into:

  • Now WindowProxy handles indexed properties directly, we should expose them through [[OwnPropertyKeys]] too. Currently we only do that for the cross-origin case.
  • I need to get tc39/ecma262#356 landed and add some references.

Things that made me ponder:

  • Although I used <span> around a bunch of Ordinary* abstract operation references, the build script is not complaining about missing <dfn>s. What is up with that?

In any event, this is definitely ready for review.

@annevk
Member
annevk commented Feb 6, 2016

If tc39/ecma262#367 lands we need to figure out what to do with [[Enumerate]]. It's not entirely clear to me what we can do then.

@domenic
Member
domenic commented Feb 6, 2016

Although I used around a bunch of Ordinary* abstract operation references, the build script is not complaining about missing s. What is up with that?

I've noticed this too. I think the build script thinks that empty spans are just meant to be using span to mark up a length of text, not auto-linking. That is why we should move to longer term.

Will try to review Monday.

@sideshowbarker
Member

Although I used around a bunch of Ordinary* abstract operation references, the build script is not complaining about missing s. What is up with that?

I've noticed this too. I think the build script thinks that empty spans are just meant to be using span to mark up a length of text, not auto-linking. That is why we should move to longer term.

To be clear, that’s an issue with wattsi, right? (Not something else in the build.sh script or the Perl scripts it calls.) If so, I wonder if whatwg/wattsi#5 regressed this, or if it’s always been this way, or what.

@Ms2ger Ms2ger commented on an outdated diff Feb 8, 2016
- elements that are <span data-x="in a document">in the <code>Document</code></span> that is the
- <span>active document</span> of that <code>Window</code> object, if that <code>Window</code>'s
- <span>browsing context</span> shares the same <span>event loop</span> as the <span>responsible
- document</span> specified by the <span>entry settings object</span> accessing the IDL attribute;
- otherwise, it must return zero.</p>
-
- <!-- in other words, frames are only accessible to same-thread processes -->
-
- <p>The <span>supported property indices</span> on the <code>Window</code> object at any instant
- are the numbers in the range 0 .. <span data-x=""><var>n</var>-1</span>, where <var>n</var> is the number returned by the <code data-x="dom-length">length</code> IDL
- attribute. If <var>n</var> is zero then there are no <span>supported property
- indices</span>.</p>
+ <p>The <dfn>number of child browsing contexts</dfn> is the number of <span data-x="child browsing
+ context">child browsing contexts</span> that are <span data-x="browsing context nested
+ through">nested through</span> elements that are <span data-x="in a document">in the
+ <code>Document</code></span> that is the <span>active document</span> of the <code>Window</code>
@Ms2ger
Ms2ger Feb 8, 2016 Member

A Window does not have an "active document"; a browsing context does.

@Ms2ger Ms2ger commented on the diff Feb 8, 2016
<p>There is no <code>WindowProxy</code> interface object.</p>
- <p class="note">The <code>WindowProxy</code> object allows scripts to act as if each
- <span>browsing context</span> had a single <code>Window</code> object, while still keeping
- separate <code>Window</code> objects for each <code>Document</code>.</p>
+ <p>Every <code>WindowProxy</code> object has a
+ [[<dfn data-x="concept-windowproxy-window">Window</dfn>]] internal slot representing the wrapped
@Ms2ger
Ms2ger Feb 8, 2016 Member

[[Window]] is never set, only read.

@domenic
domenic Feb 11, 2016 Member

+1, setting [[Window]] on navigation is pretty important :). Seems like it's in "Initialising a new Document object", step 2. Also "create a new browsing context", step 1.

@annevk
annevk Feb 12, 2016 Member

Thank for you for pointing out the locations, fixup1 has the fix.

@domenic domenic was assigned by annevk Feb 10, 2016
@annevk
Member
annevk commented Feb 10, 2016

WindowProxy needs to use https://heycam.github.io/webidl/#dfn-named-property-visibility (or a variant thereof) where it implements cross-origin named properties. In particular I think we don't want to have [OverrideBuiltins] behavior if I understood @bzbarsky's comments in https://bugzilla.mozilla.org/show_bug.cgi?id=1245554 correctly.

@bzbarsky
Collaborator

We should probably test what UAs actually do with cross-origin named properties carefully. Defining how this should behave will be a bit tricky. For example, consider this testcase:

<!DOCTYPE html>
<body>
  <iframe name="foo"></iframe>
  <script>
    Object.prototype.foo = 5;
    onload = function() { alert(window.foo); }
  </script>
</body> 

In browsers this alerts "5" (at least in Chrome, Safari, and Firefox). What should happen on cross-origin access to the "foo" property on this window? Chrome and Firefox return the subframe, looks like. Safari returns undefined (or 5, depending on what the accessing thing actually is; yes, it leaks info cross-origin in some cases). Of course maybe Safari returns undefined for cross-origin named access in general? We really need some exhaustive tests. :(

@annevk annevk referenced this pull request in annevk/html-cross-origin-objects Feb 11, 2016
Closed

Bugs to close when we move this to HTML #25

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
@@ -2976,16 +2977,23 @@ a.setAttribute('href', 'http://example.com/'); // change the content attribute d
<li>The <dfn data-noexport="" data-x="js-prod-Module" data-x-href="https://tc39.github.io/ecma262/#prod-Module"><i>Module</i></dfn> production</li>
<li>The <dfn data-noexport="" data-x="js-prod-Pattern" data-x-href="https://tc39.github.io/ecma262/#prod-Pattern"><i>Pattern</i></dfn> production</li>
<li>The <dfn data-noexport="" data-x="js-prod-Script" data-x-href="https://tc39.github.io/ecma262/#prod-Script"><i>Script</i></dfn> production</li>
+ <li><dfn data-noexport="" data-x-href="https://tc39.github.io/ecma262/#sec-property-descriptor-specification-type">PropertyDescriptor</dfn></li>
@domenic
domenic Feb 11, 2016 Member

I've been curating this section, perhaps a bit obsessively. This should be "The [PropertyDescriptor] specification type"

@annevk
annevk Feb 12, 2016 Member

This is meant to refer to the tag literal descriptions of Property Descriptor records.

@domenic
domenic Feb 12, 2016 Member

Yeah but ES conflates them

@domenic
domenic Feb 12, 2016 Member

Still would like to see this fixed. The fact that ES uses specification type names as tags when creating literals is just notation; the actual thing being referenced is the PropertyDescriptor specification type.

@annevk
annevk Feb 14, 2016 Member

Should it then say "Property Descriptor specification type"? But the references can use the literal PropertyDescriptor?

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
<li>The <dfn data-noexport="" data-x-href="https://tc39.github.io/ecma262/#sec-source-text-module-records">Source Text Module Record</dfn> specification type and its <dfn data-noexport="" data-x="js-ModuleEvaluation" data-x-href="https://tc39.github.io/ecma262/#sec-moduleevaluation">ModuleEvaluation</dfn> and <dfn data-noexport="" data-x="js-ModuleDeclarationInstantiation" data-x-href="https://tc39.github.io/ecma262/#sec-moduledeclarationinstantiation">ModuleDeclarationInstantiation</dfn> methods</li>
+ <li><dfn data-noexport="" data-x-href="https://tc39.github.io/ecma262/#current-realm">The current Realm Record</dfn></li>
@domenic
domenic Feb 11, 2016 Member

This should move up to the "untyped" section at the top

@annevk
annevk Feb 12, 2016 Member

I'm not sure what this means, but I made a best guess.

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
<li>The <dfn data-noexport="" data-x="js-NewObjectEnvironment" data-x-href="https://tc39.github.io/ecma262/#sec-newobjectenvironment">NewObjectEnvironment</dfn> abstract operation</li>
- <li>The <dfn data-noexport="" data-x="js-ParseModule" data-x-href="https://tc39.github.io/ecma262/#sec-parsemodule">ParseModule</dfn> abstract operation
+ <li>The <dfn data-noexport="" data-x-href="https://tc39.github.io/ecma262/#sec-ordinarydefineownproperty">OrdinaryDefineOwnProperty</dfn> abstract operation</li>
@domenic
domenic Feb 11, 2016 Member

Add in all the other OrdinaryXs. Consider sticking with the js- prefix, even though it's kind of a pain and I might take it back if I were starting over.

@annevk
annevk Feb 12, 2016 Member

Perhaps it's better to move away from it over time?

@domenic domenic commented on the diff Feb 11, 2016
@@ -76751,7 +76759,365 @@ dictionary <dfn>DragEventInit</dfn> : <span>MouseEventInit</span> {
-<!--TOPIC:DOM APIs-->
+ <h3 id="cross-origin-objects">Security infrastructure for <code>Window</code>,
+ <code>WindowProxy</code>, and <code>Location</code> objects</h3>
+
+ <p>Although typically objects cannot be accessed across <span data-x="origin">origins</span>, the
+ web platform would not be true to itself if it did not have some legacy exceptions to that rule
+ that the web depends upon.
+
+
+ <h4>Integration with IDL</h4>
+
+ <p>When <span>perform a security check</span> is invoked, with a <var>platformObject</var>,
@domenic
domenic Feb 11, 2016 Member

This isn't linking anywhere

@annevk
annevk Feb 12, 2016 Member

This is fixed by fixup1.

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
+ <li>
+ <p>If <var>platformObject</var> is a <code>Window</code> or <code>Location</code> object,
+ then:</p>
+
+ <ol>
+ <li>
+ <p>Repeat for each <var>e</var> that is an element of
+ <span>CrossOriginProperties</span>(<var>platformObject</var>):</p>
+
+ <ol>
+ <li>
+ <p>If <span>SameValue</span>(<var>e</var>.[[property]], <var>identifier</var>) is
+ <b>true</b>, then:</p>
+
+ <ol>
+ <li><p>If <var>type</var> is "method" and <var>e</var> has neither [[needsGet]] nor
@domenic
domenic Feb 11, 2016 Member

Do we want to do the typical "<code data-x="">method</code>" style here? Or just leave it un-coded?

@annevk
annevk Feb 12, 2016 Member

I went with IDL's precedent, but since we're not copying ECMAScript's precedent I'll use <code>. Hopefully at some point we'll get all standards to align, since this is just unnecessarily confusing readers.

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
+ <var>realm</var>, <var>identifier</var>, and <var>type</var>, run these steps:</p>
+
+ <ol>
+ <li>
+ <p>If <var>platformObject</var> is a <code>Window</code> or <code>Location</code> object,
+ then:</p>
+
+ <ol>
+ <li>
+ <p>Repeat for each <var>e</var> that is an element of
+ <span>CrossOriginProperties</span>(<var>platformObject</var>):</p>
+
+ <ol>
+ <li>
+ <p>If <span>SameValue</span>(<var>e</var>.[[property]], <var>identifier</var>) is
+ <b>true</b>, then:</p>
@domenic
domenic Feb 11, 2016 Member

HTML does not typically bold "true" (or "null"). In the few ES-spec-ese sections I've written (HostResolveImportedModule and HostPromiseRejectionTracker), I've stuck with not-bold.

@annevk
annevk Feb 12, 2016 Member

Okay, removed.

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
+ [[needsGet]], then return.</p></li>
+
+ <li><p>Otherwise, if <var>type</var> is "getter" and <var>e</var>.[[needsGet]] is
+ <b>true</b>, then return.</p></li>
+
+ <li><p>Otherwise, if <var>type</var> is "setter" and <var>e</var>.[[needsSet]] is
+ <b>true</b>, then return.</p></li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+
+ <li><p>If <var>platformObject</var>'s global object's <span>effective script origin</span> is not
+ <span>same origin</span> with <span>the current Realm Record</span>'s global object's
@domenic
domenic Feb 11, 2016 Member

s/global object/[[globalObject]]/

@domenic
domenic Feb 11, 2016 Member

I can't find where global objects get effective script origins, only Documents. Maybe you need to add "responsible document" to the chain??

@annevk
annevk Feb 12, 2016 Member

I guess I should start using "relevant settings object" here now that we changed to work for platform objects as well. It still doesn't feel like the best of setups though.

See also the discussion in https://www.w3.org/Bugs/Public/show_bug.cgi?id=28375.

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
+ <b>true</b>, then return.</p></li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+
+ <li><p>If <var>platformObject</var>'s global object's <span>effective script origin</span> is not
+ <span>same origin</span> with <span>the current Realm Record</span>'s global object's
+ <span>effective script origin</span>, throw a <code>SecurityError</code>.</p></li>
+ </ol>
+ <!-- we should probably remove the realm argument from IDL -->
+
+
+ <h4>Shared internal slot: [[<span>crossOriginPropertyDescriptorMap</span>]]</h4>
@domenic
domenic Feb 11, 2016 Member

I think the link in the heading looks bad and doesn't really add much since it's just linking a sentence down.

@annevk
annevk Feb 12, 2016 Member

HTML does this all the time though.

@domenic
domenic Feb 12, 2016 Member

Links close by, yes, but in headings?

@annevk
annevk Feb 12, 2016 Member

E.g., "The Window object".

@domenic
domenic Feb 12, 2016 Member

Yeah, for <code>s it is. But e.g. for "Browsing contexts" (and all of its subheadings, which also have terms corresponding to them) it is not.

@annevk
annevk Feb 12, 2016 Member

Ok, will remove the <span>.

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
+ </li>
+ </ol>
+ </li>
+
+ <li><p>If <var>platformObject</var>'s global object's <span>effective script origin</span> is not
+ <span>same origin</span> with <span>the current Realm Record</span>'s global object's
+ <span>effective script origin</span>, throw a <code>SecurityError</code>.</p></li>
+ </ol>
+ <!-- we should probably remove the realm argument from IDL -->
+
+
+ <h4>Shared internal slot: [[<span>crossOriginPropertyDescriptorMap</span>]]</h4>
+
+ <p><code>Window</code> and <code>Location</code> objects both have a
+ [[<dfn>crossOriginPropertyDescriptorMap</dfn>]] internal slot, whose value is initially an empty
+ list.
@domenic
domenic Feb 11, 2016 Member

Capitalize List, and add an entry to the references section for the List specification type that you can cross-ref.

@annevk
annevk Feb 12, 2016 Member

This should say map.

@domenic domenic commented on an outdated diff Feb 11, 2016
+
+ <li><p>If <var>platformObject</var>'s global object's <span>effective script origin</span> is not
+ <span>same origin</span> with <span>the current Realm Record</span>'s global object's
+ <span>effective script origin</span>, throw a <code>SecurityError</code>.</p></li>
+ </ol>
+ <!-- we should probably remove the realm argument from IDL -->
+
+
+ <h4>Shared internal slot: [[<span>crossOriginPropertyDescriptorMap</span>]]</h4>
+
+ <p><code>Window</code> and <code>Location</code> objects both have a
+ [[<dfn>crossOriginPropertyDescriptorMap</dfn>]] internal slot, whose value is initially an empty
+ list.
+
+ <p>User agents should allow a value held in the map to be garbage collected along with its
+ corresponding key when nothing holds a reference to any part of the value. I.e., as long as
@domenic
domenic Feb 11, 2016 Member

The hanging i.e. is a bit awkward. Maybe make it a parenthetical sentence: "(That is, as long as garbage collection is not observable.)"

@domenic domenic commented on an outdated diff Feb 11, 2016
+ <span>effective script origin</span>, throw a <code>SecurityError</code>.</p></li>
+ </ol>
+ <!-- we should probably remove the realm argument from IDL -->
+
+
+ <h4>Shared internal slot: [[<span>crossOriginPropertyDescriptorMap</span>]]</h4>
+
+ <p><code>Window</code> and <code>Location</code> objects both have a
+ [[<dfn>crossOriginPropertyDescriptorMap</dfn>]] internal slot, whose value is initially an empty
+ list.
+
+ <p>User agents should allow a value held in the map to be garbage collected along with its
+ corresponding key when nothing holds a reference to any part of the value. I.e., as long as
+ garbage collection is not observable.</p>
+
+ <p>E.g., with <code data-x="">const href = Object.getOwnPropertyDescriptor(crossOriginLocation,
@domenic
domenic Feb 11, 2016 Member

Make this class="example" and rephrase to "For example, if author code did

...
the value... collected, as that would be observable"

@domenic domenic commented on an outdated diff Feb 11, 2016
+
+ <h4>Shared internal slot: [[<span>crossOriginPropertyDescriptorMap</span>]]</h4>
+
+ <p><code>Window</code> and <code>Location</code> objects both have a
+ [[<dfn>crossOriginPropertyDescriptorMap</dfn>]] internal slot, whose value is initially an empty
+ list.
+
+ <p>User agents should allow a value held in the map to be garbage collected along with its
+ corresponding key when nothing holds a reference to any part of the value. I.e., as long as
+ garbage collection is not observable.</p>
+
+ <p>E.g., with <code data-x="">const href = Object.getOwnPropertyDescriptor(crossOriginLocation,
+ "href").set</code> the value and its corresponding key in the map cannot be garbage collected as
+ that would be observable.</p>
+
+ <p>User agents may have an optimization whereby they remove key-value pairs from the map when
@domenic
domenic Feb 11, 2016 Member

Another class="example" paragraph would be pretty great for this.

@domenic domenic commented on an outdated diff Feb 11, 2016
+
+ <li><p>Return <var>crossOriginWindowProperties</var>.</p></li>
+ </ol>
+
+ <p class="note">Indexed properties do not need to be safelisted as they are handled directly by
+ the <code>WindowProxy</code> object.</p>
+
+ <h5><dfn>IsWindowOrLocationSameOrigin</dfn> ( <var>O</var> )</h5>
+
+ <ol>
+ <li><p>Return <b>true</b> if <span>the current Realm Record</span>'s global object's
+ <span>effective script origin</span> is <span>same origin</span> with the <var>O</var>'s global
+ object's <span>effective script origin</span>, and <b>false</b> otherwise.</p></li>
+ </ol>
+
+ <h5><dfn>CrossOriginGetPrototypeOf</dfn> ( <var>O</var> )</h5>
@domenic
domenic Feb 11, 2016 Member

I think these need different names if they're planning to handle both same origin and cross-origin. WindowProxyOrLocationGetPrototypeOf? :-/

@domenic domenic commented on the diff Feb 11, 2016
+ <h5><dfn>CrossOriginGetPrototypeOf</dfn> ( <var>O</var> )</h5>
+
+ <ol>
+ <li><p>If <span>IsWindowOrLocationSameOrigin</span>(<var>O</var>), then return
+ <span>OrdinaryGetPrototypeOf</span>(<var>O</var>).</p></li>
+
+ <li><p>Return null.</p></li>
+ </ol>
+
+ <h5><dfn>CrossOriginGetOwnPropertyHelper</dfn> ( <var>O</var>, <var>P</var> )</h5>
+
+ <p class="note">If this abstract operation returns undefined and there is no custom behavior, the
+ caller needs to throw a <code>SecurityError</code> exception.</p>
+
+ <ol>
+ <li><p>If <var>P</var> is <span>@@toStringTag</span>, <span>@@hasInstance</span>, or
@domenic
domenic Feb 11, 2016 Member

The symbols aren't linking correctly

@annevk
annevk Feb 12, 2016 Member

This should be addressed by fixup1.

@domenic domenic commented on an outdated diff Feb 11, 2016
+ list.
+
+ <p>User agents should allow a value held in the map to be garbage collected along with its
+ corresponding key when nothing holds a reference to any part of the value. I.e., as long as
+ garbage collection is not observable.</p>
+
+ <p>E.g., with <code data-x="">const href = Object.getOwnPropertyDescriptor(crossOriginLocation,
+ "href").set</code> the value and its corresponding key in the map cannot be garbage collected as
+ that would be observable.</p>
+
+ <p>User agents may have an optimization whereby they remove key-value pairs from the map when
+ <code data-x="dom-document-domain">document.domain</code> is set. This is not observable as <code
+ data-x="dom-document-domain">document.domain</code> cannot revisit an earlier value.</p>
+
+
+ <h4>Shared abstract operations</h4>
@domenic
domenic Feb 11, 2016 Member

This needs a note about how all of the abstract operations here apply only to ordinary objects.

@domenic
domenic Feb 11, 2016 Member

Meh, trying to figure out how to phrase such a note made me give up on the idea. Maybe a note later when defining WindowProxy. We'll see when I get there.

@domenic domenic commented on an outdated diff Feb 11, 2016
+ <span>CrossOriginPropertyDescriptor</span>(<var>e</var>, <var>originalDesc</var>).</p></li>
+
+ <li><p>Append key <var>crossOriginKey</var> with its corresponding value
+ <var>crossOriginDesc</var> to the value of the
+ [[<span>crossOriginPropertyDescriptorMap</span>]] internal slot of <var>O</var>.</p></li>
+
+ <li><p>Return <var>crossOriginDesc</var>.</p></li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+
+ <li><p>Return <b>undefined</b>.</p></li>
+ </ol>
+
+ <h5><dfn>CrossOriginPropertyDescriptor</dfn> ( <var>crossOriginProperty</var>,
@domenic
domenic Feb 11, 2016 Member

I would nest all three of CrossOriginPropertyDescriptor, CrossOriginFunctionWrapper, and cross-origin wrapper functions under CrossOriginGetOwnPropertyHelper. (No need to nest cross-origin wrapper functions under CrossOriginFunctionWrapper. In fact maybe it's OK to not give it its own section.)

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
+ <ol>
+ <li><p>Let <var>value</var> be <var>originalDesc</var>.[[Value]].</p></li>
+
+ <li><p>If IsCallable(<var>value</var>) is <b>true</b>, set <var>value</var> to
+ <span>CrossOriginFunctionWrapper</span>(<b>true</b>, <var>value</var>).</p></li>
+
+ <li><p>Return <span>PropertyDescriptor</span>{
+ [[Value]]: <var>value</var>,
+ [[Enumerable]]: <b>true</b>,
+ [[Writable]]: <b>false</b>,
+ [[Configurable]]: <b>true</b> }.</p></li>
+ </ol>
+ </li>
+
+ <li>
+ <p>Otherwise, then:</p>
@domenic
domenic Feb 11, 2016 Member

Just "Otherwise,"

@zcorpan
zcorpan Feb 12, 2016 Member

Or Otherwise: to be consistent with other parts of the spec.

@domenic domenic commented on the diff Feb 11, 2016
@@ -76785,7 +77151,6 @@ dictionary <dfn>DragEventInit</dfn> : <span>MouseEventInit</span> {
[Replaceable] readonly attribute <span>WindowProxy</span> <span data-x="dom-parent">parent</span>;
readonly attribute <span>Element</span>? <span data-x="dom-frameElement">frameElement</span>;
<span>WindowProxy</span>? <span data-x="dom-open">open</span>(optional DOMString url = "about:blank", optional DOMString target = "_blank", [TreatNullAs=EmptyString] optional DOMString features = "", optional boolean replace = false);
- <span data-x="dom-window-item">getter</span> <span>WindowProxy</span> (unsigned long index);
<span data-x="dom-window-namedItem">getter</span> object (DOMString name);
@domenic
domenic Feb 11, 2016 Member

What do you think of adding a comment like "// indexed access to subframes is taken care of by WindowProxy" after this line?

@domenic
domenic Feb 11, 2016 Member

The named getter here means Window is exotic, which means you need to delegate to it per our earlier discussions instead of using OrdinaryX(). Did you mean to move the named getter elsewhere?

@bzbarsky
bzbarsky Feb 11, 2016 Collaborator

For global objects, the named getter adds an exotic NamedPropertiesObject on the proto chain instead of making the global itself exotic.

@domenic
domenic Feb 11, 2016 Member

That is some of the spookiest action at a distance I have seen in a while -_-. Maybe a comment? "// since this is a global, per IDL, this adds an exotic NamedPropertiesObject to the prototype chain"

@annevk
annevk Feb 12, 2016 Member

I have added a comment in fixup1 explaining both.

@domenic
domenic Feb 12, 2016 Member

Comment looks good. Maybe add a blank line between open() and the getter.

@annevk
annevk Feb 15, 2016 Member

We should do that separately, since currently each newline is indicative of a new section. So that would require some extra annotations here and there.

@domenic domenic commented on an outdated diff Feb 11, 2016
- <p>These properties are the <dfn>dynamic nested browsing context properties</dfn>.</p>
+ <p class="note">The indexed getter is defined through the
@domenic
domenic Feb 11, 2016 Member

Not quite the right phrasing; there is no indexed getter, since that is an IDL concept. Maybe "indexed access to child browsing contexts is defined through..."

@domenic domenic commented on an outdated diff Feb 11, 2016
@@ -77590,31 +77866,203 @@ callback <dfn>FrameRequestCallback</dfn> = void (<span>DOMHighResTimeStamp</span
<h4>The <code>WindowProxy</code> object</h4>
@domenic
domenic Feb 11, 2016 Member

IMO this probably deserves to get bumped up a level (h3) now that it's not just a hand-wavy thing placed in front of Window.

@domenic domenic commented on the diff Feb 11, 2016
+
+ <h5 id="windowproxy-preventextensions">[[PreventExtensions]] ( )</h5>
+
+ <ol>
+ <li>Return <b>false</b>.</li>
+ </ol>
+
+ <h5 id="windowproxy-getownproperty">[[GetOwnProperty]] ( <var>P</var> )</h5>
+
+ <ol>
+ <li><p>Let <var>W</var> be the value of the
+ [[<span data-x="concept-windowproxy-window">Window</span>]] internal slot of
+ <b>this</b>.</p></li>
+
+ <li>
+ <p>If <var>P</var> is an <span>array index property name</span>, then:</p>
@domenic
domenic Feb 11, 2016 Member

This and the subsequent step could probably use https://tc39.github.io/ecma262/#sec-canonicalnumericindexstring instead. I don't have a strong preference.

@domenic
domenic Feb 12, 2016 Member

Yeah, they do it a bit differently I guess; there's a later IsInteger check. Probably not worth it.

@domenic domenic commented on an outdated diff Feb 11, 2016
+ <ol>
+ <li>Return <b>false</b>.</li>
+ </ol>
+
+ <h5 id="windowproxy-getownproperty">[[GetOwnProperty]] ( <var>P</var> )</h5>
+
+ <ol>
+ <li><p>Let <var>W</var> be the value of the
+ [[<span data-x="concept-windowproxy-window">Window</span>]] internal slot of
+ <b>this</b>.</p></li>
+
+ <li>
+ <p>If <var>P</var> is an <span>array index property name</span>, then:</p>
+
+ <ol>
+ <li><p>Let <var>index</var> be ToUint32(<var>P</var>).</p></li>
@domenic
domenic Feb 11, 2016 Member

ToUin32 needs to link

@domenic domenic commented on an outdated diff Feb 11, 2016
+ <p>If <var>P</var> is an <span>array index property name</span>, then:</p>
+
+ <ol>
+ <li><p>Let <var>index</var> be ToUint32(<var>P</var>).</p></li>
+
+ <li><p>Let <var>maxProperties</var> be the <span>number of child browsing contexts</span> of
+ <var>W</var>.
+
+ <li><p>Let <var>value</var> be <b>undefined</b>.
+
+ <li>
+ <p>If <var>maxProperties</var> is greater than 0 and <var>index</var> is greater than
+ <var>maxProperties</var> &minus; 1, then:
+
+ <ol>
+ <li><p>Set <var>value</var> to the <code>WindowProxy</code> object of the <var>index</var>th
@domenic
domenic Feb 11, 2016 Member

Seriously, browsers!?!? This is the worst.

@domenic domenic commented on the diff Feb 11, 2016
- <div class="example">
+ <p>The <code>WindowProxy</code> object internal methods are described in the subsections
+ below.</p>
@domenic
domenic Feb 11, 2016 Member

Here is where my NOTE goes.

NOTE: although WindowProxy is named as a "proxy", it does not do polymorphic dispatch on its target's internal methods like a real proxy would, due to a desire to reuse machinery between Location and WindowProxy objects. As long as the Window object does not exhibit any exotic behaviors (such as indexed or named getters or setters) this is unobservable.

@domenic domenic commented on an outdated diff Feb 11, 2016
+ <ol>
+ <li><p>Let <var>W</var> be the value of the
+ [[<span data-x="concept-windowproxy-window">Window</span>]] internal slot of
+ <b>this</b>.</p></li>
+
+ <li><p>Return <span>CrossOriginHasProperty</span>(<var>W</var>, <var>P</var>).</p></li>
+ </ol>
+
+ <h5 id="windowproxy-get">[[Get]] ( <var>P</var>, <var>Receiver</var> )</h5>
+
+ <ol>
+ <li><p>Let <var>W</var> be the value of the
+ [[<span data-x="concept-windowproxy-window">Window</span>]] internal slot of
+ <b>this</b>.</p></li>
+
+ <li><p>Return ? <span>CrossOriginGet</span>(this, <var>W</var>, <var>P</var>,
@domenic
domenic Feb 11, 2016 Member

I don't understand why the second parameter is named proxyO if you're passing the Window, not the WindowProxy, as proxyO.

Again I think this would be much clearer if the "is same origin" check was inlined into the call sites instead of having to pass in these two different objects. Then you could keep the CrossOriginX names too.

@domenic domenic commented on an outdated diff Feb 11, 2016
+
+ <li><p>Return ? <span>CrossOriginSet</span>(this, <var>W</var>, <var>P</var>, <var>V</var>,
+ <var>Receiver</var>).</p></li>
+ </ol>
+
+ <h5 id="windowproxy-delete">[[Delete]] ( <var>P</var> )</h5>
+
+ <ol>
+ <li><p>Let <var>W</var> be the value of the
+ [[<span data-x="concept-windowproxy-window">Window</span>]] internal slot of
+ <b>this</b>.</p></li>
+
+ <li><p>Return <span>CrossOriginDelete</span>(<var>W</var>, <var>P</var>).</p></li>
+ </ol>
+
+ <h5 id="windowproxy-enumerate">[[Enumerate]] ( )</h5>
@domenic
domenic Feb 11, 2016 Member

Enumerate is either dead or almost dead. Kill it here and elsewhere.

@domenic domenic commented on an outdated diff Feb 11, 2016
@@ -79159,6 +79607,59 @@ State: &lt;OUTPUT NAME=I>1&lt;/OUTPUT> &lt;INPUT VALUE="Increment" TYPE=BUTTON O
<p>Each <code>Window</code> object is associated with a unique instance of a <code>Location</code>
object, allocated when the <code>Window</code> object is created.</p>
+ <div w-nodev>
+
+ <p>To create a <code>Location</code> object, run these steps:</p>
+
+ <ol>
+ <li><p>Let <var>location</var> be a new <code>Location</code> <span>platform
+ object</span>.</p></li>
+
+ <li><p>Perform ! <var>location</var>.[[DefineOwnProperty]]("toString", {
+ [[Value]]: %ObjProto_toString%,
@domenic
domenic Feb 11, 2016 Member

Cross-ref %ObjProto_toString%

@domenic domenic commented on an outdated diff Feb 11, 2016
+ <ol>
+ <li>Return ? <span>ToObject</span>(<b>this</b>).</li>
+ </ol>
+
+ <p>The value of the function object's "length" property is the Number value 0.</p>
+
+ <p>The value of the function object’s "name" property is the String value "valueOf".</p>
+ </li>
+
+ <li><p>Perform ! <var>location</var>.[[DefineOwnProperty]]("valueOf", {
+ [[Value]]: <var>valueOfFunction</var>,
+ [[Writable]]: <b>false</b>,
+ [[Enumerable]]: <b>false</b>,
+ [[Configurable]]: <b>false</b> }).</p></li>
+
+ <li><p>Perform ! <var>location</var>.[[DefineOwnProperty]](@@toPrimitive, { [
@domenic
domenic Feb 11, 2016 Member

Cross link @@toPrimitive.

@domenic domenic commented on an outdated diff Feb 11, 2016
@@ -79159,6 +79607,59 @@ State: &lt;OUTPUT NAME=I>1&lt;/OUTPUT> &lt;INPUT VALUE="Increment" TYPE=BUTTON O
<p>Each <code>Window</code> object is associated with a unique instance of a <code>Location</code>
object, allocated when the <code>Window</code> object is created.</p>
+ <div w-nodev>
+
+ <p>To create a <code>Location</code> object, run these steps:</p>
@domenic
domenic Feb 11, 2016 Member

Might want something about how Location is a mish-mash of IDL with overwritten creation behavior and internal methods?

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
@@ -79662,10 +80263,18 @@ State: &lt;OUTPUT NAME=I>1&lt;/OUTPUT> &lt;INPUT VALUE="Increment" TYPE=BUTTON O
</ol>
+ <p class="note">The <code data-x="dom-location-replace">replace(<var>url</var>)</code> method
@domenic
domenic Feb 11, 2016 Member

Do we usually refer to methods including their parameter names? Or would this just be "The replace method"? Maybe even "The location.replace method"??

@annevk
annevk Feb 12, 2016 Member

I made it "The replace() method" locally.

@domenic domenic commented on an outdated diff Feb 11, 2016
@@ -79739,72 +80350,138 @@ State: &lt;OUTPUT NAME=I>1&lt;/OUTPUT> &lt;INPUT VALUE="Increment" TYPE=BUTTON O
<li><p>Return to the step labeled <i>loop</i>.</p></li>
- <li><p><i>End</i>: Let <var>output</var> be the values of the array, in the same order.</p></li>
+ <li><p><i>End</i>: Return <var>output</var>.</p></li>
+ </ol>
+
+ <h5>Security infrastructure specific to the <code>Location</code> object</h5>
@domenic
domenic Feb 11, 2016 Member

I think we don't need a new subsection here. Just an intro paragraph explaining how Location is a special pumpkin that overrides internal methods for security reasons.

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
- <p>When the <span>effective script origin</span> specified by the <span>entry settings
- object</span> is different than a <code>Location</code> object's associated
- <code>Document</code>'s <span>effective script origin</span>, the user agent must act as if any
- changes to that <code>Location</code> object's properties, getters, setters, etc, were not
- present, and as if all the properties of that <code>Location</code> object had their
- [[Enumerable]] attribute set to false.</p>
+ <li><p>Let <var>property</var> be <span>CrossOriginGetOwnProperty</span>(<b>this</b>,
@domenic
domenic Feb 11, 2016 Member

Missing "Helper" causes failed link

@annevk
annevk Feb 12, 2016 Member

Addressed.

@domenic domenic commented on an outdated diff Feb 11, 2016
+
+ <ol>
+ <li>Return <span>CrossOriginHasProperty</span>(<b>this</b>, <var>P</var>).</li>
+ </ol>
+
+ <h6 id="location-get-receiver">[[Get]] ( <var>P</var>, <var>Receiver</var> )</h6>
+
+ <ol>
+ <li>Return <span>CrossOriginGet</span>(<b>this</b>, <b>this</b>, <var>P</var>,
+ <var>Receiver</var>).</li>
+ </ol>
+
+ <h6 id="location-set-v-receiver">[[Set]] ( <var>P</var>, <var>V</var>, <var>Receiver</var> )</h6>
+
+ <ol>
+ <li>Return <span>CrossOriginSet</span>(<b>this</b>, <b>this</b>, <var>P</var>, <var>V</var>,
@domenic
domenic Feb 11, 2016 Member

Seeing these repeated "this, this" I feel even more strongly the security check should be pulled out. The fact that it's the same object for Location and the Window for WindowProxy is an important detail that gets lost when you only see "O, proxyO" in the abstract.

@domenic domenic and 1 other commented on an outdated diff Feb 11, 2016
+ <ol>
+ <li>Return <span>CrossOriginGet</span>(<b>this</b>, <b>this</b>, <var>P</var>,
+ <var>Receiver</var>).</li>
+ </ol>
+
+ <h6 id="location-set-v-receiver">[[Set]] ( <var>P</var>, <var>V</var>, <var>Receiver</var> )</h6>
+
+ <ol>
+ <li>Return <span>CrossOriginSet</span>(<b>this</b>, <b>this</b>, <var>P</var>, <var>V</var>,
+ <var>Receiver</var>).</li>
+ </ol>
+
+ <h6 id="location-delete">[[Delete]] ( <var>P</var> )</h6>
+
+ <ol>
+ <li>Return <span>CrossOriginDelete</span>(this, <var>P</var>).</li>
@domenic
domenic Feb 11, 2016 Member

Missing bold for this here.

Also, if we're going with ES-style bold this, it'd be good to fix line 75927 where I do <code data-x="">this</code>. I think that's the only other place in the spec though, based on searching for >this<.

@annevk
annevk Feb 12, 2016 Member

I found another one around 85k. Also changed. (Not yet pushed.)

@domenic domenic commented on the diff Feb 11, 2016
@@ -76751,7 +76759,365 @@ dictionary <dfn>DragEventInit</dfn> : <span>MouseEventInit</span> {
-<!--TOPIC:DOM APIs-->
+ <h3 id="cross-origin-objects">Security infrastructure for <code>Window</code>,
@domenic
domenic Feb 11, 2016 Member

Maybe Window doesn't belong on this list?

@annevk
annevk Feb 12, 2016 Member

It does, due to the IDL security check happening on Window, not WindowProxy.

@annevk
Member
annevk commented Feb 12, 2016

Outstanding feedback, ignoring tests for the moment which I'd like to look into after we have a standard to write them against:

  • Now WindowProxy handles indexed properties directly, we should expose them through [[OwnPropertyKeys]] too. Currently we only do that for the cross-origin case.
  • [[Enumerate]] needs to be removed, but to do that GOPD (in the cross-origin case) always needs to return false for [[Enumerable]] and GetPrototypeOf needs to return null. The latter is already the case.
  • I would nest all three of CrossOriginPropertyDescriptor, CrossOriginFunctionWrapper, and cross-origin wrapper functions under CrossOriginGetOwnPropertyHelper. (No need to nest cross-origin wrapper functions under CrossOriginFunctionWrapper. In fact maybe it's OK to not give it its own section.)
  • Bump WindowProxy up to <h3>
  • Remove Location subsection in favor of an intro paragraph explaining how Location is a special pumpkin that overrides internal methods for security reasons. Perhaps <hr> could be added though.
  • Domenic wants the security check pulled out primarily because of "O, proxyO". Investigate if that's feasible.
@annevk
Member
annevk commented Feb 12, 2016

Another comment was renaming CrossOrigin* to WindowProxyOrLocation*, which we should do if we don't pull out the security check.

@domenic
Member
domenic commented Feb 12, 2016

Domenic wants the security check pulled out primarily because of "O, proxyO". Investigate if that's feasible.

To expand on this a bit, I think it's much easier to understand if "SomethingSomethingGet" takes the same arguments as ES's "Get". It's strange now how some match (Delete, HasProperty) but others don't (Get, Set).

And, I think it's clearer to show how the security checks are on very different objects if they're present in each definition, instead of using this, this for Location and this, W for WindowProxy, then having a generic O vs. proxyO in the operation.

@annevk
Member
annevk commented Feb 12, 2016

@bholley, @bzbarsky, if you are curious I have uploaded a single-page version of the standard that has this PR merged here: https://html5.org/temp/cross-origin-objects-review.html#cross-origin-objects.

Other interesting bits are https://html5.org/temp/cross-origin-objects-review.html#windowproxy and https://html5.org/temp/cross-origin-objects-review.html#the-location-interface (internal methods at the end of this section).

@annevk
Member
annevk commented Feb 12, 2016

I believe I have addressed all feedback thus far, but I'm in no rush to merge this so I'll wait at least until Tuesday next week, but let me know if you want more time.

@annevk
Member
annevk commented Feb 12, 2016
@annevk annevk referenced this pull request in servo/servo Feb 12, 2016
Open

Implement cross-origin wrappers #2382

@domenic domenic commented on an outdated diff Feb 12, 2016
+ corresponding key when nothing holds a reference to any part of the value. That is, as long as
+ garbage collection is not observable.</p>
+
+ <p class="example">For example, with <code data-x="">const href =
+ Object.getOwnPropertyDescriptor(crossOriginLocation, "href").set</code> the value and its
+ corresponding key in the map cannot be garbage collected as that would be observable.</p>
+
+ <p>User agents may have an optimization whereby they remove key-value pairs from the map when
+ <code data-x="dom-document-domain">document.domain</code> is set. This is not observable as <code
+ data-x="dom-document-domain">document.domain</code> cannot revisit an earlier value.</p>
+
+ <p class="example">For example, setting <code data-x="dom-document-domain">document.domain</code>
+ to "<code data-x="">example.com</code>" on www.example.com, means user agents can remove all
+ key-value pairs from the map where part of the key is www.example.com as that can never be part of
+ the <span>effective script origin</span> again and therefore the corresponding value could never
+ be retrieved from the map.</p>
@domenic
domenic Feb 12, 2016 Member

Move a comma around: "on example.com means user agents ... key is www.example.com, as that can..."

@domenic domenic and 1 other commented on an outdated diff Feb 12, 2016
+ <p class="example">For example, setting <code data-x="dom-document-domain">document.domain</code>
+ to "<code data-x="">example.com</code>" on www.example.com, means user agents can remove all
+ key-value pairs from the map where part of the key is www.example.com as that can never be part of
+ the <span>effective script origin</span> again and therefore the corresponding value could never
+ be retrieved from the map.</p>
+
+
+ <h4>Shared abstract operations</h4>
+
+ <h5><dfn>CrossOriginProperties</dfn>( <var>O</var> )</h5>
+
+ <ol>
+ <li><p>Assert: <var>O</var> is a <code>Location</code> or <code>Window</code> object.</p></li>
+
+ <li><p>If <var>O</var> is a <code>Location</code> object, then return «
+ { [[property]]: "href", [[needsGet]]: false, [[needsSet]]: true },
@domenic
domenic Feb 12, 2016 Member

These strings need <code>-ifying

@annevk
annevk Feb 13, 2016 Member

Providing an xref would be weird though, right?

@domenic
domenic Feb 14, 2016 Member

Yeah, I agree it would be weird.

@domenic domenic commented on an outdated diff Feb 12, 2016
+
+ <li><p>Return undefined.</p></li>
+ </ol>
+
+ <h6><dfn>CrossOriginPropertyDescriptor</dfn> ( <var>crossOriginProperty</var>,
+ <var>originalDesc</var> )</h6>
+
+ <ol>
+ <li>
+ <p>If <var>crossOriginProperty</var>.[[needsGet]] and
+ <var>crossOriginProperty</var>.[[needsSet]] are absent, then:</p>
+
+ <ol>
+ <li><p>Let <var>value</var> be <var>originalDesc</var>.[[Value]].</p></li>
+
+ <li><p>If IsCallable(<var>value</var>) is true, set <var>value</var> to
@domenic
domenic Feb 12, 2016 Member

IsCallable needs to link

@domenic domenic commented on an outdated diff Feb 12, 2016
+ </ol>
+
+ <hr>
+
+ <p>A <dfn>cross-origin wrapper function</dfn> is an anonymous built-in function that has a
+ [[Wrapped]] internal slot.</p>
+
+ <p>When a <span>cross-origin wrapper function</span> <var>F</var> is called with a list of
+ arguments <var>argumentsList</var>, the following steps are taken:</p>
+
+ <ol>
+ <li><p>Assert: <var>F</var> has a [[Wrapped]] internal slot that is a function.</p></li>
+
+ <li><p>Let <var>wrappedFunction</var> be the [[Wrapped]] internal slot of <var>F</var>.</p></li>
+
+ <li><p>Return ? Call(<var>wrappedFunction</var>, this, <var>argumentsList</var>).</p></li>
@domenic
domenic Feb 12, 2016 Member

Call needs to link

@domenic domenic and 1 other commented on an outdated diff Feb 12, 2016
+ <p>Return true.</p>
+
+ <p class="note">If the property does not exist [[GetOwnProperty]] will have thrown an
+ exception and this step will not be reached.</p>
+ </li>
+ </ol>
+
+ <h5><dfn>CrossOriginGet</dfn> ( <var>O</var>, <var>P</var>, <var>Receiver</var> )</h5>
+
+ <ol>
+ <li><p>Let <var>desc</var> be <var>O</var>.[[GetOwnProperty]](<var>P</var>).</p></li>
+
+ <li><p>If <span>IsDataDescriptor</span>(<var>desc</var>) is true, then return
+ <var>desc</var>.[[Value]].</p></li>
+
+ <li><p>Otherwise, <span>IsAccessorDescriptor</span>(<var>desc</var>) must be true so, let
@domenic
domenic Feb 12, 2016 Member

This seems to be a typo in the ES source; should be "true, so let". Will file an ES bug.

@annevk
annevk Feb 13, 2016 Member

Seems they decided to bikeshed: tc39/ecma262#389...

@annevk
annevk Feb 14, 2016 Member

This is not yet addressed, pending tc39.

@domenic
domenic Feb 14, 2016 Member

I'd do "true, so let" pending their decision; what's there is just wrong.

@domenic domenic commented on an outdated diff Feb 12, 2016
+ exception and this step will not be reached.</p>
+ </li>
+ </ol>
+
+ <h5><dfn>CrossOriginGet</dfn> ( <var>O</var>, <var>P</var>, <var>Receiver</var> )</h5>
+
+ <ol>
+ <li><p>Let <var>desc</var> be <var>O</var>.[[GetOwnProperty]](<var>P</var>).</p></li>
+
+ <li><p>If <span>IsDataDescriptor</span>(<var>desc</var>) is true, then return
+ <var>desc</var>.[[Value]].</p></li>
+
+ <li><p>Otherwise, <span>IsAccessorDescriptor</span>(<var>desc</var>) must be true so, let
+ <var>getter</var> be <var>desc</var>.[[Get]].</p></li>
+
+ <li><p>If <var>getter</var> is not undefined, return ? Call(<var>getter</var>,
@domenic
domenic Feb 12, 2016 Member

Link Call

@domenic domenic commented on an outdated diff Feb 12, 2016
+
+ <h5><dfn>CrossOriginSet</dfn> ( <var>O</var>, <var>P</var>, <var>V</var>,
+ <var>Receiver</var> )</h5>
+
+ <ol>
+ <li><p>Let <var>desc</var> be <var>O</var>.[[GetOwnProperty]](<var>P</var>).</p></li>
+
+ <li>
+ <p>If <span>IsAccessorDescriptor</span>(<var>desc</var>) is true, then:</p>
+
+ <ol>
+ <li><p>Let <var>setter</var> be <var>desc</var>.[[Set]].</p></li>
+
+ <li><p>If <var>setter</var> is undefined, return false.</p></li>
+
+ <li><p>Perform ? Call(<var>setter</var>, <var>Receiver</var>, «<var>V</var>»).</p></li>
@domenic
domenic Feb 12, 2016 Member

Link Call

@domenic domenic commented on an outdated diff Feb 12, 2016
- <p>As mentioned earlier, each <span>browsing context</span> has a
- <dfn><code>WindowProxy</code></dfn> object. This object is unusual in that all operations that
- would be performed on it must be performed on the <code>Window</code> object of the <span>browsing
- context</span>'s <span>active document</span> instead. It is thus indistinguishable from that
- <code>Window</code> object in every way until the <span>browsing context</span> is navigated.</p>
+ <p>A <dfn><code>WindowProxy</code></dfn> is an exotic object that wraps a <code>Window</code>
+ object, indirecting most operations through to the wrapped object. Each
+ <span>browsing context</span> has an associated <code>WindowProxy</code> object. When the
+ <span>browsing context</span> is navigated, the <code>Window</code> object wrapped by the
@domenic
domenic Feb 12, 2016 Member

Maybe navigated should be a link.

@domenic domenic and 1 other commented on an outdated diff Feb 13, 2016
+
+ <li><p>Otherwise, if <var>type</var> is "<code data-x="">setter</code>" and
+ <var>e</var>.[[needsSet]] is true, then return.</p></li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+
+ <li><p>If <span>IsPlatformObjectSameOrigin</span>(<var>platformObject</var>) is false, then throw
+ a <code>SecurityError</code>.</p></li>
+ </ol>
+
+
+ <h4>Shared internal slot: [[crossOriginPropertyDescriptorMap]]</h4>
@domenic
domenic Feb 13, 2016 Member

I now realize that this should probably be capitalized ([[CrossOriginPropertyDescriptorMap]]). In streams I for some reason went with initial lowercase, but most of ES (not all) uses initial-uppercase, and so do we for [[Window]].

@annevk
annevk Feb 13, 2016 Member

Does this also apply to fields, such as [[needsGet]]?

@annevk
annevk Feb 14, 2016 Member

This is not yet addressed, wanted to know the scope first.

@domenic
domenic Feb 14, 2016 Member

Good point. Yes, those should probably be uppercase too.

@domenic domenic commented on an outdated diff Feb 13, 2016
+ corresponding key in the map cannot be garbage collected as that would be observable.</p>
+
+ <p>User agents may have an optimization whereby they remove key-value pairs from the map when
+ <code data-x="dom-document-domain">document.domain</code> is set. This is not observable as <code
+ data-x="dom-document-domain">document.domain</code> cannot revisit an earlier value.</p>
+
+ <p class="example">For example, setting <code data-x="dom-document-domain">document.domain</code>
+ to "<code data-x="">example.com</code>" on www.example.com, means user agents can remove all
+ key-value pairs from the map where part of the key is www.example.com as that can never be part of
+ the <span>effective script origin</span> again and therefore the corresponding value could never
+ be retrieved from the map.</p>
+
+
+ <h4>Shared abstract operations</h4>
+
+ <h5><dfn>CrossOriginProperties</dfn>( <var>O</var> )</h5>
@domenic
domenic Feb 13, 2016 Member

Need space between CrossOriginProperties and (

@domenic domenic and 1 other commented on an outdated diff Feb 13, 2016
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+
+ <li><p>If <span>IsPlatformObjectSameOrigin</span>(<var>platformObject</var>) is false, then throw
+ a <code>SecurityError</code>.</p></li>
+ </ol>
+
+
+ <h4>Shared internal slot: [[crossOriginPropertyDescriptorMap]]</h4>
+
+ <p><code>Window</code> and <code>Location</code> objects both have a
+ [[<dfn>crossOriginPropertyDescriptorMap</dfn>]] internal slot, whose value is initially an empty
+ map.
@domenic
domenic Feb 13, 2016 Member

Maybe it would be good to add a sentence explaining what it is used for in practice, so people can get an intuition for it. This might not be right, but I think it's something like:

This contains entries mapping from (origin1, origin2, propertyKey)-tuples to property descriptors, as a memoization of what is visible to author scripts when the origin1 inspects a Window or Location object from origin2. It is filled lazily by [CrossOriginGetOwnPropertyHelper], which consults it on future lookups.

@annevk
annevk Feb 14, 2016 Member

I added a note in fixup2.

@domenic domenic commented on an outdated diff Feb 13, 2016
+ <li><p>Let <var>W</var> be the value of the
+ [[<span data-x="concept-windowproxy-window">Window</span>]] internal slot of
+ <b>this</b>.</p></li>
+
+ <li><p>Let <var>keys</var> be a new empty <span>List</span>.</p></li>
+
+ <li><p>Let <var>maxProperties</var> be the <span>number of child browsing contexts</span> of
+ <var>W</var>.</p></li>
+
+ <li><p>Let <var>index</var> be 0.</p></li>
+
+ <li>
+ <p>Repeat while <var>index</var> &lt; <var>maxProperties</var>,
+
+ <ol>
+ <li><p>Add ! ToString(<var>index</var>) as the last element of <var>keys</var>.</p></li>
@domenic
domenic Feb 13, 2016 Member

Link ToString

@domenic domenic commented on an outdated diff Feb 13, 2016
@@ -79016,6 +79483,64 @@ State: &lt;OUTPUT NAME=I>1&lt;/OUTPUT> &lt;INPUT VALUE="Increment" TYPE=BUTTON O
<p>Each <code>Window</code> object is associated with a unique instance of a <code>Location</code>
object, allocated when the <code>Window</code> object is created.</p>
+ <div w-nodev>
+
+ <p class="warning">The <code>Location</code> exotic object is defined through a mishmash of IDL,
+ invocation of JavaScript internal methods post-creation, and overridden JavaScript internal
+ methods. Coupled with its scary security policy, please take extra care while implementing
+ this excrescence.</p>
+
+ <p>To create a <code>Location</code> object, run these steps:</p>
+
+ <ol>
+ <li><p>Let <var>location</var> be a new <code>Location</code> <span>platform
+ object</span>.</p></li>
+
+ <li><p>Perform ! <var>location</var>.[[DefineOwnProperty]]("toString", {
@domenic
domenic Feb 13, 2016 Member

Code-ify strings throughout this algorithm

@domenic domenic commented on an outdated diff Feb 13, 2016
+ </li>
+
+ <li><p>Perform ! <var>location</var>.[[DefineOwnProperty]]("valueOf", {
+ [[Value]]: <var>valueOfFunction</var>,
+ [[Writable]]: false,
+ [[Enumerable]]: false,
+ [[Configurable]]: false }).</p></li>
+
+ <li><p>Perform ! <var>location</var>.[[DefineOwnProperty]](<span>@@toPrimitive</span>, { [
+ [Value]]: undefined,
+ [[Writable]]: false,
+ [[Enumerable]]: false,
+ [[Configurable]]: false }).</p></li>
+
+ <li><p>Set the value of the [[<span>defaultProperties</span>]] internal slot of
+ <var>location</var> to <var>location</var>.[[OwnPropertyKeys]]().</p></li>
@domenic
domenic Feb 13, 2016 Member

Add a ! before location.[OwnPropertyKeys].

@domenic
domenic Feb 13, 2016 Member

Actually not really needed; ES is a bit lax about conflating completion values with the normal completions they represent, on purpose. Otherwise you'd have to replace all the IsXyz()s with ! IsXyz()s.

@domenic domenic commented on the diff Feb 13, 2016
@@ -79211,9 +79736,18 @@ State: &lt;OUTPUT NAME=I>1&lt;/OUTPUT> &lt;INPUT VALUE="Increment" TYPE=BUTTON O
</li>
</ol>
- <p>The <dfn><code data-x="dom-location-href">href</code></dfn> attribute's getter must return this
- <code>Location</code> object's <span data-x="concept-location-url">url</span>, <span
- data-x="concept-url-serialiser">serialised</span>.</p>
+ <p>The <dfn><code data-x="dom-location-href">href</code></dfn> attribute's getter must run these
+ steps:</p>
+
+ <ol>
+ <li><p>If this <code>Location</code> object's <span>relevant <code>Document</code></span>'s
+ <span>effective script origin</span> is not <span>same origin</span> with <span>entry settings
+ object</span>'s <span>effective script origin</span>, throw a <code>SecurityError</code>
+ exception.</p></li>
@domenic
domenic Feb 13, 2016 Member

I don't suppose IsPlatformObjectSameOrigin would work here, would it?

@annevk
annevk Feb 13, 2016 Member

Entry settings object is not the current Realm Record's [[globalObject]]'s relevant settings object, so I don't think so.

@domenic domenic and 1 other commented on an outdated diff Feb 13, 2016
@@ -79579,72 +80214,151 @@ State: &lt;OUTPUT NAME=I>1&lt;/OUTPUT> &lt;INPUT VALUE="Increment" TYPE=BUTTON O
<li><p>Return to the step labeled <i>loop</i>.</p></li>
- <li><p><i>End</i>: Let <var>output</var> be the values of the array, in the same order.</p></li>
+ <li><p><i>End</i>: Return <var>output</var>.</p></li>
+ </ol>
+
+ <hr>
+
+ <p>As explained earlier, the <code>Location</code> exotic object requires additional logic beyond
+ IDL for security purposes. An internal slot, abstract operation, and the internal methods
+ <code>Location</code> objects must implement are defined below.</p>
+
+ <p>Every <code>Location</code> object has a [[<dfn>defaultProperties</dfn>]] internal slot
+ representing the own properties at time of creation.</p>
@domenic
domenic Feb 13, 2016 Member

"representing its own properties at the time of its creation"

@annevk
annevk Feb 13, 2016 Member

I guess we should make this [[DefaultProperties]] then per the earlier comment?

@domenic domenic commented on an outdated diff Feb 13, 2016
+ <li><p>If <span>IsLocationDefaultProperty</span>(<b>this</b>, <var>P</var>) is true, then
+ return false.</p></li>
+
+ <li><p>Return ? <span>OrdinaryDefineOwnProperty</span>(<b>this</b>, <var>P</var>,
+ <var>Desc</var>).</p></li>
+ </ol>
+ </li>
+
+ <li><p>Return false.</p></li>
+ </ol>
+
+ <h5 id="location-hasproperty">[[HasProperty]] ( <var>P</var> )</h5>
+
+ <ol>
+ <li><p>If <span>IsPlatformObjectSameOrigin</span>(<b>this</b>) is true, then return ?
+ <span>OrdinaryHasProperty</span>(<b>O</b>, <var>P</var>).</p></li>
@domenic
domenic Feb 13, 2016 Member

s/O/this

@ajklein
Collaborator
ajklein commented Feb 13, 2016

@verwaest for more v8 WindowProxy expertise

@domenic
Member
domenic commented Feb 13, 2016

Finished another pass. Pretty much all editorial stuff. This is looking really good. I'm impressed and excited.

@annevk
Member
annevk commented Feb 14, 2016

https://html5.org/temp/cross-origin-objects-review.html now hosts the latest version, including fixup2.

@annevk
Member
annevk commented Feb 14, 2016

Supporting indexed properties directly on WindowProxy objects is not as easy as I thought it would be. In particular, [[HasProperty]], [[Get]], [[Set]], and [[Delete]] all need another look and likely fixes for the same-origin case. (It also bothers me somewhat that IDL and ECMAScript seemingly have slightly different algorithms for dealing with indexed properties. I guess I'll try to side with IDL for now and file an issue of sorts.)

@annevk
Member
annevk commented Feb 15, 2016

Hopefully fixed now. URL above still contains the latest version.

@annevk
Member
annevk commented Feb 17, 2016

I filed tc39/ecma262#393 as an editorial issue against ECMAScript that might influence what casing we use for internal records and fields. I also filed tc39/ecma262#394 about the guarantees around Ordinary* abstract operations.

Review would still be appreciated, but I also think landing this would be okay at this point as a significant improvement over the status quo.

@domenic
Member
domenic commented Feb 18, 2016
  • New question: why is Location's valueOf defined as a new function unique to each Location instance, but its toString gets to reuse %ObjProto_toString%?
  • Consider replacing "If IsLocationDefaultProperty(this, P)" with just "If the [[DefaultProperties]] internal slot of this contains P".

Otherwise LGTM! We should merge this soon.

@annevk
Member
annevk commented Feb 19, 2016

valueOf and toString for Location are based on [Unforgeable] interfaces (which was designed for Location, but Location will no longer use and can therefore be removed from IDL (I filed a bug)): https://heycam.github.io/webidl/#es-platform-objects. Perhaps you are correct though and we should create %objProto_valueOf% in ECMAScript and use that here. @bzbarsky, what do you think?

@annevk
Member
annevk commented Feb 19, 2016

@heycam you might be able to help out with the question about valueOf on [Unforgeable] interfaces above too.

@bzbarsky
Collaborator

Perhaps you are correct though and we should create %objProto_valueOf% in ECMAScript and use that here.

We could do that, I guess. Note, however, that %objProto_valueOf% and the function defined in this diff both have different behavior from the valueOf function Web IDL defines for Location right now and that Gecko implements. That function is defined to return this, while the new setup is returning ToObject(this). What's the reason for the behavior change?

@bzbarsky
Collaborator

Oh, and the valueOf thing is pretty inconsistent across browsers right now. Safari doesn't have it as an own prop on Location. Chrome has it as an own prop, but it enforces "this" being a Location, apparently, instead of just returning this.

@annevk
Member
annevk commented Feb 19, 2016

@bzbarsky I had assumed IDL was sloppy and intended to match Object.prototype.valueOf. Happy to change this back to what IDL used to say (which would also rule out uplifting this to ECMAScript).

@domenic
Member
domenic commented Feb 19, 2016

Since it's so inconsistent anyway, I'd prefer to go with the most sane thing (just making it a pointer to %ObjProto_valueOf%) instead of picking one vendor's idiosyncratic choice and canonizing that. Even if that is what IDL currently defines.

@bzbarsky
Collaborator

I am probably OK with that if there is some sort of guarantee that ToObject() on an object (and in general, the behavior of Object.prototype.valueOf) will never become hookable in ES. That probably requires an explicit note in the ES spec indicating that it must never become so. Because if it ever does become hookable, that introduces a security problem, and I have no expectation that an ES editor would know enough about Location to realize they're introducing one, unless the text of the ES spec explicitly points this out....

@annevk
Member
annevk commented Feb 19, 2016

The PR above includes such a comment in the ToObject section.

@bzbarsky
Collaborator

Should add one in the actual valueOf section too, probably...

@annevk
Member
annevk commented Feb 22, 2016

I'm having a hard time persuading folks that notifying downstream of these hooks is important. Even if I don't persuade them though, I think we should still go with %ObjProto_valueOf%. Any kind of hook ECMAScript adds anywhere poses a problem for these objects.

@bterlson bterlson added a commit to tc39/ecma262 that referenced this pull request Feb 24, 2016
@annevk @bterlson annevk + bterlson Editorial: introduce %ObjProto_valueOf% for usage by the Location exo…
…tic object

See whatwg/html#638 (comment) for context.
28c5237
@domenic
Member
domenic commented Feb 24, 2016

OK, now that ES has the appropriate hook, this LGTM!!!!! I'll let you do the honors, @annevk. wooohoooo!!!

@domenic domenic assigned annevk and unassigned domenic Feb 24, 2016
@annevk annevk assigned domenic and unassigned annevk Feb 25, 2016
@annevk
Member
annevk commented Feb 25, 2016

@domenic I had a few more issues opened against ECMAScript that are now resolved (two PRs still pending). The biggest change is the removal of [[HasProperty]] overrides due to an upstream change. Since OrdinaryHasProperty will invoke [[GetOwnProperty]] now instead of OrdinaryGetOwnProperty.

@annevk
Member
annevk commented Feb 25, 2016

In another PR @domenic noted:

I think for these kind of informal maps, I much prefer the phrasing I used for the module map:

  • If module map contains an entry with key url, ...
  • If module map contains an entry with key url whose value is "fetching", ...
  • Create an entry in module map with key url and value "fetching"

Pretty sure we're not using that terminology for the internal map we are introducing here.

@domenic domenic commented on an outdated diff Feb 25, 2016
+ <li>
+ <p>If <span>IsPlatformObjectSameOrigin</span>(<b>this</b>) is true, then:</p>
+
+ <ol>
+ <li><p>If the value of the [[<span>DefaultProperties</span>]] internal slot of <b>this</b>
+ contains <var>P</var>, then return false.</p></li>
+
+ <li><p>Return ? <span>OrdinaryDefineOwnProperty</span>(<b>this</b>, <var>P</var>,
+ <var>Desc</var>).</p></li>
+ </ol>
+ </li>
+
+ <li><p>Return false.</p></li>
+ </ol>
+
+ <h5 id="location-get-receiver">[[Get]] ( <var>P</var>, <var>Receiver</var> )</h5>
@domenic
domenic Feb 25, 2016 Member

Can this be "location-get"?

@domenic domenic commented on an outdated diff Feb 25, 2016
+ </li>
+
+ <li><p>Return false.</p></li>
+ </ol>
+
+ <h5 id="location-get-receiver">[[Get]] ( <var>P</var>, <var>Receiver</var> )</h5>
+
+ <ol>
+ <li><p>If <span>IsPlatformObjectSameOrigin</span>(<b>this</b>) is true, then return ?
+ <span>OrdinaryGet</span>(<b>this</b>, <var>P</var>, <var>Receiver</var>).</p></li>
+
+ <li><p>Return ? <span>CrossOriginGet</span>(<b>this</b>, <var>P</var>,
+ <var>Receiver</var>).</p></li>
+ </ol>
+
+ <h5 id="location-set-v-receiver">[[Set]] ( <var>P</var>, <var>V</var>, <var>Receiver</var> )</h5>
@domenic
domenic Feb 25, 2016 Member

"location-set"?

@annevk
Member
annevk commented Feb 26, 2016

Is the "do not merge yet" label there because of tc39/ecma262#416?

@domenic
Member
domenic commented Feb 26, 2016

Yep

@domenic
Member
domenic commented Feb 26, 2016

Dependencies merged; land at will @annevk!

@annevk annevk Define security around Window, WindowProxy, and Location properly
This is a relative large change to the way Window, WindowProxy, and Location objects work, at least
from a standards perspective. This should more closely match implementations and define all their
relevant security details.

A rough summary of the changes:

* Window indexed getters have moved to WindowProxy.
* WindowProxy is now a JavaScript exotic object and it handles all the security aspects for Window
  so Window can become an ordinary object.
* Cross-origin named properties for Window are now exposed (though on WindowProxy).
* Location is now an exotic object with all its internal methods overridden to handle the
  cross-origin security aspects.
* Location no longer uses Unforgeable on the interface, allowing that to be removed from IDL. (It
  moved to all of its properties instead and the remaining details are defined through prose.)

This should also address these bugs:

* https://www.w3.org/Bugs/Public/show_bug.cgi?id=20701
* https://www.w3.org/Bugs/Public/show_bug.cgi?id=21674
* https://www.w3.org/Bugs/Public/show_bug.cgi?id=22346
* https://www.w3.org/Bugs/Public/show_bug.cgi?id=27128
* https://www.w3.org/Bugs/Public/show_bug.cgi?id=27502
acae3df
@annevk annevk merged commit acae3df into master Feb 27, 2016
@annevk annevk deleted the cross-origin-objects branch Feb 27, 2016
@sideshowbarker
Member

Rock n rollーVery cool to see this landing.

@domenic
Member
domenic commented Feb 27, 2016

This might deserve a blog post :D

@caitp caitp referenced this pull request in w3c/web-platform-tests Mar 9, 2016
Closed

Bug in test for cross-origin access to window[@@iterator] #2664

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment