diff --git a/index.bs b/index.bs index 05877bc2..745a4a3c 100644 --- a/index.bs +++ b/index.bs @@ -229,19 +229,36 @@ spec: RFC8941; urlPrefix: https://datatracker.ietf.org/doc/html/rfc8941#

Policies

-

A permissions policy is a [=struct=] with the following items:

+

A declared policy is a [=struct=] with the following + [=struct/items=]:

+ +
+ : declarations + :: an [=ordered map=] from [=features=] to [=allowlists=] + + : reporting configuration + :: an [=ordered map=] from [=features=] to [=strings=] + +
+ +

A permissions policy is a [=struct=] with the following + [=struct/items=]:

: inherited policy :: an [=ordered map=] from [=features=] to "`Enabled`" or "`Disabled`" : declared policy - :: an [=ordered map=] from [=features=] to [=allowlists=] + :: a [=/declared policy=] +
+

An empty permissions policy is a permissions policy that has an inherited policy which - contains "Enabled" for every supported feature, and a declared policy which is an empty map.

+ contains "Enabled" for every supported feature, a declared policy whose [=declared + policy/declarations=] and [=declared policy/reporting configuration=] are + both empty [=ordered maps=].

Inherited policies

@@ -292,7 +309,7 @@ spec: RFC8941; urlPrefix: https://datatracker.ietf.org/doc/html/rfc8941#

Policy directives

A policy directive is an [=ordered map=], mapping policy-controlled - features to corresponding allowlists of origins.

+ features to corresponding [=allowlists=] of origins.

A policy directive is represented in HTTP headers as the serialization of an sf-dictionary structure, and in and HTML attributes as its ASCII serialization.

@@ -409,8 +426,9 @@ spec: RFC8941; urlPrefix: https://datatracker.ietf.org/doc/html/rfc8941# Dictionary. Each Dictionary Member associates a feature with an allowlist. - The Member Names must be Tokens. If a token does not name a supported - feature, then the Dictionary Member will be ignored by the processing steps. + The Member Names must be Tokens. If a token does not name one of the user + agent's [=supported features=], then the Dictionary Member will be ignored + by the processing steps. The Member Values represent allowlists, and must be one of: * a String containing the ASCII permissions-source-expression @@ -418,6 +436,9 @@ spec: RFC8941; urlPrefix: https://datatracker.ietf.org/doc/html/rfc8941# * the Token `self` * an Inner List containing zero or more of the above items. + Member Values may have a Parameter named `"report-to"`, whose value must be + a String. Any other parameters will be ignored. + Any other items inside of an Inner List will be ignored by the processing steps, and the Member Value will be processed as if they were not present. Member Values of any other form will cause the entire Dictionary Member to @@ -427,15 +448,15 @@ spec: RFC8941; urlPrefix: https://datatracker.ietf.org/doc/html/rfc8941#

Delivery

-

Permissions-Policy HTTP Header - Field

-

The `Permissions-Policy` +

\``Permissions-Policy`\` HTTP + Header Field

+

The \`Permissions-Policy\` HTTP header field can be used in the [=response=] (server to client) to communicate the permissions policy that should be enforced by the client.

-

Permissions-Policy is a structured header. Its value - must be a dictionary. It's ABNF is: +

\`Permissions-Policy\` is a structured + header. Its value must be a dictionary. It's ABNF is:

       PermissionsPolicy = sf-dictionary
     
@@ -671,21 +692,25 @@ partial interface HTMLIFrameElement {

The {{getAllowlistForFeature(feature)}} method must run the following steps: - 1. Set |result| to an empty list + 1. Set |result| to an empty list. 2. Let |origin| be this {{PermissionsPolicy}} object's default - origin. + origin. 3. Let |policy| be the observable policy for this - {{PermissionsPolicy}} object's associated node. + {{PermissionsPolicy}} object's associated node. 4. If |feature| is not allowed in |policy| for |origin|, return |result| - 5. Let |allowlist| be |policy|'s declared policy[|feature|] + 5. Let |allowlist| be |policy|'s [=/declared policy=][|feature|]'s + [=declared policy/declarations=]. 6. If |allowlist| is the special value `*`: 1. Append "`*`" to |result| 2. Return |result|. 7. If the allowlist's self-origin is not null, - append the serialization of it to |result| + append the serialization of it to + |result|. 8. If the allowlist's src-origin is not null, - append the serialization of it to |result| - 9. Otherwise, for each permissions-source-expression |item| in |allowlist|'s expressions: + append the serialization of it to + |result|. + 9. Otherwise, for each permissions-source-expression |item| in + |allowlist|'s expressions: 1. Append |item| to |result| 10. Return |result|. @@ -704,8 +729,10 @@ partial interface HTMLIFrameElement { |feature|, |node| and |node|'s declared origin. 2. Set |inherited policy|[|feature|] to |isInherited|. 4. Return a new permissions policy with inherited policy |inherited policy| and declared policy a new [=ordered map=]. + policy">inherited policy |inherited policy|, declared policy a [=struct=] with both + [=declared policy/declarations=] and [=declared policy/reporting + configuration=] new [=ordered maps=].

To get the declared origin for an Element |node|, run the following steps: @@ -786,9 +813,24 @@ partial interface HTMLIFrameElement { resulted only in this report being generated (with no further action taken by the user agent in response to the violation). - Note: There is currently no mechanism in place for enabling report-only - mode, so [=PermissionsPolicyViolationReportBody/disposition=] will always - be set to "enforce". +

+

\``Permissions-Policy-Report-Only`\` + HTTP Header Field

+

The \`Permissions-Policy-Report-Only\` + HTTP header field can be used in the [=response=] (server to client) to + communicate a permissions policy that should not be enforced by the + client, but instead should be used to trigger reports to be sent if any + policy declared within it *would* have been violated, had the policy been + active.

+

\`Permissions-Policy-Report-Only\` is a + structured header. Its value must be a dictionary. + + The semantics of the dictionary are defined in + [[#structured-header-serialization]]. + + The processing steps are defined in [[#algo-construct-policy]]. +

@@ -797,12 +839,14 @@ partial interface HTMLIFrameElement { ## Process response policy ## {#algo-process-response-policy}
- Given a [=response=] (|response|) and an [=origin=] (|origin|), this - algorithm returns a declared policy. + Given a [=response=] (|response|), an [=origin=] (|origin|), and a boolean + (|report-only|), this algorithm returns a [=/declared policy=]. + 1. Let |header name| be "Permissions-Policy-Report-Only" if + |report-only| is True, or "Permissions-Policy" otherwise. 1. Let |parsed header| be the result of executing get a structured - field value given "Permissions-Policy" and "dictionary" from - |response|’s header list. + field value given |header name| and "dictionary" from |response|’s + [=response/header list=]. 1. If |parsed header| is null, return an empty [=ordered map=]. 1. Let |policy| be the result of executing Construct policy from dictionary and origin on |parsed header| and |origin|. @@ -815,13 +859,16 @@ partial interface HTMLIFrameElement {
Given an ordered map (|dictionary|) and an [=origin=] (|origin|), this - algorithm will return a declared policy. - 1. Let |policy| be an empty [=ordered map=]. - 1. [=map/For each=] |feature-name| → |value| of |dictionary|: + algorithm will return a [=/declared policy=]. + 1. Let |declarations| be an empty [=ordered map=]. + 1. Let |reporting-config| be an empty [=ordered map=]. + 1. [=map/For each=] |feature-name| → (|value|, |params|) of |dictionary|: 1. If |feature-name| does not identify any recognized policy-controlled feature, then [=iteration/continue=]. 1. Let |feature| be the policy-controlled feature identified by |feature-name|. + 1. If |params|["report-to"] exists, and is a string, then set + |reporting-config|[|feature|] to |params|["report-to"]. 1. Let |allowlist| be a new allowlist. 1. If |value| is the token `*`, or if |value| is a list which contains the token `*`, set |allowlist| to the special value @@ -832,8 +879,8 @@ partial interface HTMLIFrameElement { |element| in |value|: 1. If |element| is the token `self`, let |allowlist|'s self-origin be |origin|. 1. If |element| is a valid permissions-source-expression, [=list/append=] |element| to |allowlist|'s expressions. - 1. Set |policy|[|feature|] to |allowlist|. - 1. Return |policy|. + 1. Set |declarations|[|feature|] to |allowlist|. + 1. Return «|declarations|, |reporting-config|».
@@ -920,7 +967,7 @@ partial interface HTMLIFrameElement { 1. Set |inherited policy|[|feature|] to |isInherited|. 1. Let |policy| be a new permissions policy, with inherited policy |inherited policy| and declared policy a new [=ordered map=]. + policy">declared policy «[], []». 1. Return |policy|. @@ -930,16 +977,21 @@ partial interface HTMLIFrameElement {
Given null or a navigable container (|container|), an origin - (|origin|), and a [=response=] (|response|), this algorithm returns a new + (|origin|), a [=response=] (|response|), and an optional boolean + (|report-only|), with a default value of False, this algorithm returns a new permissions policy. 1. Let |policy| be the result of running Create a Permissions Policy for a navigable given |container| and |origin|. 1. Let |d| be the result of running Process response - policy on |response| and |origin|. - 1. For each |feature| → |allowlist| of |d|: + policy given |response|, |origin| and |report-only|. + 1. For each |feature| → |allowlist| of |d|'s [=declared policy/declarations=]: 1. If |policy|'s inherited policy[|feature|] is true, then set |policy|'s declared policy[|feature|] to |allowlist|. + policy">declared policy's [=declared + policy/declarations=][|feature|] to |allowlist|. + 1. Set |policy|'s declared + policy[|feature|]'s [=declared policy/reporting configuration=] to + |d|'s [=declared policy/reporting configuration=]. 1. Return |policy|.
@@ -989,47 +1041,111 @@ partial interface HTMLIFrameElement { |feature| is "Disabled", return "Disabled". 1. If |feature| is present in |policy|'s declared policy: - 1. If the allowlist for |feature| in |policy|'s declared policy matches |origin|, then return - "Enabled". + 1. If |policy|'s declared + policy's [=declared policy/declarations=][|feature|] + matches |origin|, then return "Enabled". 1. Otherwise return "Disabled". 1. Return "Enabled".
- ## Is feature enabled in document for origin? ## {#algo-is-feature-enabled} - -
- Given a [=feature=] (|feature|), a {{Document}} object - (|document|), and an [=origin=] (|origin|), this algorithm - returns "Disabled" if |feature| should be considered - disabled, and "Enabled" otherwise.

- 1. Let |policy| be |document|'s [=Document/permissions policy=]. + ## Check permissions policy ## {#algo-check-permissions-policy} + +
+ To check a permissions policy, given [=permissions policy=] (|policy|), a + [=feature=] (|feature|), an [=origin=] (|origin|) and another [=origin=] + (|document origin|), this algorithm returns "Disabled" if + |feature| should be considered disabled, and "Enabled" + otherwise. 1. If |policy|'s inherited policy for |feature| is "Disabled", return "Disabled". - 1. If |feature| is present in |policy|'s declared - policy: - 1. If the allowlist for |feature| in |policy|'s declared policy matches |origin|, then return - "Enabled". + 1. If |feature| is present in |policy|'s declared policy: + 1. If |policy|'s declared + policy's [=declared policy/declarations=][|feature|] + matches |origin|, then return "Enabled". 1. Otherwise return "Disabled". 1. If |feature|'s default allowlist is *, return "Enabled". 1. If |feature|'s default allowlist is 'self', and - |origin| is [=same origin=] with |document|'s [=Document/origin=], return + |origin| is [=same origin=] with |document origin|, return "Enabled". 1. Return "Disabled".
+
+ ## Is feature enabled in document for origin? ## {#algo-is-feature-enabled} + +
+ Given a [=feature=] (|feature|), a {{Document}} object + (|document|), an [=origin=] (|origin|), and an optional boolean (|report|), + with a default value of True, this algorithm returns "Disabled" + if |feature| should be considered disabled, and "Enabled" + otherwise. If |report| is True, then it will also [=generate and queue a + report=] if the feature is not enabled in either |document|'s + [=Document/permissions policy=] or |document|'s [=Document/report-only + permissions policy=]

+ + Note: The default value of True for |report| means that most permissions + policy checks will generate a violation report if the feature is not + enabled. This is the expected result, as most checks are for an actual + attempted use of the feature. If a call to this algorithm is performed just + to query the state of a feature, and does not represent an actual attempt to + use the feature, then |report| should be set to False. + + 1. Let |policy| be |document|'s [=Document/permissions policy=]. + 1. Let |report-only policy| be |document|'s [=Document/report-only + permissions policy=]. + 1. Let |result| be the result of calling Check permissions + policy, given |policy|, + |feature|, |origin|, and |document|'s [=Document/origin=]. + 1. Let |report-only result| be the result of calling Check + permissions policy, given |report-only policy|, |feature|, |origin|, + and |document|'s [=Document/origin=]. + 1. If |report| is True: + 1. Let |settings| be |document|'s environment settings object. + 1. If |result| is "Disabled": + 1. Let |endpoint| be the result of calling Get the + reporting endpoint for a feature given |feature| and + |policy|. + 1. Call Generate report for violation of permissions + policy on settings given |feature|, |settings|, + "Enforce", and |endpoint|. + 1. Else, if |report-only result| is "Disabled": + 1. Let |report-only endpoint| be the result of calling Get the reporting endpoint for a feature given + |feature| and |report-only policy|. + 1. Call Generate report for violation of permissions + policy on settings given |feature|, |settings|, + "Report", and |report-only endpoint|. + 1. Return result + +
+
+
+ ## Get the reporting endpoint for a feature ## {#algo-get-reporting-endpoint} + +
+ Given a [=feature=] (|feature|) and a [=permissions policy=] (|policy|), + this algorithm returns a string naming the endpoint to send violation + reports to, or null if no such endpoint has been declared in |policy|. + 1. Let |config| be |policy|'s [=permissions policy/declared policy=]'s + reporting configuration. + 1. If |config|[|feature|] exists, return |config|[|feature|]. + 1. Return null. + +
+
## Generate report for violation of permissions policy on settings ## {#algo-report-permissions-policy-violation}
Given a [=feature=] (|feature|), an environment settings object - (|settings|), and an optional string (|group|), this algorithm generates a - report about the violation of the policy for |feature|. + (|settings|), a string (|disposition|), and a string-or-null (|endpoint|), + this algorithm generates a report about the violation of the + policy for |feature|. 1. Let |body| be a new {{PermissionsPolicyViolationReportBody}}, initialized as follows: @@ -1043,7 +1159,7 @@ partial interface HTMLIFrameElement { : [=PermissionsPolicyViolationReportBody/columnNumber=] :: null : [=PermissionsPolicyViolationReportBody/disposition=] - :: "enforce" + :: |disposition| 1. If the user agent is currently executing script, and can extract the source file's URL, line number, and column number from |settings|, then @@ -1051,15 +1167,10 @@ partial interface HTMLIFrameElement { [=PermissionsPolicyViolationReportBody/lineNumber=], and [=PermissionsPolicyViolationReportBody/columnNumber=] accordingly. - 1. If |group| is omitted, set |group| to "default". - 1. Execute [=generate and queue a report=] with |body|, - "permissions-policy-violation", |group|, and |settings|. + "permissions-policy-violation", |endpoint|, and |settings|.
- - Note: This algorithm should be called when a permissions policy has - been violated.
## Should request be allowed to use feature? ## {#algo-should-request-be-allowed-to-use-feature} @@ -1089,6 +1200,29 @@ partial interface HTMLIFrameElement {
+
+

Changes to other specifications

+ +
+

Changes to the HTML specification

+ Every {{Document}} has a report-only permissions + policy, which is a [=permissions policy=], which is initially empty. + + In 7.5.1 + Shared document creation infrastructure, after step 3, insert the + following step: + + 4. Let |reportOnlyPermissionsPolicy| be the result of calling Create a Permissions Policy for a navigable from + response given navigationParams's navigable's container, + navigationParams's origin, navigationParams's response, and True. + + And in the same section, in step 10, set the new {{Document}}'s + [=Document/report-only permissions policy=] to |reportOnlyPermissionsPolicy|. +
+
+

IANA Considerations

The permanent message header field registry should be updated with the