1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
|
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>`__.
Please note: This library was designated as a ``Critical Project`` by
PyPi, it is currently maintained by `a single
person <https://xkcd.com/2347/>`__. I still accept PRs and Issues, but
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 .
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.
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..."}}
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.
Sending Data using ``webpush()`` One Call
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In many cases, your code will be sending a single message to many
recipients. There’s a “One Call” function which will make things easier.
.. code:: python
from pywebpush import webpush
webpush(subscription_info,
data,
vapid_private_key="Private Key or File Path[1]",
vapid_claims={"sub": "mailto:YourEmailAddress"})
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**
*subscription_info* - The ``dict`` of the subscription info (described
above).
*data* - can be any serial content (string, bit array, serialized JSON,
etc), but be sure that your receiving application is able to parse and
understand it. (e.g. ``data = "Mary had a little lamb."``)
*content_type* - specifies the form of Encryption to use, either
``'aes128gcm'`` or the deprecated ``'aesgcm'``. NOTE that not all User
Agents can decrypt ``'aesgcm'``, so the library defaults to the RFC 8188
standard form.
*vapid_claims* - a ``dict`` containing the VAPID claims required for
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``.
*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>`__
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.
e.g. the output of:
.. code:: bash
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
**Example**
.. code:: python
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 is not None and ex.response.json():
extra = ex.response.json()
print("Remote service replied with a {}:{}, {}",
extra.code,
extra.errno,
extra.message
)
Methods
~~~~~~~
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.
The following methods are available:
``.send(data, headers={}, ttl=0, gcm_key="", reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Send the data using additional parameters. On error, returns a
``WebPushException``
**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)
*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”)
*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.
*timeout* timeout for requests POST query. See `requests
documentation <http://docs.python-requests.org/en/master/user/quickstart/#timeouts>`__.
**Example**
to send from Chrome using the old GCM mode:
.. code:: python
WebPusher(subscription_info).send(data, headers, ttl, gcm_key)
``.encode(data, content_encoding="aes128gcm")``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Encode the ``data`` for future use. On error, returns a
``WebPushException``
**Parameters**
*data* Binary string of data to send
*content_encoding* ECE content encoding type (defaults to “aes128gcm”)
**Example**
.. code:: python
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.
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
{"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:
.. code:: bash
./bin/pywebpush --data stuff_to_send.data --info subscription.info
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
|