From 19043296e3286ba02c5a60aa7f723e6b48cf5c3e Mon Sep 17 00:00:00 2001 From: Johann Hofmann Date: Fri, 18 Nov 2022 13:48:58 +0000 Subject: [PATCH 01/17] Use the Permissions API --- storage-access.bs | 65 +++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index 62ce4a4..6c7928c 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -143,8 +143,6 @@ A storage access flag set is a set of zero or more of the following f : The has storage access flag :: 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|. -: The was expressly denied storage access flag -:: When set, this flag indicates that the user expressly denied |embedded origin| access to its [=unpartitioned data=] when it's loaded in a [=third party context=] on |top-level site|. To obtain a storage access flag set for a [=partitioned storage key=] |key| from a [=/storage access map=] |map|, run the following steps: @@ -153,10 +151,6 @@ To obtain a storage access flag set for a [=partit 1. [=map/Set=] |map|[|key|] to |flags|. 1. Return |map|[|key|]. -To save the storage access flag set for a [=partitioned storage key=] |key| in a [=/storage access map=] |map|, run the following steps: - -1. [=map/Set=] [=global storage access map=][|key|] to |map|[|key|]. -

Changes to {{Document}}

@@ -182,14 +176,7 @@ When invoked on {{Document}} |doc|, the ha
 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. Run these steps [=in parallel=]:
-    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 [=was expressly denied storage access flag=] is set, [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p| with false, and abort these steps.
-    1. If |flag set|'s [=has storage access flag=] is set, [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p| with true, and abort these steps.
-    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 [=permission task source=] given |global| to [=/resolve=] |p| with the result of |hasAccess|.
+1. [=Resolve=] or [=reject=] |p| based on the result of running [=determine if a site has storage access=] with |key| and |doc|.
 1. Return |p|.
 
 ISSUE: Shouldn't step 8 be [=same site=]?
@@ -215,7 +202,6 @@ When invoked on {{Document}} |doc|, the re
 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 [=was expressly denied storage access flag=] is set, [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|.
 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=].
@@ -223,7 +209,6 @@ When invoked on {{Document}} |doc|, the re
     1. [=Queue a global task=] on the [=permission task source=] given |global| to
         1. Set |flag set|'s [=has storage access flag=].
         1. Resolve or reject |p| based on the result of |hasAccess|.
-    1. [=Save the storage access flag set=] for |key| in |map|.
 1. Return |p|.
 
 ISSUE: Shouldn't step 9 be [=same site=]?
@@ -237,37 +222,22 @@ To determine if a site has storage access with [=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, return true.
-1. Let |has storage access| (a [=boolean=]) be the result of running an [=implementation-defined=] set of steps to determine if |key|'s [=partitioned storage key/embedded origin=] has access to its [=unpartitioned data=] on |key|'s [=partitioned storage key/top-level site=].
-1. If |has storage access| is true, set |flag set|'s [=has storage access flag=].
-1. [=Save the storage access flag set=] for |key| in |map|.
-1. Return |has storage access|.
+1. Return false.
 
 To determine the storage access policy for [=partitioned storage key=] |key| with {{Document}} |doc| and {{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.
-
-    Note: These [=implementation-defined=] set of steps might result in |flag set|'s [=has storage access flag=] and [=was expressly denied storage access flag=] changing, since the User Agent could have relevant out-of-band information (e.g. a user preference that changed) that this specification is unaware of.
 1. Let |global| be |doc|'s [=relevant global object=].
 1. If |implicitly granted| is true, [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p|, 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 |p|.
-1. Ask the user if they would like to grant |key|'s [=partitioned storage key/embedded origin=] access to its [=unpartitioned data=] when it's loaded in a [=third party context=] on |key|'s [=partitioned storage key/top-level site=], and wait for an answer. Let |expressly granted| and |expressly denied| (both [=booleans=]) be the result.
-
-    Note: While |expressly granted| and |expressly denied| cannot both be true, they could both be false in User Agents which allow users to dismiss the prompt without choosing to allow or deny the request. (Such a dismissal is interpreted in this algorithm as a denial.)
-1. If |expressly granted| is true, run these steps:
-    1. Unset |flag set|'s [=was expressly denied storage access flag=].
-    1. [=Save the storage access flag set=] for |key| in |map|.
-    1. [=Queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p|, and return.
+1. Let |permissionState| be the result of [=requesting permission to use=] "storage-access".
+1. If |permissionState| is "granted", [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p|, and return.
 1. Unset |flag set|'s [=has storage access flag=].
-1. If |expressly denied| is true, run these steps:
-    1. If |doc|'s {{Window}} object has [=transient activation=], [=consume user activation=] with it.
-    1. Set |flag set|'s [=was expressly denied storage access flag=].
-1. [=Save the storage access flag set=] for |key| in |map|.
+1. If |doc|'s {{Window}} object has [=transient activation=], [=consume user activation=] with it.
 1. [=Queue a global task=] on the [=permission task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}.
 
-ISSUE: [since this is UA-defined, does it make sense to follow-up separately with a user prompt?](https://github.com/privacycg/storage-access/pull/24#discussion_r408784492)
-
 
 
 Before changing the current entry of a session history, run the following steps:
@@ -278,7 +248,6 @@ Before changing the current entry of a session history, run the following steps:
 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=].
-1. [=Save the storage access flag set=] for |key| in |map|.
 
 ISSUE(privacycg/storage-access#3): What this section should look like ultimately hinges on
 
@@ -302,6 +271,30 @@ To the [=parse a sandboxing directive=] algorithm, add the following under step
 
  • The [=sandbox storage access by user activation flag=], unless tokens contains the allow-storage-access-by-user-activation keyword. +

    Permissions Integration

    + +The Storage Access API defines a [=powerful feature=] identified by the [=powerful feature/name=] `"storage-access"`. + +

    Changes to generate a permission store key

    + +Update the generate a permission store key algorithm to take the [=powerful feature/name=] |name|. Prepend the following steps to it: + +1. If |name| is "storage-access", run the following steps: + 1. Let |topLevelOrigin| be |settings|' [=environment/top-level origin]. + 1. Let |embeddedOrigin| be |settings|' [=environment/origin]. + 1. Return (|topLevelOrigin|, |embeddedOrigin|). + +

    Changes to compare permission store keys

    + +Update the compare permission store keys algorithm to take the [=powerful feature/name=] |name|. Prepend the following steps to it: + +1. If |name| is "storage-access", run the following steps: + 1. Let |topLevelSite1| be the result of [=obtaining a site=] from |key1|'s permission store key/top-level origin. + 1. Let |topLevelSite2| be the result of [=obtaining a site=] from |key2|'s permission store key/top-level origin. + 1. If |topLevelSite1| is not [=same site=] with |topLevelSite2|, return false. + 1. If |key1|'s permission store key/granted origin is not [=same origin=] with |key2|'s permission store key/granted origin, return false. + 1. Return true. +

    Permissions Policy Integration

    The Storage Access API defines a [=policy-controlled feature=] identified by the string `"storage-access"`. Its [=default allowlist=] is `"*"`. From 651be054d2fabc54973f09fae7c05ee2d371c41c Mon Sep 17 00:00:00 2001 From: Johann Hofmann Date: Tue, 22 Nov 2022 10:47:48 +0000 Subject: [PATCH 02/17] Better permissions reference, fix other references --- storage-access.bs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index 6c7928c..a1dc461 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -273,22 +273,22 @@ To the [=parse a sandboxing directive=] algorithm, add the following under step

    Permissions Integration

    -The Storage Access API defines a [=powerful feature=] identified by the [=powerful feature/name=] `"storage-access"`. +The Storage Access API defines a [=powerful feature=] identified by the [=powerful feature/name=] "storage-access".

    Changes to generate a permission store key

    Update the generate a permission store key algorithm to take the [=powerful feature/name=] |name|. Prepend the following steps to it: -1. If |name| is "storage-access", run the following steps: - 1. Let |topLevelOrigin| be |settings|' [=environment/top-level origin]. - 1. Let |embeddedOrigin| be |settings|' [=environment/origin]. +1. If |name| is "storage-access", run the following steps: + 1. Let |topLevelOrigin| be |settings|' [=top-level origin=]. + 1. Let |embeddedOrigin| be |settings|' [=environment settings object/origin=]. 1. Return (|topLevelOrigin|, |embeddedOrigin|).

    Changes to compare permission store keys

    Update the compare permission store keys algorithm to take the [=powerful feature/name=] |name|. Prepend the following steps to it: -1. If |name| is "storage-access", run the following steps: +1. If |name| is "storage-access", run the following steps: 1. Let |topLevelSite1| be the result of [=obtaining a site=] from |key1|'s permission store key/top-level origin. 1. Let |topLevelSite2| be the result of [=obtaining a site=] from |key2|'s permission store key/top-level origin. 1. If |topLevelSite1| is not [=same site=] with |topLevelSite2|, return false. From 4af7cf791d10804e2c0822dcfb3a4dced1fd6a5c Mon Sep 17 00:00:00 2001 From: Johann Hofmann Date: Tue, 22 Nov 2022 10:49:33 +0000 Subject: [PATCH 03/17] Forgot another reference --- storage-access.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage-access.bs b/storage-access.bs index a1dc461..a7c438d 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -232,7 +232,7 @@ To determine the storage access policy for [=parti 1. Let |global| be |doc|'s [=relevant global object=]. 1. If |implicitly granted| is true, [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p|, 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 |p|. -1. Let |permissionState| be the result of [=requesting permission to use=] "storage-access". +1. Let |permissionState| be the result of [=requesting permission to use=] "storage-access". 1. If |permissionState| is "granted", [=queue a global task=] on the [=permission 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. From 3a8677843cf80e7b0f8fc81223fb76787a67e266 Mon Sep 17 00:00:00 2001 From: Johann Hofmann Date: Wed, 23 Nov 2022 13:26:44 +0000 Subject: [PATCH 04/17] Define as algorithms on the feature instead --- storage-access.bs | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index a7c438d..7dc1eb6 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -273,27 +273,35 @@ To the [=parse a sandboxing directive=] algorithm, add the following under step

    Permissions Integration

    -The Storage Access API defines a [=powerful feature=] identified by the [=powerful feature/name=] "storage-access". +The Storage Access API defines a [=powerful feature=] identified by the [=powerful feature/name=] "storage-access". It defines the following permission-related algorithms: -

    Changes to generate a permission store key

    +
    +
    [=powerful feature/permission query algorithm=]
    +
    + To query the "storage-access" permission, given a {{PermissionDescriptor}} |permissionDesc| and a {{PermissionStatus}} |status|, run the following steps: -Update the generate a permission store key algorithm to take the [=powerful feature/name=] |name|. Prepend the following steps to it: + 1. Set |status|'s {{PermissionStatus/state}} to |permissionDesc|'s [=permission state=]. + 1. If |status|'s {{PermissionStatus/state}} is [=permission/denied=], set |status|'s {{PermissionStatus/state}} to [=permission/prompt=]. -1. If |name| is "storage-access", run the following steps: - 1. Let |topLevelOrigin| be |settings|' [=top-level origin=]. - 1. Let |embeddedOrigin| be |settings|' [=environment settings object/origin=]. - 1. Return (|topLevelOrigin|, |embeddedOrigin|). - -

    Changes to compare permission store keys

    + Note: The "denied" permission state is not revealed to avoid exposing the user's decision to developers. This is done to prevent retaliation against the user and repeated prompting to the detriment of the user experience. +
    +
    [=powerful feature/permission key generation algorithm]
    +
    + To generate a new [=permission store key] for the "storage-access" feature, given an [=environment settings object=] |settings|, run the following steps: -Update the compare permission store keys algorithm to take the [=powerful feature/name=] |name|. Prepend the following steps to it: - -1. If |name| is "storage-access", run the following steps: - 1. Let |topLevelSite1| be the result of [=obtaining a site=] from |key1|'s permission store key/top-level origin. - 1. Let |topLevelSite2| be the result of [=obtaining a site=] from |key2|'s permission store key/top-level origin. - 1. If |topLevelSite1| is not [=same site=] with |topLevelSite2|, return false. - 1. If |key1|'s permission store key/granted origin is not [=same origin=] with |key2|'s permission store key/granted origin, return false. + 1. Let |topLevelSite| be |settings|' [=top-level site=]. + 1. Let |embeddedOrigin| be |settings|' [=environment settings object/origin=]. + 1. Return (|topLevelSite|, |embeddedOrigin|). +
    +
    [=powerful feature/permission key comparison algorithm]
    +
    + To compare the [=permission keys] |key1| and |key2| for the "storage-access" feature, run the following steps: + + 1. If |key1|[0] is not [=same site=] with |key2|[0], return false. + 1. If |key1|[1] is not [=same origin=] with |key2|[1], return false. 1. Return true. +
    +

    Permissions Policy Integration

    From 0128bcaf7a5ddfe71e665018b4772f9ac4a31dd4 Mon Sep 17 00:00:00 2001 From: Johann Hofmann Date: Fri, 2 Dec 2022 19:43:02 +0000 Subject: [PATCH 05/17] Add permission key type --- storage-access.bs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/storage-access.bs b/storage-access.bs index 7dc1eb6..d270499 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -285,9 +285,13 @@ The Storage Access API defines a [=powerful feature=] identified by the [=powerf Note: The "denied" permission state is not revealed to avoid exposing the user's decision to developers. This is done to prevent retaliation against the user and repeated prompting to the detriment of the user experience. +
    [=powerful feature/permission key type]
    +
    + A [=permission key] of the "storage-access" feature has the type ([=site=], [=/origin=]). +
    [=powerful feature/permission key generation algorithm]
    - To generate a new [=permission store key] for the "storage-access" feature, given an [=environment settings object=] |settings|, run the following steps: + To generate a new [=permission key] for the "storage-access" feature, given an [=environment settings object=] |settings|, run the following steps: 1. Let |topLevelSite| be |settings|' [=top-level site=]. 1. Let |embeddedOrigin| be |settings|' [=environment settings object/origin=]. From bfb3ddead913946e2ddaaaa33ec6fa022042aefd Mon Sep 17 00:00:00 2001 From: cfredric Date: Thu, 1 Dec 2022 18:13:02 -0500 Subject: [PATCH 06/17] Modify Storage Access to use a per-frame model. This is an attempt to address https://github.com/privacycg/storage-access/issues/122. --- storage-access.bs | 105 +++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 57 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index d270499..494436a 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -44,6 +44,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
  • @@ -105,23 +118,14 @@ A {{Document}} is in a first-party-site context if it is the [=active
     
     A {{Document}} is in a third party context if it is not in a [=first-party-site context=].
     
    -

    User Agent state related to storage access

    - -A storage access map is a [=map=] whose keys are [=partitioned storage keys=] and whose values are [=storage access flag sets=]. - -User Agents maintain a single global storage access map. +

    Changes to User Agent state related to storage access

    -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: +1. Add a new member called obtained storage access flag 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 storage access map. - -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 obtain the storage access map 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: +1. Add a new member called obtained storage access flag of type boolean. +1. Add a new member called environment id of type opaque string. A partitioned storage key is a [=tuple=] consisting of a top-level site (a [=site=]) and an embedded origin (an [=/origin=]). @@ -139,18 +143,6 @@ To generate a partitioned storage key 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 storage access flag set 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 has storage access flag -:: 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 obtain a storage access flag set 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|]. -

    Changes to {{Document}}

    @@ -174,9 +166,7 @@ When invoked on {{Document}} |doc|, the 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|. 
     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. [=Resolve=] or [=reject=] |p| based on the result of running [=determine if a site has storage access=] with |key| and |doc|.
    +1. [=Resolve=] or [=reject=] |p| based on |global|'s [=environment/obtained storage access flag=].
     1. Return |p|.
     
     ISSUE: Shouldn't step 8 be [=same site=]?
    @@ -198,56 +188,57 @@ When invoked on {{Document}} |doc|, the re
     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|. 
     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. If |global|'s [=environment/obtained storage access flag=] is true, [=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 [=permission task source=] given |global| to
    -        1. Set |flag set|'s [=has storage access flag=].
    -        1. Resolve or reject |p| based on the result of |hasAccess|.
    +    1. [=Determine the storage access policy=] with |doc| and |hasAccess|.
    +    1. [=Queue a global task=] on the [=permission task source=] given |global| to resolve or reject |p| based on the result of |hasAccess|.
     1. Return |p|.
     
    -ISSUE: Shouldn't step 9 be [=same site=]?
    +ISSUE: Shouldn't step 10 be [=same site=]?
     
     

    User Agent storage access policies

    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 determine if a site has storage access with [=partitioned storage key=] |key| and {{Document}} |doc|, run these steps: +To determine if a site has storage access 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/obtained storage access flag=]. -To determine the storage access policy for [=partitioned storage key=] |key| with {{Document}} |doc| and {{Promise}} |p|, run these steps: +To determine the storage access policy 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 |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. Let |global| be |doc|'s [=relevant global object=]. 1. If |implicitly granted| is true, [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p|, 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 |p|. 1. Let |permissionState| be the result of [=requesting permission to use=] "storage-access". -1. If |permissionState| is "granted", [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p|, and return. -1. Unset |flag set|'s [=has storage access flag=]. +1. If |permissionState| is "granted": + 1. [=Queue a global task=] on the [=permission task source=] given |global| to: + 1. Set |global|'s [=environment/obtained storage access flag=] to true. + 1. [=/Resolve=] |p|. + 1. Return. +1. Set |global|'s [=environment/obtained storage access flag=] to false. 1. If |doc|'s {{Window}} object has [=transient activation=], [=consume user activation=] with it. 1. [=Queue a global task=] on the [=permission task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. -Before changing the current entry of a session history, run the following steps: +When [=snapshotting source snapshot params=]: +1. Set [=source snapshot params/obtained storage access flag=] to |sourceDocument|'s [=source snapshot params/obtained storage access flag=]. +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 the [=reserved client=]'s [=environment/obtained storage access flag=] to be |sourceSnapshotParams|'s [=source snapshot params/obtained storage access flag=] if: + 1. |sourceSnapshotParams|'s [=source snapshot params/environment id=] equals navigable's [=active document=]'s [=relevant settings object=]'s [=environment/id=]. + 1. entry's URL is [=same origin=] with currentURL. + 1. |response| is null or |response|'s [=response/has-cross-origin-redirects=] is false. +1. Otherwise, set |request|'s [=reserved client=]'s [=environment/obtained storage access flag=] to false. + +When [=set up a window environment settings object|setting up a window environment settings object=]: +1. Set settings object's [=environment/obtained storage access flag=] to reserved environment's [=environment/obtained storage access flag=]. -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 From fd4c94ea204bcd95082ae971230953175533f23e Mon Sep 17 00:00:00 2001 From: cfredric Date: Mon, 5 Dec 2022 12:23:21 -0500 Subject: [PATCH 07/17] Move user activation check and consumption. --- storage-access.bs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index 494436a..a233d18 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -181,7 +181,6 @@ When invoked on {{Document}} |doc|, the 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|'s [=Document/origin=] is an [=opaque origin=], [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return |p|. @@ -208,6 +207,12 @@ To determine if a site has storage access with {{D To determine the storage access policy for {{Document}} |doc| with {{Promise}} |p|, run these steps: +1. Let |previousPermissionState| be the result of [=getting the current permission state=] given "storage-access" and |global|. +1. If |previousPermissionState| is not [=permission/prompt=]: + 1. Set |global|'s [=environment/obtained storage access flag=] based on whether |previousPermissionState| is [=permission/granted=] or [=permission/denied=]. + 1. [=/Resolve=] or [=/reject=] |p| (with a "{{NotAllowedError}}" {{DOMException}}) based on whether |previousPermissionState| is [=permission/granted=] or [=permission/denied=]. + 1. Return. +1. If |doc|'s {{Window}} object does not have [=transient activation=], [=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. 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=]. @@ -220,7 +225,7 @@ To determine the storage access policy for {{Docum 1. [=/Resolve=] |p|. 1. Return. 1. Set |global|'s [=environment/obtained storage access flag=] to false. -1. If |doc|'s {{Window}} object has [=transient activation=], [=consume user activation=] with it. +1. [=Consume user activation=] given |doc|'s {{Window}} object. 1. [=Queue a global task=] on the [=permission task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. From edd52484b6e54443ef323ed177b4ab6a60b0aa64 Mon Sep 17 00:00:00 2001 From: cfredric Date: Mon, 5 Dec 2022 13:35:56 -0500 Subject: [PATCH 08/17] Fix issue numbering. --- storage-access.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage-access.bs b/storage-access.bs index a233d18..50054ef 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -194,7 +194,7 @@ When invoked on {{Document}} |doc|, the re 1. [=Queue a global task=] on the [=permission task source=] given |global| to resolve or reject |p| based on the result of |hasAccess|. 1. Return |p|. -ISSUE: Shouldn't step 10 be [=same site=]? +ISSUE: Shouldn't step 9 be [=same site=]?

    User Agent storage access policies

    From 22cd19b948fef9b1b8d882c3ee0a86bf2251f351 Mon Sep 17 00:00:00 2001 From: cfredric Date: Mon, 12 Dec 2022 10:34:05 -0500 Subject: [PATCH 09/17] Incorporate review feedback. --- storage-access.bs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index 50054ef..3d8937b 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -121,11 +121,11 @@ A {{Document}} is in a third party context if it is not in a [=first-

    Changes to User Agent state related to storage access

    Modify the definition of [=environment=] in the following manner: -1. Add a new member called obtained storage access flag of type boolean. +1. Add a new member called has storage access flag of type [=boolean=]. Modify the definition of [=source snapshot params=] in the following manner: -1. Add a new member called obtained storage access flag of type boolean. -1. Add a new member called environment id of type opaque string. +1. Add a new member called has storage access flag of type [=boolean=]. +1. Add a new member called environment id of type opaque [=string=]. A partitioned storage key is a [=tuple=] consisting of a top-level site (a [=site=]) and an embedded origin (an [=/origin=]). @@ -166,7 +166,7 @@ When invoked on {{Document}} |doc|, the 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|. 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=] or [=reject=] |p| based on |global|'s [=environment/obtained storage access flag=]. +1. [=Resolve=] or [=reject=] |p| based on |global|'s [=environment/has storage access flag=]. 1. Return |p|. ISSUE: Shouldn't step 8 be [=same site=]? @@ -187,7 +187,7 @@ When invoked on {{Document}} |doc|, the re 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|. 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. If |global|'s [=environment/obtained storage access flag=] is true, [=resolve=] and return |p|. +1. If |global|'s [=environment/has storage access flag=] is true, [=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 |doc| and |hasAccess|. @@ -203,14 +203,18 @@ Different User Agents have different policies around whether or not [=sites=] ma To determine if a site has storage access with {{Document}} |doc|, run these steps: 1. Let |global| be |doc|'s [=relevant global object=]. -1. Return |global|'s [=environment/obtained storage access flag=]. +1. Return |global|'s [=environment/has storage access flag=]. To determine the storage access policy for {{Document}} |doc| with {{Promise}} |p|, run these steps: 1. Let |previousPermissionState| be the result of [=getting the current permission state=] given "storage-access" and |global|. 1. If |previousPermissionState| is not [=permission/prompt=]: - 1. Set |global|'s [=environment/obtained storage access flag=] based on whether |previousPermissionState| is [=permission/granted=] or [=permission/denied=]. - 1. [=/Resolve=] or [=/reject=] |p| (with a "{{NotAllowedError}}" {{DOMException}}) based on whether |previousPermissionState| is [=permission/granted=] or [=permission/denied=]. + 1. If |previousPermissionState| is [=permission/granted=]: + 1. Set |global|'s [=environment/has storage access flag=] to true. Set |global|'s [=environment/has storage access flag=] to false. + 1. [=/Resolve=] |p|. + 1. Return. + 1. Set |global|'s [=environment/has storage access flag=] to false. + 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 |p|. 1. Let |key| be the result of [=generate a partitioned storage key|generating a partitioned storage key=] from |doc|. @@ -221,28 +225,28 @@ To determine the storage access policy for {{Docum 1. Let |permissionState| be the result of [=requesting permission to use=] "storage-access". 1. If |permissionState| is "granted": 1. [=Queue a global task=] on the [=permission task source=] given |global| to: - 1. Set |global|'s [=environment/obtained storage access flag=] to true. + 1. Set |global|'s [=environment/has storage access flag=] to true. 1. [=/Resolve=] |p|. 1. Return. -1. Set |global|'s [=environment/obtained storage access flag=] to false. +1. Set |global|'s [=environment/has storage access flag=] to false. 1. [=Consume user activation=] given |doc|'s {{Window}} object. 1. [=Queue a global task=] on the [=permission task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. When [=snapshotting source snapshot params=]: -1. Set [=source snapshot params/obtained storage access flag=] to |sourceDocument|'s [=source snapshot params/obtained storage access flag=]. +1. Set [=source snapshot params/has storage access flag=] to |sourceDocument|'s [=source snapshot params/has storage access flag=]. 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 the [=reserved client=]'s [=environment/obtained storage access flag=] to be |sourceSnapshotParams|'s [=source snapshot params/obtained storage access flag=] if: +1. Set the [=reserved client=]'s [=environment/has storage access flag=] to be |sourceSnapshotParams|'s [=source snapshot params/has storage access flag=] if: 1. |sourceSnapshotParams|'s [=source snapshot params/environment id=] equals navigable's [=active document=]'s [=relevant settings object=]'s [=environment/id=]. 1. entry's URL is [=same origin=] with currentURL. 1. |response| is null or |response|'s [=response/has-cross-origin-redirects=] is false. -1. Otherwise, set |request|'s [=reserved client=]'s [=environment/obtained storage access flag=] to false. +1. Otherwise, set |request|'s [=reserved client=]'s [=environment/has storage access flag=] to false. When [=set up a window environment settings object|setting up a window environment settings object=]: -1. Set settings object's [=environment/obtained storage access flag=] to reserved environment's [=environment/obtained storage access flag=]. +1. Set settings object's [=environment/has storage access flag=] to reserved environment's [=environment/has storage access flag=]. ISSUE(privacycg/storage-access#3): What this section should look like ultimately hinges on From 065eb8cfd54bc6f62e5e4f558f7b98fe1f75b1e6 Mon Sep 17 00:00:00 2001 From: cfredric Date: Wed, 14 Dec 2022 11:31:56 -0500 Subject: [PATCH 10/17] Address review comments. --- storage-access.bs | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index 3d8937b..df6ccd1 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -118,13 +118,13 @@ A {{Document}} is in a first-party-site context if it is the [=active A {{Document}} is in a third party context if it is not in a [=first-party-site context=]. -

    Changes to User Agent state related to storage access

    +

    Changes to user agent state related to storage access

    Modify the definition of [=environment=] in the following manner: -1. Add a new member called has storage access flag of type [=boolean=]. +1. Add a new member called has storage access of type [=boolean=]. Modify the definition of [=source snapshot params=] in the following manner: -1. Add a new member called has storage access flag of type [=boolean=]. +1. Add a new member called has storage access of type [=boolean=]. 1. Add a new member called environment id of type opaque [=string=]. A partitioned storage key is a [=tuple=] consisting of a top-level site (a [=site=]) and an embedded origin (an [=/origin=]). @@ -166,7 +166,7 @@ When invoked on {{Document}} |doc|, the 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|. 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=] or [=reject=] |p| based on |global|'s [=environment/has storage access flag=]. +1. [=Resolve=] |p| with |global's| [=environment/has storage access=]. 1. Return |p|. ISSUE: Shouldn't step 8 be [=same site=]? @@ -187,11 +187,8 @@ When invoked on {{Document}} |doc|, the re 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|. 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. If |global|'s [=environment/has storage access flag=] is true, [=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 |doc| and |hasAccess|. - 1. [=Queue a global task=] on the [=permission task source=] given |global| to resolve or reject |p| based on the result of |hasAccess|. +1. If |global|'s [=environment/has storage access=] is true, [=resolve=] and return |p|. +1. [=Determine the storage access policy=] with |doc| and |p|. 1. Return |p|. ISSUE: Shouldn't step 9 be [=same site=]? @@ -203,17 +200,17 @@ Different User Agents have different policies around whether or not [=sites=] ma To determine if a site has storage access with {{Document}} |doc|, run these steps: 1. Let |global| be |doc|'s [=relevant global object=]. -1. Return |global|'s [=environment/has storage access flag=]. +1. Return |global|'s [=environment/has storage access=]. To determine the storage access policy for {{Document}} |doc| with {{Promise}} |p|, run these steps: 1. Let |previousPermissionState| be the result of [=getting the current permission state=] given "storage-access" and |global|. 1. If |previousPermissionState| is not [=permission/prompt=]: 1. If |previousPermissionState| is [=permission/granted=]: - 1. Set |global|'s [=environment/has storage access flag=] to true. Set |global|'s [=environment/has storage access flag=] to false. + 1. Set |global|'s [=environment/has storage access=] to true. Set |global|'s [=environment/has storage access=] to false. 1. [=/Resolve=] |p|. 1. Return. - 1. Set |global|'s [=environment/has storage access flag=] to false. + 1. Set |global|'s [=environment/has storage access=] to false. 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 |p|. @@ -225,28 +222,28 @@ To determine the storage access policy for {{Docum 1. Let |permissionState| be the result of [=requesting permission to use=] "storage-access". 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 flag=] to true. + 1. Set |global|'s [=environment/has storage access=] to true. 1. [=/Resolve=] |p|. 1. Return. -1. Set |global|'s [=environment/has storage access flag=] to false. +1. Set |global|'s [=environment/has storage access=] to false. 1. [=Consume user activation=] given |doc|'s {{Window}} object. 1. [=Queue a global task=] on the [=permission task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. When [=snapshotting source snapshot params=]: -1. Set [=source snapshot params/has storage access flag=] to |sourceDocument|'s [=source snapshot params/has storage access flag=]. +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 the [=reserved client=]'s [=environment/has storage access flag=] to be |sourceSnapshotParams|'s [=source snapshot params/has storage access flag=] if: +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 navigable's [=active document=]'s [=relevant settings object=]'s [=environment/id=]. 1. entry's URL is [=same origin=] with currentURL. 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 flag=] to 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 settings object's [=environment/has storage access flag=] to reserved environment's [=environment/has storage access flag=]. +1. Set settings object's [=environment/has storage access=] to reserved environment's [=environment/has storage access=]. ISSUE(privacycg/storage-access#3): What this section should look like ultimately hinges on From 1c1a4c03f8d7bea366a8dde03dd33f2103ce7f52 Mon Sep 17 00:00:00 2001 From: cfredric Date: Thu, 15 Dec 2022 12:49:43 -0500 Subject: [PATCH 11/17] Refer to `storage-access` feature. --- storage-access.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage-access.bs b/storage-access.bs index df6ccd1..267ce1b 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -182,7 +182,7 @@ When invoked on {{Document}} |doc|, the re 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"` 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|. 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|. 1. If |doc|'s [=Document/origin=] is [=same origin=] with the [=top-level origin=] of |doc|'s [=relevant settings object=], [=/resolve=] and return |p|. From eabde3b4ffadad995532a4389e4f10352f1b284d Mon Sep 17 00:00:00 2001 From: cfredric Date: Thu, 15 Dec 2022 16:08:22 -0500 Subject: [PATCH 12/17] Fix up `determine storage access policy`. --- storage-access.bs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index 267ce1b..ff4b9e6 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -187,7 +187,6 @@ When invoked on {{Document}} |doc|, the re 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|. 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. If |global|'s [=environment/has storage access=] is true, [=resolve=] and return |p|. 1. [=Determine the storage access policy=] with |doc| and |p|. 1. Return |p|. @@ -204,28 +203,27 @@ To determine if a site has storage access with {{D To determine the storage access policy 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 "storage-access" 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. Set |global|'s [=environment/has storage access=] to false. - 1. [=/Resolve=] |p|. + 1. Set |global|'s [=environment/has storage access=] to true. + 1. [=/Resolve=] |p| with {{undefined}}. 1. Return. - 1. Set |global|'s [=environment/has storage access=] to false. 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 |p|. +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. Let |global| be |doc|'s [=relevant global object=]. -1. If |implicitly granted| is true, [=queue a global task=] on the [=permission task source=] given |global| to [=/resolve=] |p|, 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 |p|. +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=] "storage-access". 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|. + 1. [=/Resolve=] |p| with {{undefined}}. 1. Return. -1. Set |global|'s [=environment/has storage access=] to false. 1. [=Consume user activation=] given |doc|'s {{Window}} object. 1. [=Queue a global task=] on the [=permission task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. From 61f152b9e3d436fd6ac78e521896878a8e7b6a1a Mon Sep 17 00:00:00 2001 From: cfredric Date: Wed, 4 Jan 2023 09:10:44 -0500 Subject: [PATCH 13/17] Restore missing "in parallel" clause. --- storage-access.bs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage-access.bs b/storage-access.bs index ff4b9e6..410a50a 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -187,7 +187,8 @@ When invoked on {{Document}} |doc|, the re 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|. 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. [=Determine the storage access policy=] with |doc| and |p|. +1. Run the following steps in parallel: + 1. [=Determine the storage access policy=] with |doc| and |p|. 1. Return |p|. ISSUE: Shouldn't step 9 be [=same site=]? From a1bc9adb464d2b4e5edbda09eceed94a0b68505e Mon Sep 17 00:00:00 2001 From: cfredric Date: Thu, 5 Jan 2023 10:00:46 -0500 Subject: [PATCH 14/17] Consumer user gesture within a global task --- storage-access.bs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index cd5192e..833944d 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -234,8 +234,9 @@ To determine the storage access policy for {{Docum 1. Set |global|'s [=environment/has storage access=] to true. 1. [=/Resolve=] |p| with {{undefined}}. 1. Return. -1. [=Consume user activation=] given |doc|'s {{Window}} object. -1. [=Queue a global task=] on the [=permission task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. +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}}. From e078ef9f53d4d66b8f84e8a483013ccc66847358 Mon Sep 17 00:00:00 2001 From: cfredric Date: Thu, 12 Jan 2023 16:16:55 -0500 Subject: [PATCH 15/17] Address review feedback --- storage-access.bs | 89 +++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 49 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index 833944d..6dabe1f 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -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 @@ -167,13 +168,13 @@ When invoked on {{Document}} |doc|, the 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|. 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|. -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|. +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=]? @@ -188,56 +189,46 @@ When invoked on {{Document}} |doc|, the 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|. -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|. + 1. [=Reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. + 1. Let |previous permission state| be the result of [=getting the current permission state=] given "storage-access" and |global|. + 1. If |previous permission state| is not [=permission/prompt=]: + 1. Run |process permission state| with |previous permission state|. + 1. Return. + 1. If |has transient activation| is false, [=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: + 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=] "storage-access". + 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. + ISSUE(privacycg/storage-access#144): We shouldn't use the permissions task source here. ISSUE: Shouldn't step 9 be [=same site=]? -

    User Agent storage access policies

    - -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 determine if a site has storage access with {{Document}} |doc|, run these steps: - -1. Let |global| be |doc|'s [=relevant global object=]. -1. Return |global|'s [=environment/has storage access=]. - -To determine the storage access policy 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 "storage-access" 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=] "storage-access". -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}}. - When [=snapshotting source snapshot params=]: @@ -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 navigable's [=active document=]'s [=relevant settings object=]'s [=environment/id=]. - 1. entry's URL is [=same origin=] with currentURL. + 1. entry's URL's [=url/origin=] is [=same origin=] with currentURL's [=url/origin=]. 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. @@ -265,9 +256,9 @@ This API only impacts HTTP cookies. A future revision of this API might impact o

    Cookies

    -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=]). From 75eb6e9c241a00da2e44aa10a8661120b4f57136 Mon Sep 17 00:00:00 2001 From: cfredric Date: Fri, 13 Jan 2023 12:31:06 -0500 Subject: [PATCH 16/17] Restore slashes; save top-level URL; don't reject in parallel --- storage-access.bs | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index 6dabe1f..0c9c97c 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -167,14 +167,14 @@ When invoked on {{Document}} |doc|, the 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| 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. 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|. -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. 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|. +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=]? @@ -186,31 +186,33 @@ When invoked on {{Document}} |doc|, the re 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| 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=] "`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|. -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. If |global|'s [=environment/has storage access=] is true, [=resolve=] |p| with {{undefined}} and return. +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=] "`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|. +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. 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. [=/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|. - 1. [=Reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. + 1. [=/Reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. 1. Let |previous permission state| be the result of [=getting the current permission state=] given "storage-access" and |global|. 1. If |previous permission state| is not [=permission/prompt=]: 1. Run |process permission state| with |previous permission state|. 1. Return. - 1. If |has transient activation| is false, [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}} and return. + 1. If |has transient activation| is false: + 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. + 1. 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: @@ -235,10 +237,13 @@ 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=]. +To the [=create navigation params by fetching=] algorithm, insert the following step as step 3: +1. Let |originalURL| be entry's URL. + 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. Set [=reserved client=]'s [=environment/has storage access=] to |sourceSnapshotParams|'s [=source snapshot params/has storage access=] if all of the following hold: 1. |sourceSnapshotParams|'s [=source snapshot params/environment id=] equals navigable's [=active document=]'s [=relevant settings object=]'s [=environment/id=]. - 1. entry's URL's [=url/origin=] is [=same origin=] with currentURL's [=url/origin=]. + 1. |originalURL|'s [=url/origin=] is [=same origin=] with currentURL's [=url/origin=]. 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. From f1ad74acd879e1ec261e3dc07f339d64a8dc1cc3 Mon Sep 17 00:00:00 2001 From: cfredric Date: Mon, 16 Jan 2023 21:02:17 -0500 Subject: [PATCH 17/17] Reuse lambda; s/return/abort.../; remove queued task --- storage-access.bs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/storage-access.bs b/storage-access.bs index 0c9c97c..ae06f08 100644 --- a/storage-access.bs +++ b/storage-access.bs @@ -204,23 +204,23 @@ When invoked on {{Document}} |doc|, the re 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|. + 1. [=Consume user activation=] given |global|. 1. [=/Reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. 1. Let |previous permission state| be the result of [=getting the current permission state=] given "storage-access" and |global|. 1. If |previous permission state| is not [=permission/prompt=]: 1. Run |process permission state| with |previous permission state|. - 1. Return. + 1. Abort these steps. 1. If |has transient activation| is false: - 1. [=Queue a global task=] on the [=DOM manipulation task source=] given |global| to [=/reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. - 1. Return. + 1. Run |process permission state| with [=permission/denied=]. + 1. Abort these steps. 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. Abort these steps. 1. If |implicitly denied| is true: 1. Run |process permission state| with [=permission/denied=]. - 1. Return. + 1. Abort these steps. 1. Let |permissionState| be the result of [=requesting permission to use=] "storage-access". 1. Run |process permission state| with |permissionState|. 1. Return |p|.