Movatterモバイル変換


[0]ホーム

URL:


ThePush API enables sending of apush message to a web application via apush service. Anapplication server can send apush message at any time, even when a web application oruser agent is inactive. Thepush service ensures reliable and efficient delivery to theuser agent.Push messages are delivered to aService Worker that runs in the origin of the web application, which can use the information in the message to update local state or display a notification to the user.

This specification is designed for use with theweb push protocol, which describes how anapplication server oruser agent interacts with apush service.

Introduction

The Push API allows a web application to communicate with auser agent asynchronously. This allows anapplication server to provide theuser agent with time-sensitive information whenever that information becomes known, rather than waiting for a user to open the web application.

As defined here,push services support delivery ofpush messages at any time.

In particular, apush message will be delivered to the web application even if that web application is not currently active in a browser window: this relates to use cases in which the user may close the web application, but still benefits from the web application being able to be restarted when apush message is received. For example, apush message might be used to inform the user of an incoming WebRTC call.

Apush message can also be sent when theuser agent is temporarily offline. In support of this, thepush service stores messages for theuser agent until theuser agent becomes available. This supports use cases where a web application learns of changes that occur while a user is offline and ensures that theuser agent can be provided with relevant information in a timely fashion.Push messages are stored by thepush service until theuser agent becomes reachable and the message can be delivered.

The Push API will also ensure reliable delivery of push messages while auser agent is actively using a web application, for instance if a user is actively using the web application or the web application is in active communication with anapplication server through an active worker, frame, or background window. This is not the primary use case for the Push API. A web application might choose to use the Push API for infrequent messages to avoid having to maintain constant communications with theapplication server.

Push messaging is best suited to occasions where there is not already an active communications channel established between theuser agent and the web application. Sendingpush messages requires considerably more resources when compared with more direct methods of communication such as the [[Fetch|Fetch API]] or [[WebSockets]].Push messages usually have higher latency than direct communications and they can also be subject to restrictions on use. Mostpush services limit the size and quantity ofpush messages that can be sent.

Dependencies

Theweb push protocol [[RFC8030]] describes a protocol that enables communication between auser agent orapplication server and apush service. Alternative protocols could be used in place of this protocol, but this specification assumes the use of this protocol; alternative protocols are expected to provide compatible semantics.

TheContent-Encoding HTTP header, described in Section 8.4 of [[RFC9110]], indicates the content coding applied to the payload of apush message.

Concepts

Application server

The termapplication server refers to server-side components of a web application.

Push message

Apush message is data sent to a web application from anapplication server.

Apush message is delivered to the [=service worker registration/active worker=] associated with thepush subscription to which the message was submitted. If the service worker is not currently running, the worker is started to enable delivery.

Declarative push message

Adeclarative push message is a [=push message=] whose data is a JSON document that is understood by the user agent. A user agent opportunistically parses each incoming [=push message=] to determine if it is a [=declarative push message=] using the [=declarative push message parser=].

A [=declarative push message=] allows for the creation and display of a notification without the involvement of a service worker. Nevertheless, a service worker can still be involved if desired by the [=application server=]. In such a scenario the declarative nature of the [=push message=] serves as a backup in case the service worker was evicted due to storage pressure, for instance. And also provides a more object-oriented approach to transmitting notification data.

          {            "web_push": 8030,            "notification": {              "title": "Ada emailed ‘London’",              "lang": "en-US",              "dir": "ltr",              "body": "Did you hear about the tube strikes?",              "navigate": "https://email.example/message/12"            }          }

Members

A [=declarative push message=] has the following members:

web_push (required)

An integer that must be 8030. Used to disambiguate a [=declarative push message=] from other JSON documents.

notification (required)

A JSON object consisting of the following members, all analogous to Notifications API features, though sometimes with a slightly stricter type. Apart fromtitle all members are derived from the {{NotificationOptions}} dictionary and to be maintained in tandem. [[NOTIFICATIONS]]

title (required)

A string.

dir

"auto", "ltr", or "rtl".

lang

A string that holds a language tag.

body

A string.

navigate (required)

A string that holds a URL.

tag

A string.

image

A string that holds a URL.

icon

A string that holds a URL.

badge

A string that holds a URL.

vibrate

An array of [=/32-bit unsigned integers=].

timestamp

A [=/64-bit unsigned integer=].

renotify

A boolean.

silent

A boolean.

requireInteraction

A boolean.

This is not namedrequire_interaction for consistency with the {{NotificationOptions}} dictionary.

data

Any JSON value.

actions

An array of JSON objects consisting of the following members, all derived from the {{NotificationAction}} dictionary and to be maintained in tandem.

action (required)

A string.

title (required)

A string.

navigate (required)

A string that holds a URL.

icon

A string that holds a URL.

mutable

A boolean. When true causes apush event to be dispatched to a service worker (if any) containing the {{Notification}} object described by thedeclarative push message.

Parser

Adeclarative push message parser result is a [=/tuple=] consisting of anotification (a [=/notification=]) and amutable (a boolean).

Thedeclarative push message parser given a [=/byte sequence=]bytes, [=/origin=]origin, [=/URL=]baseURL, and {{EpochTimeStamp}}fallbackTimestamp runs these steps. They return failure or a [=/declarative push message parser result=].

  1. Letmessage be the result of [=parse JSON bytes to an Infra value|parsing JSON bytes to an Infra value=] givenbytes. If that throws an exception, then return failure.

  2. Ifmessage is not a [=/map=], then return failure.

  3. Ifmessage["`web_push`"] does not [=map/exist=] or is not 8030, then return failure.

  4. Ifmessage["`notification`"] does not [=map/exist=], then return failure.

  5. LetnotificationInput bemessage["`notification`"].

  6. IfnotificationInput is not a [=/map=], then return failure.

  7. IfnotificationInput["`title`"] does not [=map/exist=] or is not a string, then return failure.

  8. IfnotificationInput["`navigate`"] does not [=map/exist=] or is not a string, then return failure.

  9. LetnotificationTitle benotificationInput["`title`"].

  10. LetnotificationOptions be a {{NotificationOptions}} dictionary.

  11. IfnotificationInput["`dir`"] [=map/exists=] and is "`auto`", "`ltr`", or "`rtl`", then setnotificationOptions["{{NotificationOptions/dir}}"] tonotificationInput["`dir`"].

  12. IfnotificationInput["`lang`"] [=map/exists=] and is a string, then setnotificationOptions["{{NotificationOptions/lang}}"] tonotificationInput["`lang`"].

  13. IfnotificationInput["`body`"] [=map/exists=] and is a string, then setnotificationOptions["{{NotificationOptions/body}}"] tonotificationInput["`body`"].

  14. SetnotificationOptions["{{NotificationOptions/navigate}}"] tonotificationInput["`navigate`"], [=string/converted=].

  15. IfnotificationInput["`tag`"] [=map/exists=] and is a string, then setnotificationOptions["{{NotificationOptions/tag}}"] tonotificationInput["`tag`"].

  16. IfnotificationInput["`image`"] [=map/exists=] and is a string, then setnotificationOptions["{{NotificationOptions/image}}"] tonotificationInput["`image`"], [=string/converted=].

  17. IfnotificationInput["`icon`"] [=map/exists=] and is a string, then setnotificationOptions["{{NotificationOptions/icon}}"] tonotificationInput["`icon`"], [=string/converted=].

  18. IfnotificationInput["`badge`"] [=map/exists=] and is a string, then setnotificationOptions["{{NotificationOptions/badge}}"] tonotificationInput["`badge`"], [=string/converted=].

  19. IfnotificationInput["`vibrate`"] [=map/exists=] and is a [=/list=] of which each [=list/item=] is a [=/32-bit unsigned integer=], then setnotificationOptions["{{NotificationOptions/vibrate}}"] tonotificationInput["`vibrate`"].

  20. IfnotificationInput["`timestamp`"] [=map/exists=] and is a [=/64-bit unsigned integer=], then setnotificationOptions["{{NotificationOptions/timestamp}}"] tonotificationInput["`timestamp`"].

  21. IfnotificationInput["`renotify`"] [=map/exists=] and is a boolean, then setnotificationOptions["{{NotificationOptions/renotify}}"] tonotificationInput["`renotify`"].

  22. IfnotificationInput["`silent`"] [=map/exists=] and is a boolean, then setnotificationOptions["{{NotificationOptions/silent}}"] tonotificationInput["`silent`"].

  23. IfnotificationInput["`requireInteraction`"] [=map/exists=] and is a boolean, then setnotificationOptions["{{NotificationOptions/requireInteraction}}"] tonotificationInput["`requireInteraction`"].

  24. IfnotificationInput["`data`"] [=map/exists=], then setnotificationOptions["{{NotificationOptions/data}}"] to the result of runningconvert an Infra value to a JSON-compatible JavaScript value givennotificationInput["`data`"].

  25. IfnotificationInput["`actions`"] [=map/exists=] and is a [=/list=]:

    1. LetnotificationActions be « ».

    2. [=list/For each=]actionInput ofnotificationInput["`actions`"]:

      1. IfactionInput["`action`"] does not [=map/exist=] or is not a string, then [=iteration/continue=].

      2. IfactionInput["`title`"] does not [=map/exist=] or is not a string, then [=iteration/continue=].

      3. IfactionInput["`navigate`"] does not [=map/exist=] or is not a string, then [=iteration/continue=].

      4. LetactionNavigate beactionInput["`navigate`"], [=string/converted=].

      5. LetnotificationAction be the {{NotificationAction}} dictionary «[ "{{NotificationAction/action}}" →actionInput["`action`"], "{{NotificationAction/title}}" →actionInput["`title`"], "{{NotificationAction/navigate}}" →actionNavigate ]».

      6. IfactionInput["`icon`"] [=map/exists=] and is a string, then setnotificationAction["{{NotificationAction/icon}}"] toactionInput["`icon`"], [=string/converted=].

      7. [=list/Append=]notificationAction tonotificationActions.

    3. SetnotificationOptions["{{NotificationOptions/actions}}"] tonotificationActions.

  26. Letnotification be the result ofcreating a notification givennotificationTitle,notificationOptions,origin,baseURL, andfallbackTimestamp. If this throws an exception, then return failure.

  27. Ifnotification's [=notification/navigation URL=] is null, then return failure.

  28. If the [=notification action/navigation URL=] of any [=/notification action=] ofnotification's [=notification/actions=] is null, then return failure.

  29. Letmutable be false.

  30. Ifmessage["`mutable`"] [=map/exists=] andmessage["`mutable`"] is a boolean, then setmutable tomessage["`mutable`"].

  31. Return (notification,mutable).

Push subscription

Apush subscription is a message delivery context established between theuser agent and thepush service on behalf of a web application.

A [=push subscription=] has an associatedscope, which is a [=/URL=].

A [=push subscription=] is considered to have awindow-accessible scope when its [=push subscription/scope=]'s [=url/path=] is a [=/list=] of [=list/size=] 1 and [=push subscription/scope=]'s [=url/path=][0] is the empty string.

I.e., the [=url/path=] component of the [=/URL=] serializes as "`/`".

Apush subscription has an associatedpush endpoint. It MUST be the absolute URL exposed by thepush service where theapplication server can sendpush messages to. Apush endpoint MUST uniquely identify thepush subscription.

Apush subscription MAY have an associatedsubscription expiration time. When set, it MUST be the time, in milliseconds since 00:00:00 UTC on 1 January 1970, at which the subscription will bedeactivated. Theuser agent SHOULD attempt torefresh the push subscription before the subscription expires.

Apush subscription has internal slots for a P-256ECDH key pair and an authentication secret in accordance with [[RFC8291]]. These slots MUST be populated when creating thepush subscription.

If theuser agent has to change the keys of a [=push subscription=] for any reason and the [=push subscription=]'s [=associated service worker registration=] is non-null, it MUST [=refresh=] the [=push subscription=].

Tocreate a push subscription, given an {{PushSubscriptionOptionsInit}} |optionsDictionary:PushSubscriptionOptionsInit|:

  1. Let |subscription:PushSubscription| be a new {{PushSubscription}}.
  2. Let |options:PushSubscriptionOptions| be a newly created {{PushSubscriptionOptions}} object, initializing its attributes with the corresponding members and values of |optionsDictionary|.
  3. Set |subscription|'s {{PushSubscription/options}} attribute to |options|.
  4. Generate a new P-256ECDH key pair [[ANSI-X9-62]]. Store the private key in an internal slot on |subscription|; this value MUST NOT be made available to applications. The public key is also stored in an internal slot and can be retrieved by calling the {{PushSubscription/getKey()}} method of the {{PushSubscription}} with an argument of {{PushEncryptionKeyName/"p256dh"}}.
  5. Generate a new authentication secret, which is a sequence of octets as defined in [[RFC8291]]. Store the authentication secret in an internal slot on |subscription|. This key can be retrieved by calling the {{PushSubscription/getKey()}} method of the {{PushSubscription}} with an argument of {{PushEncryptionKeyName/"auth"}}.
  6. Request a newpush subscription. Include the {{PushSubscriptionOptions/applicationServerKey}} attribute of |options| when it has been set. Rethrow any [=exceptions=].
  7. When thepush subscription request has completed successfully:
    1. Set |subscription|'s {{PushSubscription/endpoint}} attribute to thepush subscription'spush endpoint.
    2. If provided by thepush subscription, set |subscription|'s {{PushSubscription/expirationTime}}.
  8. Return |subscription|.

Relationship to service worker registrations

A [=push subscription=]'sassociated service worker registration is the [=service worker registration=] whose [=service worker registration/scope URL=] [=URL/equals=] the [=push subscription=]'s [=push subscription/scope=], if any; otherwise null.

A [=push subscription=]'s [=associated service worker registration=] can only be null when it has a [=push subscription/window-accessible scope=].

And vice versa, a [=service worker registration=]'sassociated push subscription is the [=push subscription=] whose [=push subscription/scope=] [=URL/equals=] the [=service worker registration=]'s [=service worker registration/scope URL=], if any; otherwise null.

Subscription refreshes

Auser agent orpush service MAY choose torefresh apush subscription whose [=associated service worker registration=] is non-null at any time, for example because it has reached a certain age.

When this happens, theuser agent MUST run the steps tocreate a push subscription given thePushSubscriptionOptions that were provided for creating the currentpush subscription, and set the new [=push subscription=]'s [=push subscription/scope=] to the original subscription's [=push subscription/scope=]. The newpush subscription MUST have a key pair that's different from the original subscription.

When successful,user agent then MUSTfire the "`pushsubscriptionchange`" event with theservice worker registration associated with thepush subscription as |registration|, a {{PushSubscription}} instance representing the initialpush subscription as |oldSubscription| and a {{PushSubscription}} instance representing the newpush subscription as |newSubscription|.

To allow for time to propagate changes toapplication servers, auser agent MAY continue to accept messages for an oldpush subscription for a brief time after a refresh. Once messages have been received for a refreshedpush subscription, any oldpush subscriptions MUST bedeactivated.

If theuser agent is not able to refresh thepush subscription, it SHOULD periodically retry the refresh. When thepush subscription can no longer be used, for example because it has expired, theuser agent MUSTfire the "`pushsubscriptionchange`" event with theservice worker registration associated with thepush subscription as |registration|, a {{PushSubscription}} instance representing the deactivatingpush subscription as |oldSubscription| and `null` as the |newSubscription|.

Subscription deactivation

When apush subscription isdeactivated, both theuser agent and thepush service MUST delete any stored copies of its details. Subsequentpush messages for thispush subscription MUST NOT be delivered.

Apush subscription without a [=push subscription/window-accessible scope=] MUST bedeactivated when its associatedservice worker registration is unregistered, though apush subscription MAY bedeactivated earlier.

Apush subscription without a [=push subscription/window-accessible scope=] is removed whenservice worker registration is cleared.

Push service

The termpush service refers to a system that allowsapplication servers to sendpush messages to a web application. A push service serves thepush endpoint orendpoints for thepush subscriptions it serves.

Theuser agent connects to thepush service used to createpush subscriptions.User agents MAY limit the choice ofpush services available. Reasons for doing so include performance-related concerns such as service availability (including whether services are blocked by firewalls in specific countries, or networks at workplaces and the like), reliability, impact on battery lifetime, and agreements to steer metadata to, or away from, specificpush services.

Permission

The Push API is a [=powerful feature=] identified by the [=powerful feature/name=]"push".

For integration with the [[[Permissions]]] specification, this specification defines the {{PushPermissionDescriptor}} [=powerful feature/permission descriptor type=].

          dictionary PushPermissionDescriptor : PermissionDescriptor {            boolean userVisibleOnly = false;          };

TheuserVisibleOnly has the same semantics as {{PushSubscriptionOptionsInit/userVisibleOnly}}.

`{name: "push", userVisibleOnly: false}` is [=PermissionDescriptor/stronger than=] `{name: "push", userVisibleOnly: true}`.

Security and privacy considerations

The contents of apush message are encrypted [[RFC8291]]. However, thepush service is still exposed to the metadata of messages sent by anapplication server to auser agent over apush subscription. This includes the timing, frequency, and size of messages. Other than changingpush services, which user agents may disallow, the only known mitigation is to increase the apparent message size by padding.

There is no guarantee that apush message was sent by anapplication server having the same origin as the web application. Theapplication server is able to share the details necessary to use apush subscription with a third party at its own discretion.

The following requirements are intended to protect the privacy and security of the user as far as possible, and subject to meeting that goal, to protect the integrity of theapplication server's communication with the user.

The Push API may have to wake up the Service Worker associated with theservice worker registration in order to run the developer-provided event handlers. This can cause resource usage, such as network traffic, that theuser agent SHOULD attribute to the web application that created thepush subscription.

Theuser agent MAY consider thePushSubscriptionOptions when acquiring permission or determining the permission status.

When a permission is revoked, theuser agent MAYfire the "`pushsubscriptionchange`" event for subscriptions created with that permission, with theservice worker registration associated with thepush subscription as |registration|, a {{PushSubscription}} instance representing thepush subscription as |oldSubscription|, and `null` as |newSubscription|. Theuser agent MUSTdeactivate the affected subscriptions in parallel.

Thepush endpoint MUST NOT expose information about the user to be derived by actors other than thepush service, such as the user's device, identity or location. See the Privacy Considerations in [[RFC8030]] for the exact requirements.

Thepush endpoint of adeactivatedpush subscription MUST NOT be reused for a newpush subscription. This prevents the creation of a persistent identifier that the user cannot remove. This also prevents reuse of the details of onepush subscription to sendpush messages to anotherpush subscription.

Push Framework

Apush message is sent from anapplication server to a web application as follows:

This overall framework allowsapplication servers to activate aService Worker in response to events at theapplication server. Information about those events can be included in thepush message, which allows the web application to react appropriately to those events, potentially without needing to initiate network requests.

The following code and diagram illustrate a hypothetical use of the push API.

Example

          // https://example.com/serviceworker.js          this.onpush = event => {            console.log(event.data);            // From here we can write the data to IndexedDB, send it to any open            // windows, display a notification, etc.          }          // https://example.com/webapp.js          // inside an async function...          try {            const serviceWorkerRegistration = await navigator.serviceWorker.register(              "serviceworker.js"            );            const pushSubscription = await serviceWorkerRegistration.pushManager.subscribe();            // The push subscription details needed by the application            // server are now available, and can be sent to it using,            // for example, an XMLHttpRequest.            console.log(pushSubscription.endpoint);            console.log(pushSubscription.getKey("p256dh"));            console.log(pushSubscription.getKey("auth"));          } catch (err) {            // In a production environment it might make sense to            // also report information about errors back to the            // application server.            console.log(error);          }

Sequence diagram

Example flow of events for subscription, push message delivery, and unsubscription
Example flow of events for subscription, push message delivery, and unsubscription

Push service use

The fields included in the {{PushSubscription}} is all the information needed for anapplication server to send apush message. Push services that are compatible with the Push API provide apush endpoint that conforms to theweb push protocol. These parameters and attributes include:

`PushManagerAttribute` mixin

This specifications extends the {{Window}} and {{ServiceWorkerRegistration}} objects through the {{PushManagerAttribute}} mixin. [[HTML]] [[SERVICE-WORKERS]]

        [SecureContext]        interface mixin PushManagerAttribute {          readonly attribute PushManager pushManager;        };        Window includes PushManagerAttribute;        ServiceWorkerRegistration includes PushManagerAttribute;

{{Window}} and {{ServiceWorkerRegistration}} objects have an associated {{PushManager}} object.

ThepushManager getter steps are to return [=this=]'s associated {{PushManager}} object.

On a {{Window}} object the {{PushManager}}'s [=PushManager/service worker registration=] is null.

On a {{ServiceWorkerRegistration}} object the {{PushManager}}'s [=PushManager/service worker registration=] is theservice worker registration represented by the {{ServiceWorkerRegistration}} object.

PushManager interface

The {{PushManager}} interface defines the operations to accesspush services.

        [Exposed=(Window,Worker), SecureContext]        interface PushManager {          [SameObject] static readonly attribute FrozenArray<DOMString> supportedContentEncodings;          Promise<PushSubscription> subscribe(optional PushSubscriptionOptionsInit options = {});          Promise<PushSubscription?> getSubscription();          Promise<PermissionState> permissionState(optional PushSubscriptionOptionsInit options = {});        };

A {{PushManager}} has an associatedservice worker registration which is null or aservice worker registration.

ThesupportedContentEncodings attribute exposes the sequence of supported content codings that can be used to encrypt the payload of apush message. A content coding is indicated using theContent-Encoding header field when requesting the sending of apush message from thepush service.

User agents MUST support the `aes128gcm` content coding defined in [[RFC8291]], and MAY support content codings defined in previous versions of the draft for compatibility reasons.

`subscribe()` method

Thesubscribe() method steps are:

  1. Let |promise| be [=a new promise=].
  2. Let |global| be [=this=]'s [=relevant global object=].
  3. Let |scope| be null.
  4. Let |registration| be null.
  5. If [=this=]'s [=PushManager/service worker registration=] is null:
    1. Set |scope| to the result of running the [=basic URL parser=] given "`/`" and |global|'sassociatedDocument's [=Document/URL=].
  6. Otherwise:
    1. [=/Assert=]: [=this=]'s [=PushManager/service worker registration=] is a [=service worker registration=].
    2. Set |registration| to [=this=]'s [=PushManager/service worker registration=].
  7. If |scope| is failure or is a [=/URL=] whose [=url/scheme=] is not "`https`", then [=queue a global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with a {{"NotAllowedError"}} {{DOMException}} and terminate these steps.
  8. If |options|["{{PushSubscriptionOptionsInit/userVisibleOnly}}"] is false and the user agent requires it to be true, then [=queue a global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with a {{"NotAllowedError"}} {{DOMException}} and terminate these steps.
  9. If |options|["{{PushSubscriptionOptionsInit/applicationServerKey}}"] is null and thepush service requires it to be non-null, then [=queue a global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with a {{"NotSupportedError"}} {{DOMException}} and terminate these steps.
  10. If |options|["{{PushSubscriptionOptions/applicationServerKey}}"] is non-null:
    1. If |options|["{{PushSubscriptionOptions/applicationServerKey}}"] is a string, then set its value to an {{ArrayBuffer}} containing the sequence of octets that result from decoding |options|["{{PushSubscriptionOptions/applicationServerKey}}"] using the base64url encoding [[RFC7515]].
    2. If decoding fails, then [=queue a global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with an {{"InvalidCharacterError"}} {{DOMException}} and terminate these steps.
    3. Ensure that |options|["{{PushSubscriptionOptions/applicationServerKey}}"] describes a valid point on the P-256 curve. If its value is invalid, then [=queue a global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with an {{"InvalidAccessError"}} {{DOMException}} and terminate these steps.
  11. Run these steps [=in parallel=]:
    1. Let |subscription| be null.
    2. If |scope| is non-null:
      1. If there is a [=push subscription=] with a [=push subscription/window-accessible scope=] whose [=push subscription/scope=] [=URL/equals=] |scope|, then set |subscription| to that [=push subscription=].
    3. Otherwise:
      1. [=/Assert=]: |registration| is non-null.
      2. If |registration|'s [=service worker registration/active worker=] is null, then [=queue a global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with an {{"InvalidStateError"}} {{DOMException}} and terminate these steps.
      3. If |registration|'s [=associated push subscription=] is non-null, then set |subscription| to |registration|'s [=associated push subscription=].
      4. Set |scope| to |registration|'s [=service worker registration/scope URL=].
    4. Let |permission| be [=request permission to use=] "push".
    5. If |permission| is {{PermissionState/"denied"}}, [=queue a global task=] on the [=user interaction task source=] using |global| to [=reject=] |promise| with a {{"NotAllowedError"}} {{DOMException}} and terminate these steps.
    6. If |subscription| is non-null:
      1. If there is an error with |subscription|, then [=queue a global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with an {{"AbortError"}} {{DOMException}} and terminate these steps.
      2. Compare the |options| argument with the `options` attribute of |subscription|. The contents of {{BufferSource}} values are compared for equality rather than [=ECMAScript/reference record|reference=].
      3. If any attribute on |options| contains a different value to that stored for |subscription|, then [=queue a global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with an {{"InvalidStateError"}} {{DOMException}} and terminate these steps.
      4. [=Queue a global task=] on the [=networking task source=] using |global| to [=resolve=] |promise| with |subscription| and terminate these steps.
    7. [=/Assert=]: |subscription| is null and |scope| is a [=/URL=].
    8. Set |subscription| to the result of trying to [=create a push subscription=] with |options|. If creating the subscription [=exception/throws=] an [=exception=], [=queue a global task=] on the [=networking task source=] using |global| to [=reject=] |promise| with a that [=exception=] and terminate these steps.
    9. Set |subscription|'s [=push subscription/scope=] to |scope|.
    10. [=Queue a global task=] on the [=networking task source=] using |global| to [=resolve=] |promise| with a {{PushSubscription}} corresponding to |subscription|.
  12. Return |promise|.

ThegetSubscription() method steps are:

  1. Let |promise| bea new promise.
  2. Let |global| be [=this=]'s [=relevant global object=].
  3. Let |windowScope| be null.
  4. Let |registration| be null.
  5. If [=this=]'s [=PushManager/service worker registration=] is null, then set |windowScope| to the result of running the [=basic URL parser=] given "`/`" and |global|'sassociatedDocument's [=Document/URL=].
  6. Otherwise:
    1. [=/Assert=]: [=this=]'s [=PushManager/service worker registration=] is a [=service worker registration=].
    2. Set |registration| to [=this=]'s [=PushManager/service worker registration=].
  7. Run these steps [=/in parallel=]:
    1. Let |subscription| be null.
    2. If |windowScope| is non-null:
      1. If there is a [=push subscription=] whose [=push subscription/scope=] is |windowScope|, then set |subscription| to that [=push subscription=].
    3. Otherwise:
      1. [=/Assert=]: |registration| is non-null.
      2. If |registration|'s [=associated push subscription=] is non-null, then set |subscription| to |registration|'s [=associated push subscription=].
    4. If |subscription| is null, then resolve |promise| with null.
    5. If there is an error with |subscription|, reject |promise| with a {{DOMException}} whose name is {{"AbortError"}} and terminate these steps.
    6. Resolve |promise| with a {{PushSubscription}} corresponding to |subscription|.
  8. Return |promise|.

ThepermissionState() method when invoked MUST run the following steps:

  1. Let |promise| bea new promise.
  2. Return |promise| and continue the following steps asynchronously.
  3. Let |descriptor| be a new {{PermissionDescriptor}} with the {{PermissionDescriptor/name}} initialized to "push".
  4. let |state| be the [=permission state=] of |descriptor| and the result.
  5. Resolve |promise| with |state|.

Permission to use the push service can be persistent, that is, it does not need to be reconfirmed for subsequent subscriptions if a valid permission exists.

If there is a need to ask for permission, it needs to be done by invoking the {{PushManager/subscribe()}} method.

PushSubscriptionOptions Interface

          [Exposed=(Window,Worker), SecureContext]          interface PushSubscriptionOptions {            readonly attribute boolean userVisibleOnly;            [SameObject] readonly attribute ArrayBuffer? applicationServerKey;          };

TheuserVisibleOnly attribute, when getting, returns the value it was initialized with.

TheapplicationServerKey attribute, when getting, returns the value it was initialized with.

If present, the value of {{PushSubscriptionOptions/applicationServerKey}} MUST include a point on the P-256 elliptic curve [[DSS]], encoded in the uncompressed form described in [[ANSI-X9-62]] Annex A (that is, 65 octets, starting with an 0x04 octet). When provided as a {{DOMString}}, the value MUST be encoded using the base64url encoding [[RFC7515]].

User agents MAY reject a subscription attempt when {{PushSubscriptionOptions/applicationServerKey}} is not present and thepush service requires one for operational reasons.

The {{PushSubscriptionOptions/applicationServerKey}} MUST be a different value to the one used for message encryption [[RFC8291]].

PushSubscriptionOptionsInit dictionary

          dictionary PushSubscriptionOptionsInit {            boolean userVisibleOnly = false;            (BufferSource or DOMString)? applicationServerKey = null;          };

TheuserVisibleOnly member, when set to `true`, indicates that thepush subscription will only be used forpush messages whose effect is made visible to the user, for example by displaying a Web Notification. [[NOTIFICATIONS]]

APushSubscriptionOptionsInit represents additional options associated with apush subscription. Theuser agent MAY consider these options when requestingexpress permission from the user. When an option is considered, theuser agent SHOULD enforce it on incomingpush messages.

These options are optional, anduser agents MAY choose to support only a subset of them. Auser agent MUST NOT expose options that it does not support.

Once set, options for apush subscription cannot change. A pre-existingpush subscription can be unsubscribed, via {{PushSubscription/unsubscribe}}, to create apush subscription with new options.

TheapplicationServerKey member is used by theuser agent when establishing apush subscription with apush service. The {{PushSubscriptionOptions/applicationServerKey}} option includes an elliptic curve public key for anapplication server. This is the key that theapplication server will use to authenticate itself when sendingpush messages to thispush subscription as defined in [[RFC8292]]; thepush service will reject anypush message unless the corresponding private key is used to generate an authentication token.

PushSubscription interface

A {{PushSubscription}} object represents apush subscription.

        [Exposed=(Window,Worker), SecureContext]        interface PushSubscription {          readonly attribute USVString endpoint;          readonly attribute EpochTimeStamp? expirationTime;          [SameObject] readonly attribute PushSubscriptionOptions options;          ArrayBuffer? getKey(PushEncryptionKeyName name);          Promise<boolean> unsubscribe();          PushSubscriptionJSON toJSON();        };        dictionary PushSubscriptionJSON {          USVString endpoint;          EpochTimeStamp? expirationTime = null;          record<DOMString, USVString> keys;        };

Whengetting the `endpoint` attribute, theuser agent MUST return thepush endpoint associated with thepush subscription. Theuser agent MUST use a serialization method that does not contain input-dependent branches (that is, one that is constant time).

Whengetting the `expirationTime` attribute, theuser agent MUST return thesubscription expiration time associated with thepush subscription if there is one, or `null` otherwise.

When getting theoptions attribute, theuser agent MUST return aPushSubscriptionOptions object representing the options associated with thepush subscription.

ThegetKey() method retrieves keying material that can be used for encrypting and authenticating messages. When {{PushSubscription/getKey()}} is invoked the following process is followed:

  1. Find the internal slot corresponding to the key named by the `name` argument.
  2. If a slot was not found, return `null`.
  3. Initialize a variable |key| with a newly instantiated {{ArrayBuffer}} instance.
  4. If the internal slot contains an asymmetric key pair, set the contents of |key| to the serialized value of the public key from the key pair. This uses the serialization format described in the specification that defines the name. For example, [[RFC8291]] specifies that the {{PushEncryptionKeyName/"p256dh"}} public key is encoded using the uncompressed format defined in [[ANSI-X9-62]] Annex A (that is, a 65 octet sequence that starts with a 0x04 octet).
  5. Otherwise, if the internal slot contains a symmetric key, set the contents of |key| to a copy of the value from the internal slot. For example, the `auth` parameter contains an octet sequence used by theuser agent to authenticate messages sent by anapplication server.
  6. Return |key|.

Keys named {{PushEncryptionKeyName/"p256dh"}} and {{PushEncryptionKeyName/"auth"}} MUST be supported, and their values MUST correspond to those necessary for the user agent to decrypt received push messages in accordance with [[RFC8291]].

Theunsubscribe() method when invoked MUST run the following steps:

  1. Let |promise| bea new promise.
  2. Return |promise| and continue the following steps asynchronously.
  3. If thepush subscription has already beendeactivated, resolve |promise| with `false` and terminate these steps.
  4. Run the following step in parallel:
    1. Deactivate thepush subscription. Theuser agent MUST NOT deliver any furtherpush messages for thepush subscription.

      If theuser agent failed to request thepush service todeactivate thepush subscription, for example because of network failures, it SHOULD retry the request to thepush service for a reasonable amount of time.

  5. Resolve |promise| with `true`.

ThetoJSON() method when invoked MUST run the following steps:

  1. Let |json:PushSubscriptionJSON| be a new {{PushSubscriptionJSON}} dictionary.
  2. Set |json|["endpoint"] to the result of [=getting the `endpoint` attribute=] of [=this=].
  3. Set |json|["expirationTime"] to the result of [=getting the `expirationTime` attribute=] of [=this=].
  4. Let |keys| be a new empty instance of `record<DOMString, USVString>` .
  5. For each identifier |i| corresponding to keys in internal slots on the {{PushSubscription}}, ordered by the name of the key:
    1. If the internal slot corresponds to an asymmetric key pair, let |b| be the encoded value of the public key corresponding to the key name |i|, using the encoding defined for the key name (see {{PushSubscription/getKey()}}).
    2. Otherwise, let |b| be the value as returned by {{PushSubscription/getKey}}.
    3. Let |s| be the URL-safe base64 encoding without padding [[RFC4648]] of |b| as a {{USVString}}. Theuser agent MUST use a serialization method that does not branch based on the value of |b|.
    4. Set |keys|[|i|] to |s|.
  6. Set |json|["keys"] to |keys|.
  7. Return |json|.

APushSubscriptionJSON dictionary represents theJSON type of a {{PushSubscription}}. In ECMAScript this can be converted into a JSON string through the `JSON`.{{JSON/stringify()}} function.

Thekeys record contains an entry for each of the supported {{PushEncryptionKeyName}} entries to the URL-safe base64 encoded representation [[RFC4648]] of its value.

Note that the options to a {{PushSubscription}} are not serialized.

PushEncryptionKeyName enumeration

Encryption keys used forpush message encryption are provided to a web application through the {{PushSubscription/getKey()}} method or the serializer of {{PushSubscription}}. Each key is named using a value from the {{PushEncryptionKeyName}} enumeration.

          enum PushEncryptionKeyName {            "p256dh",            "auth"          };

Thep256dh value is used to retrieve the P-256 ECDH Diffie-Hellman public key described in [[RFC8291]].

Theauth value is used to retrieve the authentication secret described in [[RFC8291]].

PushMessageData interface

        [Exposed=ServiceWorker, SecureContext]        interface PushMessageData {          ArrayBuffer arrayBuffer();          Blob blob();          Uint8Array bytes();          any json();          USVString text();        };

{{PushMessageData}} objects have an associatedbytes (a [=byte sequence=]), which is set on creation.

ThearrayBuffer() method steps are to return an {{ArrayBuffer}} whose contents are [=this=]'s [=bytes=]. Exceptions thrown during the creation of the {{ArrayBuffer}} object are re-thrown.

Theblob() method steps are to return a new {{Blob}} object whose contents are [=this=]'s [=bytes=].

Thebytes() method steps are to return a new {{Uint8Array}} backed by a {{ArrayBuffer}} whose contents are [=this=]'s [=bytes=]. Exceptions thrown during the creation of the {{ArrayBuffer}} object are re-thrown.

Thejson() method steps are to return the result of [=parse JSON bytes to a JavaScript value|parsing JSON bytes to a JavaScript value=] given [=this=]'s [=bytes=].

Thetext() method steps are to return the result of runningUTF-8 decode on [=this=]'s [=bytes=].

Toextract a byte sequence from |object|, run these steps:

  1. Let |bytes| be an empty byte sequence.
  2. Switch on |object|'s type:
    {{BufferSource}}
    Set |bytes| to a copy of |object|'s contents.
    {{USVString}}
    Set |bytes| to the result of runningutf-8 encode on |object|.
  3. Return |bytes|.

Events

Extensions to the `ServiceWorkerGlobalScope` interface

The Service Worker specification defines a {{ServiceWorkerGlobalScope}} interface [[SERVICE-WORKERS]], which this specification extends.

          [Exposed=ServiceWorker, SecureContext]          partial interface ServiceWorkerGlobalScope {            attribute EventHandler onpush;            attribute EventHandler onpushsubscriptionchange;          };

Theonpush attribute is anevent handler IDL attribute whose correspondingevent handler event type is "`push`". The "`push`" event indicates that apush message has been received for apush subscription.

Theonpushsubscriptionchange attribute is anevent handler IDL attribute whose correspondingevent handler event type is "`pushsubscriptionchange`".

PushEvent Interface

            [Exposed=ServiceWorker, SecureContext]            interface PushEvent : ExtendableEvent {              constructor(DOMString type, optional PushEventInit eventInitDict = {});              readonly attribute PushMessageData? data;              readonly attribute Notification? notification;            };            dictionary PushEventInit : ExtendableEventInit {              PushMessageDataInit? data = null;              Notification? notification = null;            };            typedef (BufferSource or USVString) PushMessageDataInit;

When aconstructor of thePushEvent interface, or of an interface that inherits from thePushEvent interface, is invoked, the usualevent constructing steps are extended to include the following steps:

  1. If |eventInitDict|'s `data` member is not present, set the `data` attribute of the event to `null` and terminate these steps.
  2. Set |b| to the result ofextracting a byte sequence from the "`data`" member of |eventInitDict|.
  3. Set the `data` attribute of the event to a new {{PushMessageData}} instance whose [=PushMessageData/bytes=] is |b|.

Thedata attribute must return the value it was initialized with.

Thenotification attribute must return the value it was initialized with.

Receiving aPush Message

When theuser agent receives apush message from thepush service, it MUST run the following steps.

  1. Let |subscription| be the activepush subscription corresponding to thepush message.

  2. Let |registration| be |subscription|'s [=push subscription/associated service worker registration=].

  3. Let |bytes| be null.

  4. If thepush message contains a payload:

    1. Decrypt thepush message's payload using the private key from the key pair associated with |subscription| and the process described in [[RFC8291]]. Set |bytes| to the resulting [=/byte sequence=].

    2. If thepush message payload could not be decrypted for any reason, then [=acknowledge a push message|acknowledge=] thepush message and abort these steps.

      A `push` event is not fired for apush message that was not successfully decrypted using the key pair associated with thepush subscription.

  5. If |bytes| is non-null:

    1. Let |baseURL| be |subscription|'s [=push subscription/scope=].

    2. Let |origin| be |baseURL|'s [=url/origin=].

    3. Let |fallbackTimestamp| be [=current coarsened wall time=].

    4. Let |declarativeResult| be the result of running the [=/declarative push message parser=] given |bytes|, |origin|, |baseURL|, and |fallbackTimestamp|.

    5. If |declarativeResult| is not failure:

      1. Let |notification| be |declarativeResult|'s [=declarative push message parser result/notification=].

      2. Set |notification|'s [=notification/service worker registration=] to |registration|.

      3. Let |notificationShown| be false.

      4. If |declarativeResult|'s [=declarative push message parser result/mutable=] is true and |registration| is non-null:

        1. Let |result| be the result of [=fire a push event|firing a push event=] given |registration|, null, and a new {{Notification}} object representing |notification|.

        2. If |result| is not failure, then set |notificationShown| to |result|'s [=push event result/notification shown=].

      5. If |notificationShown| is false, then run the [=notification show steps=] given |notification|.

      6. [=acknowledge a push message|Acknowledge=] thepush message and abort these steps.

  6. If |registration| is null, then abort these steps.

  7. Let |data| be a new {{PushMessageData}} object whose [=PushMessageData/bytes=] is |bytes| if |bytes| is non-null; otherwise null.

  8. Let |result| be the result of [=fire a push event|firing a push event=] given |registration|, |data|, and null.

  9. Ifresult is failure and the samepush message has been delivered to aservice worker registration multiple times unsuccessfully, then [=acknowledge a push message|acknowledge=] thepush message.

  10. Ifresult is not failure, then [=acknowledge a push message|acknowledge=] thepush message.

Apush event result is a [=/tuple=] consisting of anotification shown (a [=/boolean=]).

Tofire a push event given a [=/service worker registration=] |registration|, {{PushMessageData}} object or null |data|, and a [=/notification=] or null |notification|, run these steps. They return failure or a [=/push event result=].

  1. Let |notificationResult| be null.

  2. Set |registration|'s [=service worker registration/has shownotification() been successfully invoked|has `showNotification()` been successfully invoked=] to false.

  3. Fire a functional event named "`push`" usingPushEvent on |registration| with the following properties:

    {{PushEvent/data}}
    |data|
    {{PushEvent/notification}}
    |notification|

    Then run the following steps in parallel, with |dispatchedEvent|:

    1. Wait for all of the promises in the [=ExtendableEvent/extend lifetime promises=] of |dispatchedEvent| to resolve.

    2. If they do not resolve successfully, then set |notificationResult| to failure.

    3. Otherwise, set |notificationResult| to |registration|'s [=service worker registration/has shownotification() been successfully invoked|has `showNotification()` been successfully invoked=].

  4. Wait for |notificationResult| to be non-null.

  5. If |notificationResult| is failure, then return failure.

  6. [=/Assert=]: |notificationResult| is a [=/boolean=].

  7. Return (|notificationResult|).

Toacknowledge a push message given apush messagepushMessage means to acknowledge the receipt ofpushMessage according to [[RFC8030]].

Acknowledging thepush message causes thepush service to stop delivering the message and to report success to theapplication server. This prevents the samepush message from being retried by thepush service indefinitely.

Acknowledging also means that anapplication server could incorrectly receive a delivery receipt indicating successful delivery of thepush message. Therefore, multiple rejections SHOULD be permitted before acknowledging; allowing at least three attempts is recommended.

Thepushsubscriptionchange Event

Thepushsubscriptionchange event indicates a change in apush subscription that was triggered outside of the application's control, for example because it has been refreshed, revoked or lost.

Tofire the "`pushsubscriptionchange`" event given aservice worker registration of |registration|, |newSubscription| and |oldSubscription|, theuser agent mustfire a functional event named "`pushsubscriptionchange`" usingPushSubscriptionChangeEvent on |registration| with the following properties:

`newSubscription`
|newSubscription|
`oldSubscription`
|oldSubscription|

Consider using a more reliable synchronization mechanism such as [[WEB-BACKGROUND-SYNC]] when sending the details of the newpush subscription to yourapplication server. The user might be subject to unreliable network conditions that could cause a fetch to fail.

PushSubscriptionChangeEvent Interface

            [Exposed=ServiceWorker, SecureContext]            interface PushSubscriptionChangeEvent : ExtendableEvent {              constructor(DOMString type, optional PushSubscriptionChangeEventInit eventInitDict = {});              readonly attribute PushSubscription? newSubscription;              readonly attribute PushSubscription? oldSubscription;            };

ThenewSubscription attribute, when getting, returns the value it was initialized to.

TheoldSubscription attribute, when getting, returns the value it was initialized to.

PushSubscriptionChangeEventInit Interface

              dictionary PushSubscriptionChangeEventInit : ExtendableEventInit {                PushSubscription newSubscription = null;                PushSubscription oldSubscription = null;              };

ThenewSubscription member details thepush subscription that is valid per invocation of thepushsubscriptionchange event. The value will be `null` when no newpush subscription could be established, for example because the web application has lostexpress permission.

TheoldSubscription member details thepush subscription that SHOULD NOT be used anymore. The value will be `null` when theuser agent is not able to provide the full set of details, for example because of partial database corruption.

Accessibility

ThePush API does not provide any means itself to present data it receives from a [=push service=]. Instead, thePush API relies on other APIs – primarily the [[[NOTIFICATIONS]]] – to present received information to an end user. As such, there are no accessibility requirements for thePush API itself. However, specifications such as [[NOTIFICATIONS]] provide guidance how to present notifications in an accessible manner.

Further, presenting an accessible interface might depend on transferring more information than a push message can convey. Push messages are best suited to carrying small amounts of content or identifiers. Any larger resources need to be fetched from servers.

This specification defines conformance criteria that apply to a single product: theuser agent that implements the interfaces that it contains.

Acknowledgements

The editors would like to express their gratitude to the Mozilla and Telefónica Digital teams implementing the Firefox OS Push message solution, as well as to the following people who provided significant technical input to this document: Antonio Amaya, Miguel García Arribas, Ben Bangert, Kit Cambridge, José Manuel Cantera, JR Conlin, Albert Crespell, Matt Gaunt, Phil Jenvey, Guillermo López, Nikhil Marathe, John Mellor, Pınar Özlen, Fernando R. Sela, Shijun Sun and Doug Turner.


[8]ページ先頭

©2009-2025 Movatter.jp