2017-05-10 00:01:38 +02:00
|
|
|
|
|Build Status| |Requirements Status|
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
|
|
|
|
Webpush Data encryption library for Python
|
|
|
|
|
==========================================
|
|
|
|
|
|
|
|
|
|
This is a work in progress. This library is available on `pypi as
|
|
|
|
|
pywebpush <https://pypi.python.org/pypi/pywebpush>`__. Source is
|
2017-03-08 02:05:57 +01:00
|
|
|
|
available on `github <https://github.com/mozilla-services/pywebpush>`__.
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
|
|
|
|
Installation
|
|
|
|
|
------------
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
You’ll need to run ``python virtualenv``. Then
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2017-05-11 10:59:40 +02:00
|
|
|
|
::
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
bin/pip install -r requirements.txt
|
|
|
|
|
bin/python setup.py develop
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
|
|
|
|
Usage
|
|
|
|
|
-----
|
|
|
|
|
|
|
|
|
|
In the browser, the promise handler for
|
|
|
|
|
`registration.pushManager.subscribe() <https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe>`__
|
|
|
|
|
returns a
|
|
|
|
|
`PushSubscription <https://developer.mozilla.org/en-US/docs/Web/API/PushSubscription>`__
|
|
|
|
|
object. This object has a .toJSON() method that will return a JSON
|
|
|
|
|
object that contains all the info we need to encrypt and push data.
|
|
|
|
|
|
2017-03-08 02:05:57 +01:00
|
|
|
|
As illustration, a ``subscription_info`` object may look like:
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2017-03-08 02:05:57 +01:00
|
|
|
|
.. code:: json
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
{"endpoint": "https://updates.push.services.mozilla.com/push/v1/gAA...", "keys": {"auth": "k8J...", "p256dh": "BOr..."}}
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
|
|
|
|
How you send the PushSubscription data to your backend, store it
|
2021-03-16 15:51:54 +01:00
|
|
|
|
referenced to the user who requested it, and recall it when there’s a
|
2017-03-08 02:05:57 +01:00
|
|
|
|
new push subscription update is left as an exercise for the reader.
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2017-03-08 02:05:57 +01:00
|
|
|
|
Sending Data using ``webpush()`` One Call
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
In many cases, your code will be sending a single message to many
|
2021-03-16 15:51:54 +01:00
|
|
|
|
recipients. There’s a “One Call” function which will make things easier.
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
2017-05-11 10:59:40 +02:00
|
|
|
|
.. code:: python
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
from pywebpush import webpush
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
webpush(subscription_info,
|
|
|
|
|
data,
|
|
|
|
|
vapid_private_key="Private Key or File Path[1]",
|
|
|
|
|
vapid_claims={"sub": "mailto:YourEmailAddress"})
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
|
|
|
|
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**
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
*subscription_info* - The ``dict`` of the subscription info (described
|
2017-03-08 02:05:57 +01:00
|
|
|
|
above).
|
|
|
|
|
|
|
|
|
|
*data* - can be any serial content (string, bit array, serialized JSON,
|
2017-02-07 00:45:18 +01:00
|
|
|
|
etc), but be sure that your receiving application is able to parse and
|
2021-03-16 15:51:54 +01:00
|
|
|
|
understand it. (e.g. ``data = "Mary had a little lamb."``)
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
*content_type* - specifies the form of Encryption to use, either
|
2019-01-04 22:58:32 +01:00
|
|
|
|
``'aes128gcm'`` or the deprecated ``'aesgcm'``. NOTE that not all User
|
|
|
|
|
Agents can decrypt ``'aesgcm'``, so the library defaults to the RFC 8188
|
|
|
|
|
standard form.
|
2017-05-10 00:01:38 +02:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
*vapid_claims* - a ``dict`` containing the VAPID claims required for
|
2017-03-08 02:05:57 +01:00
|
|
|
|
authorization (See
|
2021-03-16 15:51:54 +01:00
|
|
|
|
`py_vapid <https://github.com/web-push-libs/vapid/tree/master/python>`__
|
2017-05-10 00:01:38 +02:00
|
|
|
|
for more details). If ``aud`` is not specified, pywebpush will attempt
|
|
|
|
|
to auto-fill from the ``endpoint``.
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
*vapid_private_key* - Either a path to a VAPID EC2 private key PEM file,
|
|
|
|
|
or a string containing the DER representation. (See
|
|
|
|
|
`py_vapid <https://github.com/web-push-libs/vapid/tree/master/python>`__
|
2017-03-08 02:05:57 +01:00
|
|
|
|
for more details.) The ``private_key`` may be a base64 encoded DER
|
|
|
|
|
formatted private key, or the path to an OpenSSL exported private key
|
|
|
|
|
file.
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
e.g. the output of:
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
2017-05-11 10:59:40 +02:00
|
|
|
|
::
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
|
|
|
|
**Example**
|
|
|
|
|
|
2017-05-11 10:59:40 +02:00
|
|
|
|
.. code:: python
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
from pywebpush import webpush, WebPushException
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
webpush(
|
|
|
|
|
subscription_info={
|
|
|
|
|
"endpoint": "https://push.example.com/v1/12345",
|
|
|
|
|
"keys": {
|
|
|
|
|
"p256dh": "0123abcde...",
|
|
|
|
|
"auth": "abc123..."
|
|
|
|
|
}},
|
|
|
|
|
data="Mary had a little lamb, with a nice mint jelly",
|
|
|
|
|
vapid_private_key="path/to/vapid_private.pem",
|
|
|
|
|
vapid_claims={
|
|
|
|
|
"sub": "mailto:YourNameHere@example.org",
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
except WebPushException as ex:
|
|
|
|
|
print("I'm sorry, Dave, but I can't do that: {}", repr(ex))
|
|
|
|
|
# Mozilla returns additional information in the body of the response.
|
|
|
|
|
if ex.response and ex.response.json():
|
|
|
|
|
extra = ex.response.json()
|
|
|
|
|
print("Remote service replied with a {}:{}, {}",
|
|
|
|
|
extra.code,
|
|
|
|
|
extra.errno,
|
|
|
|
|
extra.message
|
|
|
|
|
)
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2017-03-08 02:05:57 +01:00
|
|
|
|
Methods
|
|
|
|
|
~~~~~~~
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2017-03-08 02:05:57 +01:00
|
|
|
|
If you expect to resend to the same recipient, or have more needs than
|
|
|
|
|
just sending data quickly, you can pass just
|
|
|
|
|
``wp = WebPusher(subscription_info)``. This will return a ``WebPusher``
|
|
|
|
|
object.
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2017-03-08 02:05:57 +01:00
|
|
|
|
The following methods are available:
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2019-01-04 22:58:32 +01:00
|
|
|
|
``.send(data, headers={}, ttl=0, gcm_key="", reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)``
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2017-03-08 02:05:57 +01:00
|
|
|
|
Send the data using additional parameters. On error, returns a
|
|
|
|
|
``WebPushException``
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2017-03-08 02:05:57 +01:00
|
|
|
|
**Parameters**
|
|
|
|
|
|
|
|
|
|
*data* Binary string of data to send
|
|
|
|
|
|
|
|
|
|
*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)
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
*gcm_key* Google Cloud Messaging key (if using the older GCM push
|
2017-03-08 02:05:57 +01:00
|
|
|
|
system) This is the API key obtained from the Google Developer Console.
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
*reg_id* Google Cloud Messaging registration ID (will be extracted from
|
2017-03-08 02:05:57 +01:00
|
|
|
|
endpoint if not specified)
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
*content_encoding* ECE content encoding type (defaults to “aes128gcm”)
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
|
|
|
|
*curl* Do not execute the POST, but return as a ``curl`` command. This
|
|
|
|
|
will write the encrypted content to a local file named
|
|
|
|
|
``encrpypted.data``. This command is meant to be used for debugging
|
|
|
|
|
purposes.
|
|
|
|
|
|
2017-12-05 00:31:40 +01:00
|
|
|
|
*timeout* timeout for requests POST query. See `requests
|
|
|
|
|
documentation <http://docs.python-requests.org/en/master/user/quickstart/#timeouts>`__.
|
|
|
|
|
|
2017-03-08 02:05:57 +01:00
|
|
|
|
**Example**
|
|
|
|
|
|
|
|
|
|
to send from Chrome using the old GCM mode:
|
|
|
|
|
|
2017-05-11 10:59:40 +02:00
|
|
|
|
.. code:: python
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
WebPusher(subscription_info).send(data, headers, ttl, gcm_key)
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2019-01-04 22:58:32 +01:00
|
|
|
|
``.encode(data, content_encoding="aes128gcm")``
|
|
|
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
|
|
|
|
Encode the ``data`` for future use. On error, returns a
|
|
|
|
|
``WebPushException``
|
|
|
|
|
|
|
|
|
|
**Parameters**
|
|
|
|
|
|
|
|
|
|
*data* Binary string of data to send
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
*content_encoding* ECE content encoding type (defaults to “aes128gcm”)
|
2017-03-08 02:05:57 +01:00
|
|
|
|
|
|
|
|
|
**Example**
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2017-05-11 10:59:40 +02:00
|
|
|
|
.. code:: python
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
encoded_data = WebPush(subscription_info).encode(data)
|
2017-02-07 00:45:18 +01:00
|
|
|
|
|
2019-05-09 19:05:00 +02:00
|
|
|
|
Stand Alone Webpush
|
|
|
|
|
-------------------
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
If you’re not really into coding your own solution, there’s also a
|
|
|
|
|
“stand-alone” ``pywebpush`` command in the ./bin directory.
|
2019-05-09 19:05:00 +02:00
|
|
|
|
|
|
|
|
|
This uses two files: \* the *data* file, which contains the message to
|
|
|
|
|
send, in whatever form you like. \* the *subscription info* file, which
|
|
|
|
|
contains the subscription information as JSON encoded data. This is
|
|
|
|
|
usually returned by the Push ``subscribe`` method and looks something
|
|
|
|
|
like:
|
|
|
|
|
|
|
|
|
|
.. code:: json
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
{"endpoint": "https://push...",
|
|
|
|
|
"keys": {
|
|
|
|
|
"auth": "ab01...",
|
|
|
|
|
"p256dh": "aa02..."
|
|
|
|
|
}}
|
2019-05-09 19:05:00 +02:00
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
If you’re interested in just testing your applications WebPush
|
2019-05-09 19:05:00 +02:00
|
|
|
|
interface, you could use the Command Line:
|
|
|
|
|
|
|
|
|
|
.. code:: bash
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
./bin/pywebpush --data stuff_to_send.data --info subscription.info
|
2019-05-09 19:05:00 +02:00
|
|
|
|
|
|
|
|
|
which will encrypt and send the contents of ``stuff_to_send.data``.
|
|
|
|
|
|
|
|
|
|
See ``./bin/pywebpush --help`` for available commands and options.
|
|
|
|
|
|
2021-03-16 15:51:54 +01:00
|
|
|
|
.. |Build Status| image:: https://travis-ci.org/web-push-libs/pywebpush.svg?branch=main
|
2017-02-10 14:38:13 +01:00
|
|
|
|
:target: https://travis-ci.org/web-push-libs/pywebpush
|
2021-03-16 15:51:54 +01:00
|
|
|
|
.. |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
|