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 15 commits
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
129 changes: 62 additions & 67 deletions storage-access.bs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,19 @@ urlPrefix: https://w3c.github.io/webdriver/webdriver-spec.html#; spec: webdriver
text: unsupported operation; url: dfn-unsupported-operation
text: session; url: dfn-session
text: success; url: dfn-success

spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
type: dfn
text: source snapshot params; url: browsing-the-web.html#source-snapshot-params
text: snapshotting source snapshot params; url: browsing-the-web.html#snapshotting-source-snapshot-params
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

spec: fetch; urlPrefix: https://fetch.spec.whatwg.org/
type: dfn
for: response
text: has-cross-origin-redirects; url: #response-has-cross-origin-redirects
cfredric marked this conversation as resolved.
Show resolved Hide resolved
</pre>

<pre class=biblio>
Expand Down Expand Up @@ -112,23 +125,14 @@ A {{Document}} is in a <dfn>first-party-site context</dfn> if it is the [=active

A {{Document}} is in a <dfn>third party context</dfn> if it is not in a [=first-party-site context=].

<h3 id="ua-state">User Agent state related to storage access</h3>

A <dfn>storage access map</dfn> is a [=map=] whose keys are [=partitioned storage keys=] and whose values are [=storage access flag sets=].

User Agents maintain a single <dfn>global storage access map</dfn>.
<h3 id="ua-state">Changes to user agent state related to storage access</h3>

ISSUE(privacycg/storage-access#2): What is the lifecycle of the [=global storage access map=]? How long do we remember its contents? Firefox and Safari differ here.
Modify the definition of [=environment=] in the following manner:
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. Add a new member called <dfn for="environment">has storage access</dfn> of type [=boolean=].

ISSUE(privacycg/storage-access#5): When do we age out entries in the [=global storage access map=]? See also [Scope of Storage Access](https://github.com/privacycg/storage-access#scope-of-storage-access).

Each [=agent cluster=] has a <dfn for="agent cluster">storage access map</dfn>.

When an [=agent cluster=] is created, its [=agent cluster/storage access map=] is initialized with a [=map/clone=] of the [=global storage access map=].

To <dfn type="abstract-op">obtain the storage access map</dfn> for a {{Document}} |doc|, run the following steps:

1. Return the [=agent cluster/storage access map=] of |doc|'s [=relevant agent=]'s [=agent cluster=].
Modify the definition of [=source snapshot params=] in the following manner:
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. Add a new member called <dfn for="source snapshot params">has storage access</dfn> of type [=boolean=].
1. Add a new member called <dfn for="source snapshot params">environment id</dfn> of type opaque [=string=].
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should just be string or you should define what opaque means for the type.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I included "opaque" since this member will contain values from environment/id, which is defined as an opaque string.


A <dfn>partitioned storage key</dfn> is a [=tuple=] consisting of a <dfn for="partitioned storage key">top-level site</dfn> (a [=site=]) and an <dfn for="partitioned storage key">embedded origin</dfn> (an [=/origin=]).

Expand All @@ -146,18 +150,6 @@ To <dfn type="abstract-op">generate a partitioned storage key</dfn> for a {{Docu
1. Let |top-level site| be the result of [=obtain a site|obtaining a site=] from |settings|' [=top-level origin=].
1. Return the [=partitioned storage key=] (|top-level site|, |site|).

A <dfn>storage access flag set</dfn> is a set of zero or more of the following flags, which are used to gate access to client-side storage for |embedded origin| when loaded in a [=third party context=] on |top-level site|:

: The <dfn for="storage access flag set" id=has-storage-access-flag>has storage access flag</dfn>
:: When set, this flag indicates |embedded origin| has access to its [=unpartitioned data=] when it's loaded in a [=third party context=] on |top-level site|.

To <dfn type="abstract-op">obtain a storage access flag set</dfn> for a [=partitioned storage key=] |key| from a [=/storage access map=] |map|, run the following steps:

1. If |map|[|key|] [=map/exists|does not exist=], run these steps:
1. Let |flags| be a new [=storage access flag set=].
1. [=map/Set=] |map|[|key|] to |flags|.
1. Return |map|[|key|].

<h3 id="the-document-object">Changes to {{Document}}</h3>

<pre class="idl">
Expand All @@ -181,10 +173,7 @@ When invoked on {{Document}} |doc|, the <dfn export method for=Document><code>ha
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. Let |key| be the result of [=generate a partitioned storage key|generating a partitioned storage key=] from |doc|.
1. If |key| is failure, [=resolve=] |p| with false and return |p|.
1. Let |hasAccess| be the result of running [=determine if a site has storage access=] with |key| and |doc|.
1. [=Queue a global task=] on the [=permissions task source=] given |global| to [=/resolve=] |p| with |hasAccess|.
1. [=Resolve=] |p| with |global's| [=environment/has storage access=].
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. Return |p|.

ISSUE: Shouldn't step 8 be [=same site=]?
Expand All @@ -199,25 +188,14 @@ 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 this algorithm was invoked when |doc|'s {{Window}} object did not have [=transient activation=], [=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"` permission, [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} 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|.
cfredric marked this conversation as resolved.
Show resolved Hide resolved
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 [=active sandboxing flag set=] has its [=sandbox storage access by user activation flag=] set, [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|.
1. Let |key| be the result of [=generate a partitioned storage key|generating a partitioned storage key=] from |doc|.
1. If |key| is failure, [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|.
1. Let |map| be the result of [=obtain the storage access map|obtaining the storage access map=] for |doc|.
1. Let |flag set| be the result of [=obtain a storage access flag set|obtaining the storage access flag set=] with |key| from |map|.
1. If |flag set|'s [=has storage access flag=] is set, [=/resolve=] and return |p|.
1. Otherwise, run these steps [=in parallel=]:
1. Let |hasAccess| be [=a new promise=].
1. [=Determine the storage access policy=] with |key|, |doc| and |hasAccess|.
1. [=Queue a global task=] on the [=permissions task source=] given |global| to
1. Set |flag set|'s [=has storage access flag=].
1. If |hasAccess| is true, resolve |p|.
1. Reject |p| with a "{{NotAllowedError}}" {{DOMException}}.
1. Run the following steps in parallel:
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. [=Determine the storage access policy=] with |doc| and |p|.
cfredric marked this conversation as resolved.
Show resolved Hide resolved
1. Return |p|.

ISSUE(privacycg/storage-access#144): We shouldn't use the permissions task source here.
Expand All @@ -228,37 +206,54 @@ ISSUE: Shouldn't step 9 be [=same site=]?

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 [=partitioned storage key=] |key| and {{Document}} |doc|, run these steps:
To <dfn type="abstract-op">determine if a site has storage access</dfn> with {{Document}} |doc|, run these steps:

1. Let |map| be the result of [=obtain the storage access map|obtaining the storage access map=] for |doc|.
1. Let |flag set| be the result of [=obtain a storage access flag set|obtaining the storage access flag set=] with |key| from |map|.
1. If |flag set|'s [=has storage access flag=] is set, return true.
1. Return false.
1. Let |global| be |doc|'s [=relevant global object=].
1. Return |global|'s [=environment/has storage access=].
cfredric marked this conversation as resolved.
Show resolved Hide resolved

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

1. Let |map| be the result of [=obtain the storage access map|obtaining the storage access map=] for |doc|.
1. Let |flag set| be the result of [=obtain a storage access flag set|obtaining the storage access flag set=] with |key| from |map|.
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. Let |global| be |doc|'s [=relevant global object=].
1. If |implicitly granted| is true, [=queue a global task=] on the [=permissions task source=] given |global| to [=/resolve=] |p|, and return.
1. If |implicitly denied| is true, [=queue a global task=] on the [=permissions task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}, and return.
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|.
cfredric marked this conversation as resolved.
Show resolved Hide resolved
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.
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, [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p| with {{undefined}}, and return.
cfredric marked this conversation as resolved.
Show resolved Hide resolved
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", [=queue a global task=] on the [=permissions task source=] given |global| to [=/resolve=] |p|, and return.
1. Unset |flag set|'s [=has storage access flag=].
1. If |doc|'s {{Window}} object has [=transient activation=], [=consume user activation=] with it.
1. [=Queue a global task=] on the [=permissions task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}.
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>

Before changing the current entry of a session history, run the following steps:
When [=snapshotting source snapshot params=]:
1. Set [=source snapshot params/has storage access=] to |sourceDocument|'s [=source snapshot params/has storage access=].
1. Set [=source snapshot params/environment id=] to |sourceDocument|'s [=relevant settings object=]'s [=environment/id=].

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>.
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.

When [=set up a window environment settings object|setting up a window environment settings object=]:
1. Set <var ignore>settings object</var>'s [=environment/has storage access=] to <var ignore>reserved environment</var>'s [=environment/has storage access=].

1. Let |doc| be current entry's {{Document}}.
1. Let |map| be the result of [=obtain the storage access map|obtaining the storage access map=] for |doc|'s [=Document/browsing context=]'s [=top-level browsing context=].
1. Let |key| be the result of [=generate a partitioned storage key|generating a partitioned storage key=] from |doc|.
1. If |key| is failure, abort these steps.
1. Let |flag set| be the result of [=obtain a storage access flag set|obtaining the storage access flag set=] with |key| from |map|.
1. Unset |flag set|'s [=has storage access flag=].

ISSUE(privacycg/storage-access#3): What this section should look like ultimately hinges on

Expand Down