Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
# I am terrible at keeping this up-to-date.

## 2.2.0 (2026-)

- Update `rst` files to reflect `md` file changes

Add comment discussing additional work for Windows Notification Service (WNS)

- Update the README.md file to mention the required, non-standard headers.

_BREAKING_CHANGE_
This version also drops legacy support for GCM/FCM authorization keys, since those items
are obsolete according to Google.
See https://firebase.google.com/docs/cloud-messaging/auth-server#authorize-legacy-protocol-send-requests

## 2.1.2 (2025-11-10)

chore: fix formatting
chore: update CHANGELOG
chore: note admin update
Expand Down
60 changes: 49 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ referenced to the user who requested it, and recall it when there's
a new push subscription update is left as an exercise for the
reader.

_*Note:*_ Some platforms (like Microsoft Windows) require additional
headers specified for the Push call. These additional headers are not
standard and may be rejected by other Push services. Please see
[Special Instructions](#special-instructions) below.

### Sending Data using `webpush()` One Call

In many cases, your code will be sending a single message to many
Expand All @@ -53,7 +58,7 @@ webpush(subscription_info,
This will encode `data`, add the appropriate VAPID auth headers if required and send it to the push server identified
in the `subscription_info` block.

##### Parameters
#### Parameters

_subscription_info_ - The `dict` of the subscription info (described above).

Expand All @@ -78,7 +83,7 @@ e.g. the output of:
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
```

##### Example
#### Example

```python
from pywebpush import webpush, WebPushException
Expand Down Expand Up @@ -116,7 +121,7 @@ can pass just `wp = WebPusher(subscription_info)`. This will return a `WebPusher

The following methods are available:

#### `.send(data, headers={}, ttl=0, gcm_key="", reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)`
#### `.send(data, headers={}, ttl=0, reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)`

Send the data using additional parameters. On error, returns a `WebPushException`

Expand All @@ -128,9 +133,6 @@ _headers_ A `dict` containing any additional headers to send

_ttl_ Message Time To Live on Push Server waiting for the client to reconnect (in seconds)

_gcm_key_ Google Cloud Messaging key (if using the older GCM push system) This is the API key obtained from the Google
Developer Console.

_reg_id_ Google Cloud Messaging registration ID (will be extracted from endpoint if not specified)

_content_encoding_ ECE content encoding type (defaults to "aes128gcm")
Expand All @@ -143,10 +145,10 @@ See [requests documentation](http://docs.python-requests.org/en/master/user/quic

##### Example

to send from Chrome using the old GCM mode:
to send to a user on Chrome:

```python
WebPusher(subscription_info).send(data, headers, ttl, gcm_key)
WebPusher(subscription_info).send(data, headers, ttl)
```

#### `.encode(data, content_encoding="aes128gcm")`
Expand All @@ -159,7 +161,7 @@ _data_ Binary string of data to send

_content_encoding_ ECE content encoding type (defaults to "aes128gcm")

*Note* This will return a `NoData` exception if the data is not present or empty. It is completely
_*Note*_ This will return a `NoData` exception if the data is not present or empty. It is completely
valid to send a WebPush notification with no data, but encoding is a no-op in that case. Best not
to call it if you don't have data.

Expand All @@ -171,8 +173,7 @@ encoded_data = WebPush(subscription_info).encode(data)

## Stand Alone Webpush

If you're not really into coding your own solution, there's also a "stand-alone" `pywebpush` command in the
./bin directory.
If you're not really into coding your own solution, there's also a "stand-alone" `pywebpush` command in the `./bin` directory.

This uses two files:

Expand All @@ -198,3 +199,40 @@ If you're interested in just testing your applications WebPush interface, you co
which will encrypt and send the contents of `stuff_to_send.data`.

See `./bin/pywebpush --help` for available commands and options.

## Special Instructions

### Windows

[Microsoft requires](https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/push-request-response-headers#request-parameters)
one extra header and suggests several additional headers. Users have reported that not including
these headers can cause notifications to fail to appear. These additional headers are non-standard
and may be rejected by other platforms. You should be cautious including them with calls to
non-Microsoft platforms, or to non-Microsoft destinations.

As of 2024-Apr-19, Microsoft requires an `X-WNS-Type` header. As an example, you can include this
header within the command line call:

Content of the `windows_headers.json` file:

```json
{"X-WNS-Type":"wns/toast", "TTL":600, "Content-Type": "text/xml"}
```

_*Note*_ : This includes both the `TTL` set to 10 minutes and the required matching `Content-Type` header for `wns/toast`.

```bash
pywebpush --data stuff_to_send.xml \
--info edge_user_info.json \
--head windows_headers.json \
--claims vapid_claims.json
```

### Google Cloud Messaging (GCM)

Please note that GCM has been sunset by Google. Providers should
use [Firebase Cloud Messaging](https://firebase.google.com/support/troubleshooter/fcm/tokens/gcm) instead.

Please also note that sending messages directly to FCM is not supported by this library. In the past, you could use an insecure `gcm_key` as a proxy for the authentication service. [This was disabled in June 2024](https://firebase.google.com/docs/cloud-messaging/auth-server#authorize-legacy-protocol-send-requests).

Sending WebPush messages to Google Chrome users should not be impacted by this change.
132 changes: 99 additions & 33 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
Webpush Data encryption library for Python
==========================================

|Build Status| |Requirements Status|

This library is available on `pypi as
pywebpush <https://pypi.python.org/pypi/pywebpush>`__. Source is
available on `github <https://github.com/mozilla-services/pywebpush>`__.
Expand All @@ -14,12 +12,8 @@ make of that what you will.
Installation
------------

You’ll need to run ``python -m venv venv``. Then

.. code:: bash

venv/bin/pip install -r requirements.txt
venv/bin/python -m pip install -e .
To work with this repo locally, you’ll need to run
``python -m venv venv``. Then ``venv/bin/pip install --editable .``

Usage
-----
Expand All @@ -35,12 +29,20 @@ As illustration, a ``subscription_info`` object may look like:

.. code:: json

{"endpoint": "https://updates.push.services.mozilla.com/push/v1/gAA...", "keys": {"auth": "k8J...", "p256dh": "BOr..."}}
{
"endpoint": "https://updates.push.services.mozilla.com/push/v1/gAA...",
"keys": { "auth": "k8J...", "p256dh": "BOr..." }
}

How you send the PushSubscription data to your backend, store it
referenced to the user who requested it, and recall it when there’s a
new push subscription update is left as an exercise for the reader.

*Note:* Some platforms (like Microsoft Windows) require additional
headers specified for the Push call. These additional headers are not
standard and may be rejected by other Push services. Please see `Special
Instructions <#special-instructions>`__ below.

Sending Data using ``webpush()`` One Call
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand All @@ -60,7 +62,8 @@ This will encode ``data``, add the appropriate VAPID auth headers if
required and send it to the push server identified in the
``subscription_info`` block.

**Parameters**
Parameters
^^^^^^^^^^

*subscription_info* - The ``dict`` of the subscription info (described
above).
Expand All @@ -78,7 +81,9 @@ standard form.
authorization (See
`py_vapid <https://github.com/web-push-libs/vapid/tree/master/python>`__
for more details). If ``aud`` is not specified, pywebpush will attempt
to auto-fill from the ``endpoint``.
to auto-fill from the ``endpoint``. If ``exp`` is not specified or set
in the past, it will be set to 12 hours from now. In both cases, the
passed ``dict`` **will be mutated** after the call.

*vapid_private_key* - Either a path to a VAPID EC2 private key PEM file,
or a string containing the DER representation. (See
Expand All @@ -93,7 +98,8 @@ e.g. the output of:

openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem

**Example**
Example
^^^^^^^

.. code:: python

Expand Down Expand Up @@ -134,13 +140,16 @@ object.

The following methods are available:

``.send(data, headers={}, ttl=0, gcm_key="", reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
``.send(data, headers={}, ttl=0, reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Send the data using additional parameters. On error, returns a
``WebPushException``

**Parameters**
.. _parameters-1:

Parameters
''''''''''

*data* Binary string of data to send

Expand All @@ -149,9 +158,6 @@ Send the data using additional parameters. On error, returns a
*ttl* Message Time To Live on Push Server waiting for the client to
reconnect (in seconds)

*gcm_key* Google Cloud Messaging key (if using the older GCM push
system) This is the API key obtained from the Google Developer Console.

*reg_id* Google Cloud Messaging registration ID (will be extracted from
endpoint if not specified)

Expand All @@ -165,27 +171,41 @@ purposes.
*timeout* timeout for requests POST query. See `requests
documentation <http://docs.python-requests.org/en/master/user/quickstart/#timeouts>`__.

**Example**
.. _example-1:

to send from Chrome using the old GCM mode:
Example
'''''''

to send to a user on Chrome:

.. code:: python

WebPusher(subscription_info).send(data, headers, ttl, gcm_key)
WebPusher(subscription_info).send(data, headers, ttl)

``.encode(data, content_encoding="aes128gcm")``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Encode the ``data`` for future use. On error, returns a
``WebPushException``

**Parameters**
.. _parameters-2:

Parameters
''''''''''

*data* Binary string of data to send

*content_encoding* ECE content encoding type (defaults to “aes128gcm”)

**Example**
*Note* This will return a ``NoData`` exception if the data is not
present or empty. It is completely valid to send a WebPush notification
with no data, but encoding is a no-op in that case. Best not to call it
if you don’t have data.

.. _example-2:

Example
'''''''

.. code:: python

Expand All @@ -195,7 +215,7 @@ Stand Alone Webpush
-------------------

If you’re not really into coding your own solution, there’s also a
“stand-alone” ``pywebpush`` command in the ./bin directory.
“stand-alone” ``pywebpush`` command in the ``./bin`` directory.

This uses two files:

Expand All @@ -207,11 +227,13 @@ This uses two files:

.. code:: json

{"endpoint": "https://push...",
"keys": {
"auth": "ab01...",
"p256dh": "aa02..."
}}
{
"endpoint": "https://push...",
"keys": {
"auth": "ab01...",
"p256dh": "aa02..."
}
}

If you’re interested in just testing your applications WebPush
interface, you could use the Command Line:
Expand All @@ -224,7 +246,51 @@ which will encrypt and send the contents of ``stuff_to_send.data``.

See ``./bin/pywebpush --help`` for available commands and options.

.. |Build Status| image:: https://travis-ci.org/web-push-libs/pywebpush.svg?branch=main
:target: https://travis-ci.org/web-push-libs/pywebpush
.. |Requirements Status| image:: https://requires.io/github/web-push-libs/pywebpush/requirements.svg?branch=main
:target: https://requires.io/github/web-push-libs/pywebpush/requirements/?branch=main
Special Instructions
--------------------

Windows
~~~~~~~

`Microsoft
requires <https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/push-request-response-headers#request-parameters>`__
one extra header and suggests several additional headers. Users have
reported that not including these headers can cause notifications to
fail to appear. These additional headers are non-standard and may be
rejected by other platforms. You should be cautious including them with
calls to non-Microsoft platforms, or to non-Microsoft destinations.

As of 2024-Apr-19, Microsoft requires an ``X-WNS-Type`` header. As an
example, you can include this header within the command line call:

Content of the ``windows_headers.json`` file:

.. code:: json

{"X-WNS-Type":"wns/toast", "TTL":600, "Content-Type": "text/xml"}

*Note* : This includes both the ``TTL`` set to 10 minutes and the
required matching ``Content-Type`` header for ``wns/toast``.

.. code:: bash

pywebpush --data stuff_to_send.xml \
--info edge_user_info.json \
--head windows_headers.json \
--claims vapid_claims.json

Google Cloud Messaging (GCM)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Please note that GCM has been sunset by Google. Providers should use
`Firebase Cloud
Messaging <https://firebase.google.com/support/troubleshooter/fcm/tokens/gcm>`__
instead.

Please also note that sending messages directly to FCM is not supported
by this library. In the past, you could use an insecure ``gcm_key`` as a
proxy for the authentication service. `This was disabled in June
2024 <https://firebase.google.com/docs/cloud-messaging/auth-server#authorize-legacy-protocol-send-requests>`__.

Sending WebPush messages to Google Chrome users should not be impacted
by this change.
Loading