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

Modify Storage Access to use a "per-frame" model #141

Merged
merged 18 commits into from
Jan 18, 2023
Merged
Changes from 1 commit
Commits
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
89 changes: 40 additions & 49 deletions storage-access.bs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
text: create navigation params by fetching; url: browsing-the-web.html#create-navigation-params-by-fetching
text: set up a window environment settings object; url: nav-history-apis.html#set-up-a-window-environment-settings-object
text: environment
text: DOM manipulation task source; url: webappapis.html#dom-manipulation-task-source

spec: fetch; urlPrefix: https://fetch.spec.whatwg.org/
type: dfn
Expand Down Expand Up @@ -167,13 +168,13 @@ When invoked on {{Document}} |doc|, the <dfn export method for=Document><code>ha

1. Let |p| be [=a new promise=].
1. If |doc| is not [=Document/fully active=], then [=reject=] |p| with an "{{InvalidStateError}}" {{DOMException}} and return |p|.
1. If |doc|'s [=Document/origin=] is an [=opaque origin=], [=/resolve=] |p| with false and return |p|.
1. If |doc|'s [=Document/origin=] is an [=opaque origin=], [=resolve=] |p| with false and return |p|.
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. Let |global| be |doc|'s [=relevant global object=].
1. If |global| is not a [=secure context=], then [=resolve=] |p| with false and return |p|.
1. If |doc|'s [=Document/browsing context=] is a [=top-level browsing context=], [=/resolve=] |p| with true and return |p|.
1. If the [=top-level origin=] of |doc|'s [=relevant settings object=] is an [=opaque origin=], [=/resolve=] |p| with false and return |p|. <!-- https://github.com/privacycg/storage-access/issues/40 -->
1. If |doc|'s [=Document/origin=] is [=same origin=] with the [=top-level origin=] of |doc|'s [=relevant settings object=], [=/resolve=] |p| with true and return |p|.
1. [=Resolve=] |p| with |global's| [=environment/has storage access=].
1. If |doc|'s [=Document/browsing context=] is a [=top-level browsing context=], [=resolve=] |p| with true and return |p|.
1. If the [=top-level origin=] of |doc|'s [=relevant settings object=] is an [=opaque origin=], [=resolve=] |p| with false and return |p|. <!-- https://github.com/privacycg/storage-access/issues/40 -->
1. If |doc|'s [=Document/origin=] is [=same origin=] with the [=top-level origin=] of |doc|'s [=relevant settings object=], [=resolve=] |p| with true and return |p|.
1. [=Queue a global task=] on the [=permissions task source=] given |global| to [=resolve=] |p| with |global's| [=environment/has storage access=].
1. Return |p|.

ISSUE: Shouldn't step 8 be [=same site=]?
Expand All @@ -188,56 +189,46 @@ When invoked on {{Document}} |doc|, the <dfn export method for=Document><code>re
1. If |doc| is not [=Document/fully active=], then [=reject=] |p| with an "{{InvalidStateError}}" {{DOMException}} and return |p|.
1. Let |global| be |doc|'s [=relevant global object=].
1. If |global| is not a [=secure context=], then [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|.
1. If |doc|'s [=Document/browsing context=] is a [=top-level browsing context=], [=/resolve=] and return |p|.
1. If |doc| is not [=allowed to use=] the `"storage-access"` [=powerful feature|feature=], [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|.
1. If |doc|'s [=Document/browsing context=] is a [=top-level browsing context=], [=resolve=] and return |p|.
1. If |doc| is not [=allowed to use=] "`storage-access`", [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|.
1. If |doc|'s [=Document/origin=] is an [=opaque origin=], [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|.
1. If the [=top-level origin=] of |doc|'s [=relevant settings object=] is an [=opaque origin=], [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|. <!-- https://github.com/privacycg/storage-access/issues/40 -->
1. If |doc|'s [=Document/origin=] is [=same origin=] with the [=top-level origin=] of |doc|'s [=relevant settings object=], [=/resolve=] and return |p|.
1. If |doc|'s [=Document/origin=] is [=same origin=] with the [=top-level origin=] of |doc|'s [=relevant settings object=], [=resolve=] and return |p|.
1. If |doc|'s [=active sandboxing flag set=] has its [=sandbox storage access by user activation flag=] set, [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|.
1. Run the following steps in parallel:
1. [=Determine the storage access policy=] with |doc| and |p|.
1. If |global|'s [=environment/has storage access=] is true, [=resolve=] |p| with {{undefined}} and return.
1. Let |has transient activation| be whether |doc|'s {{Window}} object has [=transient activation=].
1. Run the following steps [=in parallel=]:
1. Let |process permission state| be an algorithm that, given a [=permission state=] |state|, runs the following steps:
1. [=Queue a global task=] on the [=permission task source=] given |global| to:
1. If |state| is [=permission/granted=]:
1. Set |global|'s [=environment/has storage access=] to true.
1. [=Resolve=] |p| with {{undefined}}.
1. Else:
1. [=Queue a global task=] on the [=DOM manipulation task source=] given |global| to [=consume user activation=] given |global|.
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. [=Reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}.
1. Let |previous permission state| be the result of [=getting the current permission state=] given "<a permission><code>storage-access</code></a>" and |global|.
1. If |previous permission state| is not [=permission/prompt=]:
1. Run |process permission state| with |previous permission state|.
1. Return.
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. If |has transient activation| is false, [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return.
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. Let |key| be the result of [=generate a partitioned storage key|generating a partitioned storage key=] from |doc|.
1. Let |implicitly granted| and |implicitly denied| (each a [=boolean=]) be the result of running an [=implementation-defined=] set of steps to determine if |key|'s [=partitioned storage key/embedded origin=]'s request for storage access on |key|'s [=partitioned storage key/top-level site=] should be granted or denied without prompting the user.
1. If |implicitly granted| is true:
1. Run |process permission state| with [=permission/granted=].
1. Return.
1. If |implicitly denied| is true:
1. Run |process permission state| with [=permission/denied=].
1. Return.
1. Let |permissionState| be the result of [=requesting permission to use=] "<a permission><code>storage-access</code></a>".
1. Run |process permission state| with |permissionState|.
1. Return |p|.

NOTE: The intent of this algorithm is to always require user activation before a storage-access permission will be set. Though it is within the means of user agents to set storage-access permissions based on custom heuristics without prior user activation, this specification strongly discourages such behavior, as it could lead to interoperability issues.
bvandersloot-mozilla marked this conversation as resolved.
Show resolved Hide resolved

ISSUE(privacycg/storage-access#144): We shouldn't use the permissions task source here.

ISSUE: Shouldn't step 9 be [=same site=]?

<h4 id="ua-policy">User Agent storage access policies</h4>

Different User Agents have different policies around whether or not [=sites=] may access their [=unpartitioned data=] when they're in a [=third party context=]. User Agents check and/or modify these policies when client-side storage is accessed (see [[#storage]]) as well as when {{Document/hasStorageAccess()}} and {{Document/requestStorageAccess()}} are called.

To <dfn type="abstract-op">determine if a site has storage access</dfn> with {{Document}} |doc|, run these steps:

1. Let |global| be |doc|'s [=relevant global object=].
1. Return |global|'s [=environment/has storage access=].

To <dfn type="abstract-op">determine the storage access policy</dfn> for {{Document}} |doc| with {{Promise}} |p|, run these steps:

1. Let |global| be |doc|'s [=relevant global object=].
1. If |global|'s [=environment/has storage access=] is true, [=resolve=] |p| with {{undefined}} and return.
1. Let |previousPermissionState| be the result of [=getting the current permission state=] given "<a permission><code>storage-access</code></a>" and |global|.
1. If |previousPermissionState| is not [=permission/prompt=]:
1. If |previousPermissionState| is [=permission/granted=]:
1. Set |global|'s [=environment/has storage access=] to true.
1. [=/Resolve=] |p| with {{undefined}}.
1. Return.
1. [=/Reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}.
1. Return.
1. If |doc|'s {{Window}} object does not have [=transient activation=], [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return.
1. Let |key| be the result of [=generate a partitioned storage key|generating a partitioned storage key=] from |doc|.
1. Let |implicitly granted| and |implicitly denied| (each a [=boolean=]) be the result of running an [=implementation-defined=] set of steps to determine if |key|'s [=partitioned storage key/embedded origin=]'s request for storage access on |key|'s [=partitioned storage key/top-level site=] should be granted or denied without prompting the user.
1. If |implicitly granted| is true, [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p| with {{undefined}}, and return.
1. If |implicitly denied| is true, [=queue a global task=] on the [=permission task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}, and return.
1. Let |permissionState| be the result of [=requesting permission to use=] "<a permission><code>storage-access</code></a>".
1. If |permissionState| is "granted":
1. [=Queue a global task=] on the [=permission task source=] given |global| to:
1. Set |global|'s [=environment/has storage access=] to true.
1. [=/Resolve=] |p| with {{undefined}}.
1. Return.
1. [=Queue a global task=] on the [=permission task source=] given |global| to:
1. [=Consume user activation=] given |doc|'s {{Window}} object.
1. [=/Reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}.

<h3 id="navigation">Changes to navigation</h3>

When [=snapshotting source snapshot params=]:
Expand All @@ -247,7 +238,7 @@ When [=snapshotting source snapshot params=]:
When creating |request|'s [=reserved client=] in [=create navigation params by fetching=]:
1. Set [=reserved client=]'s [=environment/has storage access=] to |sourceSnapshotParams|'s [=source snapshot params/has storage access=] if:
1. |sourceSnapshotParams|'s [=source snapshot params/environment id=] equals <var ignore>navigable</var>'s [=active document=]'s [=relevant settings object=]'s [=environment/id=].
1. <var ignore>entry</var>'s URL is [=same origin=] with <var ignore>currentURL</var>.
1. <var ignore>entry</var>'s URL's [=url/origin=] is [=same origin=] with <var ignore>currentURL</var>'s [=url/origin=].
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. |response| is null or |response|'s [=response/has-cross-origin-redirects=] is false.
1. Otherwise, set |request|'s [=reserved client=]'s [=environment/has storage access=] to false.

Expand All @@ -265,9 +256,9 @@ This API only impacts HTTP cookies. A future revision of this API might impact o

<h4 id="cookies">Cookies</h4>

This API is intended to be used with environments and user agent configurations that block access to unpartitioned cookies in a [=third party context=]. At the time of this writing, this concept has not yet been integrated into the [=HTTP-network-or-cache fetch=] and {{Document/cookie}} algorithms. To allow for such an integration, the [=cookie store=] will need to be modified to receive information about the top-level and embedded site of the request (to determine whether to attach cross-site, partitioned, or no cookies) as well as whether the request was made for a document that has storage access, through running the [=determine if a site has storage access=] algorithm that is defined in this specification.
This API is intended to be used with environments and user agent configurations that block access to unpartitioned cookies in a [=third party context=]. At the time of this writing, this concept has not yet been integrated into the [=HTTP-network-or-cache fetch=] and {{Document/cookie}} algorithms. To allow for such an integration, the [=cookie store=] will need to be modified to receive information about the top-level and embedded site of the request (to determine whether to attach cross-site, partitioned, or no cookies) as well as whether the request was made for a document that has storage access, through accessing the [=environment=]'s [=environment/has storage access=] that is defined in this specification.

Once the cookie store allows for receiving information about storage access, we would update [=HTTP-network-or-cache fetch=] and {{Document/cookie}} to run [=determine if a site has storage access=] and pass this information to the [=cookie store=] when retrieving cookies.
Once the cookie store allows for receiving information about storage access, we would update [=HTTP-network-or-cache fetch=] and {{Document/cookie}} to pass the [=environment=]'s [=environment/has storage access=] to the [=cookie store=] when retrieving cookies.

When getting unpartitioned cookies from the [=cookie store=] with storage access, user agents will still follow applicable `SameSite` restrictions (i.e., not attach cookies marked `SameSite=Strict` or `SameSite=Lax` in [=third party contexts=]).

Expand Down