Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spec: Wait for network revocation in nested fenced frames before disabling network. #176

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Changes from 33 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c9cbe3f
disableUntrustedNetwork skeleton
Apr 3, 2024
39d31fb
fill out more
Apr 9, 2024
7eaf2b1
more
Apr 9, 2024
c4705a6
address comments
Apr 11, 2024
ab9785d
skeleton
Jul 10, 2024
d75f324
content done % links
Jul 17, 2024
294e5fd
Merge remote-tracking branch 'origin/revoke-network' into liam-nested…
blu25 Aug 6, 2024
7c89c4e
Update spec.bs
blu25 Aug 8, 2024
0ce475f
remove 'defaults to'
blu25 Sep 11, 2024
2fc1484
Merge branch 'master' into liam-nested-revocation
blu25 Sep 11, 2024
c92fa38
address comments for code that's new in this PR
blu25 Sep 11, 2024
d94859f
Update spec.bs
blu25 Sep 12, 2024
9b6e158
attempt to fix validation errors
blu25 Sep 12, 2024
5d982b3
attempt to fix validation errors
blu25 Sep 12, 2024
f760c12
Merge branch 'master' into liam-nested-revocation
blu25 Sep 12, 2024
44435e0
test if removing the note fixes the build
blu25 Sep 12, 2024
78d1673
attempt to fix validation errors
blu25 Sep 12, 2024
77e3bd4
Update spec.bs
blu25 Sep 12, 2024
f5b1255
remove "can disable untrusted network"
blu25 Sep 12, 2024
a51ffdd
convert same-origin check to assert
blu25 Sep 12, 2024
5316240
update credentialless issue link
blu25 Sep 12, 2024
a24cd13
Merge branch 'master' into revoke-network
blu25 Sep 12, 2024
62f3b43
add changes from other review
blu25 Sep 12, 2024
49fe6a2
address comments
blu25 Sep 12, 2024
eb6bae4
Merge branch 'revoke-network' into liam-nested-revocation
blu25 Sep 12, 2024
9de235e
Update spec.bs
blu25 Oct 4, 2024
aabfad3
Merge branch 'master' into liam-nested-revocation
blu25 Nov 1, 2024
2c067b0
address review comments
blu25 Nov 1, 2024
19b33b4
Merge branch 'master' into liam-nested-revocation
blu25 Nov 4, 2024
95cc597
clean up merge issues
blu25 Nov 4, 2024
38d1e66
clean up and move note to definition
blu25 Nov 4, 2024
7a0e92a
Merge branch 'master' into liam-nested-revocation
blu25 Dec 3, 2024
f30fc25
address comments
blu25 Dec 6, 2024
eaf68b0
call out what is being stored in navigablesWithNetworkChildren
blu25 Dec 10, 2024
f476341
address review comments
blu25 Dec 12, 2024
adfb311
address review comments
blu25 Dec 23, 2024
589ca57
add iframe call and run in parallel
blu25 Dec 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 152 additions & 44 deletions spec.bs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
urlPrefix: embedder-content-other.html
text: width; url: attr-dim-width
text: height; url: attr-dim-height
urlPrefix: document-lifecycle.html
text: abort a document; url: abort-a-document
urlPrefix: document-sequences.html
text: browsing context group; url: browsing-context-group
text: browsing context group set; url: browsing-context-group-set
Expand Down Expand Up @@ -144,6 +146,7 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
text: historyHandling; url: navigation-hh
text: referrerPolicy; url: navigation-referrer-policy
text: attempt to populate the history entry's document; url: attempt-to-populate-the-history-entry's-document
text: completionSteps; url: attempt-to-populate-completion-steps
text: navigation params; url: navigation-params
text: snapshot source snapshot params; url: snapshotting-source-snapshot-params
text: the navigation must be a replace; url: the-navigation-must-be-a-replace
Expand Down Expand Up @@ -483,8 +486,13 @@ attribute.
</div>

<div algorithm=destroy>
When a <{fencedframe}> element is [=removed from a document=], the user agent <p class=XXX>TODO:
destroy the nested traversable</p>.
When a <{fencedframe}> element is [=removed from a document=], the user agent must run the
following steps:

1. <p class=XXX>TODO: destroy the nested traversable.</p>

1. [=Recalculate the untrusted network status of all fenced frame descendants=] given the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also have to do this during iframe teardown? I don't think so but I want to be sure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only if the iframe teardown results in a child fenced frame also being torn down, but that will get caught by this anyway, so we don't need to add anything for iframes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait how will it get caught by this? Check out the iframe destruction/removal path — I don't think it results in fenced frames being "removed" from the DOM, so I don't think we'd go through this path for fenced frames if their iframe parent is removed.

Also, note that the recalculate algorithm requires being in parallel, but the removal steps are not called from in parallel. That's a bug.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I had assumed it was a cascading operation, but it looks like it's not. I'll add a separate removed from a document algorithm for iframes. I didn't see any place where this was being called for iframes to begin with, so it should be okay to add a new algorithm.

I'm not sure if there's some common path that would be better to put this in. I considered the node removal algorithm, but that lives in the DOM spec, and I don't think that's supposed to get access to the concepts of traversables and node navigables. Let me know if there's a better spot you think this could live in.

I also updated the calls to be run in parallel.

Copy link
Collaborator

@domfarolino domfarolino Dec 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's already being called here: https://html.spec.whatwg.org/C#the-iframe-element:html-element-removing-steps. It's using the more appropriate removing steps hook, instead of the removed from document hook, which I have a goal of removing from the HTML spec anyways, so I don't think we should add more instances of it sadly.

So I guess we should just monkeypatch the existing iframe algorithm, and as a follow-up, some day we can probably modify our spec to not use the removed from document hook.

{{Document}}'s [=node navigable=]'s [=navigable/top-level traversable=].
</div>

The <dfn attribute for=HTMLFencedFrameElement>config</dfn> IDL attribute getter steps are to return
Expand Down Expand Up @@ -849,6 +857,11 @@ a reporting destination=] through the reference it kept, it will handle all of t
stored in the [=list=]. If the destination is never finalized, then the pending events will never
be sent.

An <dfn for=fencedframetype>untrusted network status</dfn> is either "<dfn export for='untrusted
network status'>`enabled`</dfn>", "<dfn export for='untrusted network status'>`disabled for this
tree`</dfn>", or "<dfn export for='untrusted network status'>`disabled for this and descendant
blu25 marked this conversation as resolved.
Show resolved Hide resolved
trees`</dfn>".

<div algorithm>
In order to <dfn export>finalize a reporting destination</dfn>, given a [=fencedframetype/fenced
frame reporting map=] |reporting map|, a {{FenceReportingDestination}} |destination|, an
Expand Down Expand Up @@ -1224,17 +1237,18 @@ A <dfn export>fenced frame config</dfn> is a [=struct=] with the following [=str
: <dfn for="effective enabled permissions">visibility</dfn>
:: a [=fencedframeconfig/visibility=]

Note: When non-null, this is a [=list=] of [=policy-controlled features=] that the generator of
this config relies on exclusively being enabled inside the <{fencedframe}> that navigates to
this config. Specifically, each feature in this list <span class=allow-2119>must</span> be
enabled by the <{fencedframe}>'s [=fenced navigable container/fenced navigable=]'s
[=Document/permissions policy=]'s [=permissions policy/inherited policy=] when navigating to
this config for the navigation to succeed. The features in this list are not force-enabled, but
rather are used to check that the embedder environment that influences the aforementioned
[=permissions policy/inherited policy=] is relaxed enough to support these essential features.
If the [=inherited policy for a feature|inherited policy value=] for any of these features is
"`Disabled`", the navigation to this config will fail. Any [=policy-controlled feature=] *not*
in this list will not be "`Disabled`" in the <{fencedframe}> that navigates to this config.
Note: When non-null, this is a [=list=] of [=policy-controlled features=] that the generator
of this config relies on exclusively being enabled inside the <{fencedframe}> that navigates
to this config. Specifically, each feature in this list <span class=allow-2119>must</span> be
enabled by the <{fencedframe}>'s [=fenced navigable container/fenced navigable=]'s
[=Document/permissions policy=]'s [=permissions policy/inherited policy=] when navigating to
this config for the navigation to succeed. The features in this list are not force-enabled,
but rather are used to check that the embedder environment that influences the aforementioned
[=permissions policy/inherited policy=] is relaxed enough to support these essential
features. If the [=inherited policy for a feature|inherited policy value=] for any of these
features is "`Disabled`", the navigation to this config will fail. Any [=policy-controlled
feature=] *not* in this list will not be "`Disabled`" in the <{fencedframe}> that navigates
to this config.

: <dfn>fenced frame reporting metadata</dfn>
:: null, or a [=struct=] with the following [=struct/items=]:
Expand Down Expand Up @@ -1266,16 +1280,16 @@ A <dfn export>fenced frame config</dfn> is a [=struct=] with the following [=str
: <dfn>is ad component</dfn>
:: A [=boolean=], initially false.

Note: When true, this [=fenced frame config=] represents an ad component. An ad component can
be used to construct ads composed of multiple pieces. See the <a
href=https://github.com/WICG/turtledove/blob/main/FLEDGE.md#34-ads-composed-of-multiple-pieces>Protected
Audience explainer</a>. For an ad component, event reporting is handled differently. See the <a
href=https://github.com/WICG/turtledove/blob/main/Fenced_Frames_Ads_Reporting.md#support-for-ad-components>Fenced
Frame Ads Reporting explainer</a> that describes this.

: <dfn>cross-origin reporting allowed</dfn>
:: A [=boolean=], initially false.
</dl>

Note: When true, this [=fenced frame config=] represents an ad component. An ad component can be
used to construct ads composed of multiple pieces. See the <a
href=https://github.com/WICG/turtledove/blob/main/FLEDGE.md#34-ads-composed-of-multiple-pieces>Protected
Audience explainer</a>. For an ad component, event reporting is handled differently. See the <a
href=https://github.com/WICG/turtledove/blob/main/Fenced_Frames_Ads_Reporting.md#support-for-ad-components>Fenced
Frame Ads Reporting explainer</a> that describes this.

<h4 id=fenced-frame-config-instance-struct>The [=fenced frame config instance=] [=struct=]</h4>

Expand Down Expand Up @@ -1322,8 +1336,19 @@ A <dfn export>fenced frame config instance</dfn> is a [=struct=] with the follow
: <dfn>is ad component</dfn>
:: A [=boolean=]

: <dfn>has disabled untrusted network</dfn>
:: A [=boolean=], initially false.
: <dfn>untrusted network status</dfn>
:: An [=fencedframetype/untrusted network status=], initially [=untrusted network
status/enabled=].

: <dfn>on network disabled promises</dfn>
:: A [=map=] whose [=map/keys=] are [=global objects=] and [=values=] are [=lists=] of
{{Promise|Promises}}, initially empty.

Note: This stores various {{Promise|Promises}} from various globals that were created during
{{Fence/disableUntrustedNetwork()}}. We store them here so that we can resolve all of them at
once when the <{fencedframe}> and its descendants have their network access fully revoked
(i.e., the [=fenced frame config instance/untrusted network status=] is [=untrusted network
status/disabled for this and descendant trees=]).

: <dfn>cross-origin reporting allowed</dfn>
:: A [=boolean=], initially false.
Expand Down Expand Up @@ -1415,8 +1440,11 @@ A <dfn export>fenced frame config instance</dfn> is a [=struct=] with the follow
: [=fenced frame config instance/cross-origin reporting allowed=]
:: |config|'s [=fenced frame config/cross-origin reporting allowed=]

: [=fenced frame config instance/has disabled untrusted network=]
:: false
: [=fenced frame config instance/untrusted network status=]
:: [=untrusted network status/enabled=]

: [=fenced frame config instance/on network disabled promises=]
:: A empty [=map=].
</div>

Each [=browsing context=] has a <dfn for="browsing context">fenced frame config instance</dfn>,
Expand Down Expand Up @@ -1937,8 +1965,11 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface.

1. Let |p| be [=a new promise=].

1. Let |instance| be [=this=]'s [=relevant global object=]'s [=Window/browsing context=]'s
[=browsing context/fenced frame config instance=].
1. Let |context| be [=this=]'s [=relevant global object=]'s [=Window/browsing context=].

1. If |context| is null, then throw a {{SecurityError}} {{DOMException}}.
domfarolino marked this conversation as resolved.
Show resolved Hide resolved

1. Let |instance| be |context|'s [=browsing context/fenced frame config instance=].

1. If the [=relevant settings object=]'s [=environment settings object/origin=] and
|instance|'s [=fenced frame config instance/mapped url=]'s [=url/origin=] are not [=same
Expand All @@ -1954,28 +1985,84 @@ Several APIs specific to fenced frames are defined on the {{Fence}} interface.

1. Let |fencedFrameNonce| be |instance|'s [=fenced frame config instance/partition nonce=].

1. Let |credentiallessNonce| be

Issue: the page credentialless nonce
(<a href="https://github.com/WICG/fenced-frame/issues/191">WICG/fenced-frame#191</a>)
1. Let |credentiallessNonce| be |global|'s [=page credentialless nonce=].

1. Invoke [=revoke network for a partition nonce=] on |fencedFrameNonce|.

1. Invoke [=revoke network for a partition nonce=] on |credentiallessNonce|.
1. If |credentiallessNonce| is non-null, invoke [=revoke network for a partition nonce=] on
|credentiallessNonce|.

1. Set |instance|'s [=fenced frame config instance/has disabled untrusted network=] to true.
1. Set |instance|'s [=fenced frame config instance/untrusted network status=] to [=untrusted
network status/disabled for this tree=].

1. Wait on all nested fenced frames to disable network too.
1. Let |promises| be |instance|'s [=fenced frame config instance/on network disabled
promises=].

Issue: Spec this waiting more formally.
(<a href="https://github.com/WICG/fenced-frame/issues/151">WICG/fenced-frame#151</a>)
1. If |promises|[|global|] [=map/exists=], [=list/append=] |p| to |promises|[|global|].

1. [=Queue a global task=] on the [=DOM manipulation task source=] given |global|, to
[=resolve=] |p| with {{undefined}}.
Otherwise, [=map/set=] |promises|[|global|] to the [=list=] « |p| ».

1. [=Recalculate the untrusted network status of all fenced frame descendants=] given
|global|'s [=Window/browsing context=]'s [=browsing context/top-level traversable=].

1. Return |p|.
</div>

<div algorithm>
To <dfn>Recalculate the untrusted network status of all fenced frame descendants</dfn> given a
blu25 marked this conversation as resolved.
Show resolved Hide resolved
[=top-level traversable=] |topLevelTraversable|, run these steps:

1. [=Assert=]: this is running [=in parallel=].

1. Let |navigables| be |topLevelTraversable|'s [=navigable/active document=]'s
blu25 marked this conversation as resolved.
Show resolved Hide resolved
[=Document/inclusive descendant navigables=] with [=inclusive-dn-unfenced|unfenced=] set to
true.

1. Let |navigablesWithNetworkChildren| be an empty [=set=].
blu25 marked this conversation as resolved.
Show resolved Hide resolved

1. [=iteration/While=] |navigables| is not [=stack/empty=]:

1. Let |currentNavigable| be the result of [=stack/pop|popping=] from |navigables|.

1. If |currentNavigable| is not a [=fenced navigable container/fenced navigable=], then
[=iteration/continue=].

1. Let |config| be |currentNavigable|'s [=navigable/active browsing context=]'s [=browsing
context/fenced frame config instance=].

1. If |config|'s [=fenced frame config instance/untrusted network status=] is [=untrusted
network status/disabled for this and descendant trees=], then [=iteration/continue=].

1. Let |networkCutoffReady| be true if |navigablesWithNetworkChildren| does not [=set/contain=]
blu25 marked this conversation as resolved.
Show resolved Hide resolved
|currentNavigable| and |config|'s [=fenced frame config instance/untrusted network status=]
is [=untrusted network status/disabled for this tree=], false otherwise.

Note: A frame is added to |navigablesWithNetworkChildren| when a child fenced frame is
blu25 marked this conversation as resolved.
Show resolved Hide resolved
determined to not be ready for network cutoff.

1. If |networkCutoffReady| is true:

1. Set |config|'s [=fenced frame config instance/untrusted network status=] to [=untrusted
network status/disabled for this and descendant trees=].

1. For each |global| → |promises| in |config|'s [=fenced frame config instance/on network
disabled promises=]:

1. For each |promise| in |promises|:
blu25 marked this conversation as resolved.
Show resolved Hide resolved

1. [=Queue a global task=] on the [=DOM manipulation task source=] given |global|, to
[=resolve=] |promise| with {{undefined}}.

1. [=map/Clear=] |config|'s [=fenced frame config instance/on network disabled promises=].

1. Otherwise:
1. Let |ancestorFencedRoot| be |currentNavigable|'s [=traversable navigable/unfenced
parent=]'s [=navigable/traversable navigable=].

1. If |ancestorFencedRoot| is a [=fenced navigable container/fenced navigable=],
[=set/append=] |ancestorFencedRoot| to |navigablesWithNetworkChildren|.
</div>

A user agent has an associated <dfn>network revocation nonce set</dfn>, which is a [=set=] of
[=partition nonces=], and a <dfn>network revocation exemption map</dfn>, which is a [=map=] whose
[=map/keys=] are [=partition nonces=] and [=map/values=] are [=sets=] of [=URLs=].
Expand Down Expand Up @@ -2027,6 +2114,27 @@ The network revocation mechanism requires the following monkeypatches to the [[F

Add "[=must be blocked due to a revoked partition nonce=]" to the conditions after
"should request be blocked by Content Security Policy".

Issue: This needs to be passed in both the fenced frame nonce as well as the iframe credentialless
nonce, if it exists.
(<a href="https://github.com/WICG/fenced-frame/issues/191">WICG/fenced-frame#191</a>)
</div>

The network revocation mechanism requires the following monkeypatches to the [[HTML]] Standard.

<div algorithm=network-status-document-abort>
Add a new step to the [=abort a document=] algorithm after step 4 that says:

5. [=Recalculate the untrusted network status of all fenced frame descendants=] given <var
blu25 marked this conversation as resolved.
Show resolved Hide resolved
ignore>document</var>'s [=node navigable=]'s [=navigable/top-level traversable=].
</div>

<div algorithm=network-status-navigate>
Modify the call to [=attempt to populate the history entry's document=] in the [=navigate=]
blu25 marked this conversation as resolved.
Show resolved Hide resolved
algorithm. Update the [=completionSteps=] to include the following new step:

2. [=Recalculate the untrusted network status of all fenced frame descendants=] given <var
blu25 marked this conversation as resolved.
Show resolved Hide resolved
ignore>navigable</var>'s [=navigable/top-level traversable=].
</div>

<h3 id=new-request-destination>New [=request=] [=request/destination=]</h3>
Expand Down Expand Up @@ -2733,12 +2841,12 @@ the fenced frame boundary, which is a privacy leak. To avoid this, we effectivel
<div algorithm=currently-focused-area-of-a-top-level-traversable>
Modify step 3 of the [=currently focused area of a top-level traversable=] algorithm to read:

3. While |candidate|'s [=focused area=] is either a [=navigable container=] with a non-null
[=navigable container/content navigable=] or a [=fenced navigable container=] with a non-null
[=fenced navigable container/fenced navigable=]: set |candidate| to the [=navigable/active
document=] of either that [=navigable container=]'s [=navigable container/content navigable=]
or that [=fenced navigable container=]'s [=fenced navigable container/fenced navigable=],
whichever is non-null.
3. [=iteration/While=] |candidate|'s [=focused area=] is either a [=navigable container=] with a
non-null [=navigable container/content navigable=] or a [=fenced navigable container=] with a
non-null [=fenced navigable container/fenced navigable=]: set |candidate| to the
[=navigable/active document=] of either that [=navigable container=]'s [=navigable
container/content navigable=] or that [=fenced navigable container=]'s [=fenced navigable
container/fenced navigable=], whichever is non-null.
</div>

<div algorithm=sequential-focus-navigation-patch>
Expand Down Expand Up @@ -2954,7 +3062,7 @@ CORP violation report=] algorithm, as leaving it unfenced may cause a privacy le

1. Let |current navigable| be |sourceDocument|'s [=node navigable=].

1. While |current navigable| is not null:
1. [=iteration/While=] |current navigable| is not null:

1. [=map/iterate|For each=] |type| → |data| of |current navigable|'s [=navigable/active
document=]'s [=Document/automatic beacon data map=]:
Expand Down
Loading