From 2d947f8af81acdfe6734030baadcef7128dcba65 Mon Sep 17 00:00:00 2001 From: Daniel Vogelheim <30862698+otherdaniel@users.noreply.github.com> Date: Mon, 14 Oct 2024 15:31:32 +0000 Subject: [PATCH] Initial draft: HTMLPermissionElement definition. (#31) SHA: 1f241e6b17e7daf802266cb9cebd9467f49c4b5e Reason: push, by otherdaniel Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- permission-element.html | 2209 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 2200 insertions(+), 9 deletions(-) diff --git a/permission-element.html b/permission-element.html index 545b57f..ed1d550 100644 --- a/permission-element.html +++ b/permission-element.html @@ -6,9 +6,30 @@ - + + + + + + +

The HTML <permission> Element

-

Draft Community Group Report,

+

Draft Community Group Report,

This version:
https://wicg.github.io/PEPC/permission-element.html
Issue Tracking:
GitHub -
Editors: +
Inline In Spec +
Editor:
Daniel Vogelheim (Google LLC) -
Andy Paicu (Google LLC)
@@ -453,15 +800,1859 @@

Table of Contents

  1. 1 Introduction -
  2. 2 Framework -
  3. 3 Algorithms +
  4. + 2 The permission element. +
      +
    1. 2.1 permission element internal state +
    2. 2.2 permission-supporting state at the navigable +
    3. + 2.3 permission element interesting behaviours +
        +
      1. 2.3.1 The type property +
      2. 2.3.2 Activation blockers +
      +
    4. 2.4 permission element algorithms +
    +
  5. 3 CSS Integration
  6. 4 Security & Privacy Considerations +
  7. + Index +
      +
    1. Terms defined by this specification +
    2. Terms defined by reference +
    +
  8. + References +
      +
    1. Normative References +
    +
  9. IDL Index +
  10. Issues Index

1. Introduction

-

2. Framework

-

3. Algorithms

+

User agents expose powerful features to web sites, which are features +that are important to some use cases, but can be easily abused. The arguably +canonical example of such a powerful feature is camera access, which is +essential to many use cases like online meetups, but unsolicited camera +activation would be a major privacy issue. To handle this, user +agents use permissions to ask the user whether they wish for a particular +access to be allowed or not.

+

These permission requests began as a fairly direct passthrough: A site would +ask for some capability and the user agent immediately prompts the user to make +a decision for the request. Meanwhile, spam and abuse have forced user agents +to take a more opinionated approach to protect users' security, privacy, and +attention. The status quo is that users get a multitude of permission requests, +where it’s oftentimes unclear to users what the consequences of these requests +might be.

+

This spec introduces a new mechanism that requests access to powerful features through an in-page element, with built-in protections +against abuse. This wants to tie permission requests to the actual context +in which they will be used, thus reducing "permission spam" and at the same +time providing implementations with a better signal of user intent.

+

2. The permission element.

+
+
Categories: +
Flow content. +
Phrasing content. +
Interactive content. +
Palpable content. +
Contexts in which this element can be used: +
Where phrasing content is expected. +
Content model: +
Nothing. +
Content attributes: +
Global attributes +
type — Type of permission this element applies to. +
isValid — query whether the element can currently be activated. +
invalidReason — Return a string representation of why the element currently cannot be activated. +
ondismiss — notifies when the user has dismissed the permission prompt. +
onresolve — notifies when a permission prompt has been answered by the user (positively or negatively). +
onvalidationstatuschange — notifies when the validation status changes. +
Accessibility considerations: +
+
DOM interface: +
+
[Exposed=Window]
+interface HTMLPermissionElement : HTMLElement {
+  [HTMLConstructor] constructor();
+  [CEReactions, Reflect] attribute DOMString type;
+
+  readonly attribute boolean isValid;
+  readonly attribute PermissionElementBlockerReason invalidReason;
+
+  attribute EventHandler onresolve;
+  attribute EventHandler ondismiss;
+  attribute EventHandler onvalidationstatuschange;
+};
+
+
+

Add accessibility considerations.

+

Check attribute & event handler & invalid reason names against + current proposal(s).

+

The type attribute controls the behavior of the +permission element when it is activated. Is is an enumerated attribute, +whose values are the names of powerful features. It +has neither a missing value default state nor a invalid value default state.

+

The isValid attribute reflects whether a the +permission element is not currently blocked.

+

The invalidReason attribute is an enumerated attribute that reflects the internal state of the permission +element. It’s value set are PermissionElementBlockerReason

+

The global lang attribute is observed by the permission element to select localized text.

+

The following are the event handlers (and their corresponding event handler event types) that must be supported on permission elements event handler IDL attributes:

+ + + + + +
onresolve + Event +
ondismiss + Event +
onvalidationstatuschange + Event +
+

onvalidationstatuschange is probably not a simple Event.

+

2.1. permission element internal state

+

The permission element represents a user-requestable permission, +which the user can activate to enable (or disable) a particular permission or +set of permissions. It is core to the permission element that these +requests are triggered by the user, and not by the page’s script. To enforce +this, the element checks whether the activation event is trusted. Additionally it watches a number of conditions, like whether the element is +(partially) occluded, or if it has recently been moved. The element maintains +an internal [[BlockerList]] to keep track of this.

+

The permission element has the following internal slots:

+ +

2.2. permission-supporting state at the navigable

+

In order to support the permission element, the navigable maintains +an ordered set of permission elements, [[PermissionElements]]. This ordered set is used to evaluate the blockers of type unsuccesful_registration.

+

2.3. permission element interesting behaviours

+

The permission element has a few surprising behaviours, to support its +security properties:

+

2.3.1. The type property

+

The permission type cannot be modified. Modifying the permission type at will +may lead to user confusion, and hence we’d like to prevent it. Since, however, +a page may create a permission element dynamically we still need to offer +an API to modify it. To do do, we distinguish between a freshly initialized and +an empty or invalid (no permission) state, where the former allows setting the +type and the latter does not.

+

Example:

+
// Changing a valid type:
+var pepc = document.createElement("permission");
+pepc.type = "camera";  // Okay.
+pepc.type;  // "camera".
+pepc.type = "geolocation";  // Not okay. Would have been okay as initial assignment.
+pepc.type;  // "camera". Reflects the internal state, which has not changed.
+
+// Setting an invalid type:
+pepc = document.createElement("permission");
+pepc.type = "icecream";  // Ice cream is not a powerful browser feature. Not okay.
+pepc.type;  // "". Reflects the internal state.
+pepc.type = "camera";  // Still Not okay, because type as already been set.
+                       // Would have been okay as initial assignment.
+pepc.type;  // "". Reflects the internal state, which has not changed.
+
+
+
+ The HTMLPermissionElement’s type getter steps are: +
    +
  1. +

    If [[Types]] is null: Return "".

    +
  2. +

    Return a string, containing the concatenation of all powerful feature names in [[Types]], seperated by " ".

    +
+
+
+ The HTMLPermissionElement’s type setter steps are: +
    +
  1. +

    If [[Types]] is not null: Return.

    +
  2. +

    Set [[Types]] to «[]».

    +
  3. +

    Parse the input as a string of powerful feature names, seperated by whitespace.

    +
  4. +

    If any errors occured, return.

    +
  5. +

    Check if the set of powerful features is supported for the HTMLPermissionElement by the user agent. If not, return.

    +
  6. +

    Append each powerful feature name to the [[Types]] ordered set.

    +
+

Note: The supported sets of powerful features is implementation-defined.

+
+

2.3.2. Activation blockers

+

The key goal of the permission element is to reflect a user’s conscious +choice, and we need to make sure the user cannot easily be tricked into +activating it. To do so, the permission maintains a list of blocker reasons, +which may - permanently or temporarily - prevent the element from being +activated.

+
enum PermissionElementBlockerReason {
+  "",  // No blocker reason.
+  "type_invalid", "illegal_subframe", "unsuccesful_registration",
+  "recently_attached", "intersection_changed",
+  "intersection_out_of_viewport_or_clipped",
+  "intersection_occluded_or_distorted", "style_invalid"
+};
+
+

The permission element keeps track of "blockers", reasons why the element (currently) cannot be activated. These blockers come with three lifetimes: Permanent, temporary, and expiring.

+
+
Permanent blocker +
+

Once an element has a permanent blocker, it will be disabled permanently. +There are used for issues that the website owner is expected to fix. +An example is a permission element inside a fencedframe.

+
Temporary blocker +
+

This is a blocker that will only be valid until the blocking condition no +no longer occurs. An example is a permission element that is not +currently in view. All temporary blockers turn into expiring blockers once the condition no longer applies.

+
Expiring blocker +
+

This is a blocker that is only valid for a fixed period of time. This is +used to block abuse scenarios like "click jacking". An example is +a permission element that has recently been moved.

+
+
+ + + + + + + + + + + + + +
Blocker name + Blocker type + Example condition + Order hint +
type_invalid + permanent + When an unsupported permission type has been + set. + 1 +
illegal_subframe + permanent + When the permission element is used inside a fencedframe. + 2 +
unsuccesful_registration + temporary + When too many other permission elements for the same powerful feature have been inserted into the same document. + 3 +
recently_attached + expiring + When the permission element has just been attached to the + DOM. + 4 +
intersection_changed + expiring + When the permission element is being moved. + 6 +
intersection_out_of_viewport_or_clipped + temporary + When the permission element is not or not fully in the viewport. + 7 +
intersection_occluded_or_distorted + temporary + When the permission element is fully in the viewport, + but still not fully visible (e.g. because it’s partly behind other content). + 8 +
style_invalid + temporary + + 9 +
+
+
+ To add a blocker with a PermissionElementBlockerReason reason and an optional flag expires: +
    +
  1. +

    Assert: reason is not "". +(The empty string in PermissionElementBlockerReason signals no blocker +is present. Why would you add a non-blocking blockern empty string?)

    +
  2. +

    Let timestamp be None.

    +
  3. +

    If expires, then let timestamp be current high resolution time plus the blocker delay.

    +
  4. +

    Append an entry to the internal [[BlockerList]] with reason and timestamp.

    +
+
+
The blocker delay is 500ms.
+
+ To add an expiring blocker with a PermissionElementBlockerReason reason: +
    +
  1. +

    Assert: reason is listed as "expiring" in the blocker reason table.

    +
  2. +

    Add a blocker with reason and true.

    +
+
+
+ To add a temporary blocker with a PermissionElementBlockerReason reason: +
    +
  1. +

    Assert: reason is listed as "temporary" in the blocker reason table.

    +
  2. +

    Add a blocker with reason and false.

    +
+
+
+ To add a permanent blocker with a PermissionElementBlockerReason reason: +
    +
  1. +

    Assert: reason is listed as "permanent" in the blocker reason table.

    +
  2. +

    Add a blocker with reason and false.

    +
+
+
+ To remove blockers with PermissionElementBlockerReason reason from an element: +
    +
  1. +

    Assert: reason is listed as "temporary" in the blocker reason table.

    +
  2. +

    For each entry in element’s [[BlockerList]]:

    +
      +
    1. +

      If entry’s reason equals reason, then remove entry from element’s [[BlockerList]].

      +
    +
  3. +

    Add a blocker with reason and true.

    +
+
+
+ To determine a HTMLPermissionElement element’s blocker: +
    +
  1. +

    Let blockers be the result of sorting element’s [[BlockerList]] with the blocker ordering algorithm.

    +
  2. +

    If blockers is not empty and blockers[0] is blocking, then return blockers[0].

    +
  3. +

    Return nothing.

    +
+
+
+ To determine blocker ordering for +two blockers a and b: +
    +
  1. +

    Let really large number be 99.

    +
  2. +

    Assert: No order hint in the blocker reason table is equal to or +greater than really large number.

    +
  3. +

    If a is blocking, then let a hint be the +order hint of a’s reason in the blocker reason table, otherwise let a hint be really large number.

    +
  4. +

    If b is blocking, then let b hint be the +order hint of b’s reason in the blocker reason table, otherwise let b hint be really large number.

    +
  5. +

    Return whether a hint is less than or equal to b hint.

    +
+
+
+ An HTMLPermissionElement's blocker list’s entry is blocking if: +
    +
  1. +

    entry has no blocker timestamp,

    +
  2. +

    or entry has a blocker timestamp, and the blocker timestamp is +greater or equal to the current high resolution time.

    +
+
+

NOTE: The spec maintains blockers as a list [[BlockerList]], which may + potentially grow indefinitely (since some blocker types simply expire, + but are not removed). + This structure is chosen for the simplicity of explanation, rather than for + efficiency. The details of this blocker structure are not observable except + for a handful of algorithms defined here, which should open plenty of + opportunities for implementations to handle this more efficiently.

+

2.4. permission element algorithms

+
+ The HTMLPermissionElement constructor steps are: +
    +
  1. +

    Initialize the internal [[Types]] slot to null.

    +
  2. +

    Initialize the internal [[BlockerList]] to «[]».

    +
+
+
+ The HTMLPermissionElement insertion steps are: +
    +
  1. +

    If [[Types]] is null, set [[Types]] to «[]».

    +
  2. +

    Initialize the internal [[BlockerList]] to «[]».

    +
  3. +

    Append this to node navigable's [[PermissionElements]].

    +
  4. +

    Initialize the internal [[IntersectionRect]] with undefined.

    +
  5. +

    Initialize the internal [[IntersectionObserver]] with the result of +constructing a new IntersectionObserver, with IntersectionObserver callback.

    +
  6. +

    Call [[IntersectionObserver]].observe(this).

    +
  7. +

    If [[Types]] is empty, then add a permanent blocker with reason type_invalid.

    +
  8. +

    If this is not type permissible, then add a temporary blocker with unsuccesful_registration.

    +
  9. +

    Add an expiring blocker with reason recently_attached.

    +
  10. +

    If the traversable navigable of the node navigable of this is a fenced navigable, then add a permanent blocker with illegal_subframe.

    +
+
+ +
+ HTMLPermissionElement element’s isValid getter steps are: +
    +
  1. +

    Return whether element’s blocker is Nothing.

    +
+
+
+ HTMLPermissionElement element’s invalidReason getter steps are: +
    +
  1. +

    If element’s blocker is Nothing, return "".

    +
  2. +

    Otherwise, element’s blocker's reason string.

    +
+
+
+ A permission element’s activation behavior given event is: +
    +
  1. +

    Assert: element’s [[Types]] is not null.

    +
  2. +

    If element’s [[Types]] is empty, then return.

    +
  3. +

    If event.isTrusted is false, then return.

    +
  4. +

    If element.isValid is false, then return.

    +
  5. +

    Request permission to use the powerful features named in element’s [[Types]].

    +
+

What about event handlers?

+
+
+ The HTMLPermissionElement’s IntersectionObserver callback implements IntersectionObserverCallback and runs the following steps: +
    +
  1. +

    Assert: The IntersectionObserver's root is the Document

    +
  2. +

    Let entries be the value of the first callback parameter, the list of intersection observer entries.

    +
  3. +

    Assert: entries is not empty.

    +
  4. +

    Let entry be entries’s last item.

    +
  5. +

    If entry.isVisible, then:

    +
      +
    1. +

      Remove blockers with intersection_occluded_or_distorted.

      +
    2. +

      Remove blockers with intersection_out_of_viewport_or_clipped.

      +
    +
  6. +

    Otherwise:

    +
      +
    1. +

      If entry.intersectionRatio >= 1, then:

      +
        +
      1. +

        Let reason be intersection_occluded_or_distorted.

        +
      +
    2. +

      Otherwise:

      +
        +
      1. +

        Let reason be intersection_out_of_viewport_or_clipped.

        +
      +
    3. +

      Add a temporary blocker with reason.

      +
    +
  7. +

    If [[IntersectionRect]] does not equal entry.intersectionRect then add an expiring blocker with intersection_changed.

    +
  8. +

    Set [[IntersectionRect]] to entry.intersectionRect

    +
+

Do I need to define dictionary equality?

+
+
+ To determine whether an element is type permissible: +
    +
  1. +

    Assert: element’s node navigable's [[PermissionElements]] contains element.

    +
  2. +

    Let count be 0.

    +
  3. +

    For each current in element’s node navigable's [[PermissionElements]]:

    +
      +
    1. +

      If current is element, then break.

      +
    2. +

      If the intersection of element.[[Types]] with current.[[Types]] is not empty, +then increment count by 1.

      +
    +
  4. +

    Return whether count is less than 2.

    +
+
+
+ To recheck type permissibility for a document: +
    +
  1. +

    For each current in document’s [[PermissionElements]]:

    +
      +
    1. +

      If current is type permissible, then remove blockers with unsuccesful_registration from current.

      +
    +
+
+

3. CSS Integration

4. Security & Privacy Considerations

- \ No newline at end of file + +

Index

+

Terms defined by this specification

+ +

Terms defined by reference

+ +

References

+

Normative References

+
+
[CSS21] +
Bert Bos; et al. Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification. URL: https://drafts.csswg.org/css2/ +
[DOM] +
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/ +
[FENCED-FRAME] +
Fenced Frame. Draft Community Group Report. URL: https://wicg.github.io/fenced-frame/ +
[GEOMETRY-1] +
Simon Pieters; Chris Harrelson. Geometry Interfaces Module Level 1. URL: https://drafts.fxtf.org/geometry/ +
[HR-TIME-3] +
Yoav Weiss. High Resolution Time. URL: https://w3c.github.io/hr-time/ +
[HTML] +
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/ +
[INFRA] +
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/ +
[INTERSECTION-OBSERVER] +
Stefan Zager; Emilio Cobos Álvarez; Traian Captan. Intersection Observer. URL: https://w3c.github.io/IntersectionObserver/ +
[MANIFEST-APP-INFO] +
Aaron Gustafson. Web App Manifest - Application Information. URL: https://w3c.github.io/manifest-app-info/ +
[PERMISSIONS] +
Marcos Caceres; Mike Taylor. Permissions. URL: https://w3c.github.io/permissions/ +
[WEBIDL] +
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/ +
+

IDL Index

+
[Exposed=Window]
+interface HTMLPermissionElement : HTMLElement {
+  [HTMLConstructor] constructor();
+  [CEReactions, Reflect] attribute DOMString type;
+
+  readonly attribute boolean isValid;
+  readonly attribute PermissionElementBlockerReason invalidReason;
+
+  attribute EventHandler onresolve;
+  attribute EventHandler ondismiss;
+  attribute EventHandler onvalidationstatuschange;
+};
+
+enum PermissionElementBlockerReason {
+  "",  // No blocker reason.
+  "type_invalid", "illegal_subframe", "unsuccesful_registration",
+  "recently_attached", "intersection_changed",
+  "intersection_out_of_viewport_or_clipped",
+  "intersection_occluded_or_distorted", "style_invalid"
+};
+
+
+

Issues Index

+
+
Add accessibility considerations.
+
Check attribute & event handler & invalid reason names against + current proposal(s).
+
onvalidationstatuschange is probably not a simple Event.
+
What about event handlers?
+
Do I need to define dictionary equality?
+
+ + + + \ No newline at end of file