Skip to content

Commit caf331d

Browse files
committed
feat: Allow VAPID with [gf]cm
* added primative CLI * dump as curl closes #44
1 parent b6348a6 commit caf331d

File tree

10 files changed

+600
-107
lines changed

10 files changed

+600
-107
lines changed

MANIFEST.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ include *.md
22
include *.txt
33
include setup.*
44
include LICENSE
5-
recursive-include pywebpush
5+
recursive-include pywebpush *.py

README.md

Lines changed: 112 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1-
[![Build_Status](https://travis-ci.org/jrconlin/pywebpush.svg?branch=master)](https://travis-ci.org/jrconlin/pywebpush)
1+
[![Build_Status](https://travis-ci.org/web-push-libs/pywebpush.svg?branch=master)](https://travis-ci.org/web-push-libs/pywebpush)
22
[![Requirements
3-
Status](https://requires.io/github/web-push-libs/pywebpush/requirements.svg?branch=master)]
4-
3+
Status](https://requires.io/github/web-push-libs/pywebpush/requirements.svg?branch=feat%2F44)](https://requires.io/github/web-push-libs/pywebpush/requirements/?branch=master)
54

65
# Webpush Data encryption library for Python
76

87
This is a work in progress.
9-
This library is available on [pypi as
10-
pywebpush](https://pypi.python.org/pypi/pywebpush).
11-
Source is available on [github](https://github.com/jrconlin/pywebpush)
8+
This library is available on [pypi as pywebpush](https://pypi.python.org/pypi/pywebpush).
9+
Source is available on
10+
[github](https://github.com/mozilla-services/pywebpush).
1211

1312
## Installation
1413

1514
You'll need to run `python virtualenv`.
1615
Then
17-
```
16+
```commandline
1817
bin/pip install -r requirements.txt
1918
bin/python setup.py develop
2019
```
@@ -25,42 +24,128 @@ In the browser, the promise handler for
2524
[registration.pushManager.subscribe()](https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe)
2625
returns a
2726
[PushSubscription](https://developer.mozilla.org/en-US/docs/Web/API/PushSubscription)
28-
object. This object has a .toJSON() method that will return a JSON
29-
object that contains all the info we need to encrypt and push data.
27+
object. This object has a .toJSON() method that will return a JSON object that contains all the info we need to encrypt
28+
and push data.
3029

31-
As illustration, a subscription info object may look like:
32-
```
30+
As illustration, a `subscription_info` object may look like:
31+
```json
3332
{"endpoint": "https://updates.push.services.mozilla.com/push/v1/gAA...", "keys": {"auth": "k8J...", "p256dh": "BOr..."}}
3433
```
3534

3635
How you send the PushSubscription data to your backend, store it
3736
referenced to the user who requested it, and recall it when there's
38-
new a new push subscription update is left as an excerise for the
37+
a new push subscription update is left as an exercise for the
3938
reader.
4039

41-
The data can be any serial content (string, bit array, serialized
42-
JSON, etc), but be sure that your receiving application is able to
43-
parse and understand it. (e.g. `data = "Mary had a little lamb."`)
40+
### Sending Data using `webpush()` One Call
4441

45-
gcm_key is the API key obtained from the Google Developer Console.
46-
It is only needed if endpoint is
47-
https://android.googleapis.com/gcm/send
42+
In many cases, your code will be sending a single message to many
43+
recipients. There's a "One Call" function which will make things
44+
easier.
4845

49-
`headers` is a `dict`ionary of additional HTTP header values (e.g.
50-
[VAPID](https://github.com/mozilla-services/vapid/tree/master/python)
51-
self identification headers). It is optional and may be omitted.
46+
```pythonstub
47+
from pywebpush import webpush
5248
53-
to send:
49+
webpush(subscription_info,
50+
data,
51+
vapid_private_key="Private Key or File Path[1]",
52+
vapid_claims={"sub": "mailto:YourEmailAddress"})
5453
```
55-
WebPusher(subscription_info).send(data, headers)
54+
This will encode `data`, add the appropriate VAPID auth headers if required and send it to the push server identified
55+
in the `subscription_info` block.
56+
57+
**Parameters**
58+
59+
*subscription_info* - The `dict` of the subscription info (described above).
60+
61+
*data* - can be any serial content (string, bit array, serialized JSON, etc), but be sure that your receiving
62+
application is able to parse and understand it. (e.g. `data = "Mary had a little lamb."`)
63+
64+
*vapid_claims* - a `dict` containing the VAPID claims required for authorization (See
65+
[py_vapid](https://github.com/web-push-libs/vapid/tree/master/python) for more details)
66+
67+
*vapid_private_key* - Either a path to a VAPID EC2 private key PEM file, or a string containing the DER representation.
68+
(See [py_vapid](https://github.com/web-push-libs/vapid/tree/master/python) for more details.) The `private_key` may be
69+
a base64 encoded DER formatted private key, or the path to an OpenSSL exported private key file.
70+
71+
e.g. the output of:
72+
```commandline
73+
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
5674
```
57-
to send for Chrome:
75+
76+
**Example**
77+
78+
```pythonstub
79+
from pywebpush import webpush, WebPushException
80+
81+
try:
82+
webpush(
83+
subscription_info={
84+
"endpoint": "https://push.example.com/v1/12345",
85+
"keys": {
86+
"p256dh": "0123abcde...",
87+
"auth": "abc123..."
88+
}},
89+
data="Mary had a little lamb, with a nice mint jelly",
90+
vapid_private_key="path/to/vapid_private.pem",
91+
vapid_claims={
92+
93+
}
94+
)
95+
except WebPushException as ex:
96+
print("I'm sorry, Dave, but I can't do that: {}", repr(ex))
5897
```
98+
99+
### Methods
100+
101+
If you expect to resend to the same recipient, or have more needs than just sending data quickly, you
102+
can pass just `wp = WebPusher(subscription_info)`. This will return a `WebPusher` object.
103+
104+
The following methods are available:
105+
106+
#### `.send(data, headers={}, ttl=0, gcm_key="", reg_id="", content_encoding="aesgcm", curl=False)`
107+
108+
Send the data using additional parameters. On error, returns a `WebPushException`
109+
110+
**Parameters**
111+
112+
*data* Binary string of data to send
113+
114+
*headers* A `dict` containing any additional headers to send
115+
116+
*ttl* Message Time To Live on Push Server waiting for the client to reconnect (in seconds)
117+
118+
*gcm_key* Google Cloud Messaging key (if using the older GCM push system) This is the API key obtained from the Google
119+
Developer Console.
120+
121+
*reg_id* Google Cloud Messaging registration ID (will be extracted from endpoint if not specified)
122+
123+
*content_encoding* ECE content encoding type (defaults to "aesgcm")
124+
125+
*curl* Do not execute the POST, but return as a `curl` command. This will write the encrypted content to a local file
126+
named `encrpypted.data`. This command is meant to be used for debugging purposes.
127+
128+
**Example**
129+
130+
to send from Chrome using the old GCM mode:
131+
```pythonstub
59132
WebPusher(subscription_info).send(data, headers, ttl, gcm_key)
60133
```
61134

62-
You can also simply encode the data to send later by calling
135+
#### `.encode(data, content_encoding="aesgcm")`
63136

137+
Encode the `data` for future use. On error, returns a `WebPushException`
138+
139+
**Parameters**
140+
141+
*data* Binary string of data to send
142+
143+
*content_encoding* ECE content encoding type (defaults to "aesgcm")
144+
145+
**Example**
146+
147+
```pythonstub
148+
encoded_data = WebPush(subscription_info).encode(data)
64149
```
65-
encoded = WebPush(subscription_info).encode(data)
66-
```
150+
151+

README.rst

Lines changed: 127 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
|Build\_Status| [|Requirements Status|]
1+
|Build\_Status| |Requirements Status|
22

33
Webpush Data encryption library for Python
44
==========================================
55

66
This is a work in progress. This library is available on `pypi as
77
pywebpush <https://pypi.python.org/pypi/pywebpush>`__. Source is
8-
available on `github <https://github.com/web-push-libs/pywebpush>`__
8+
available on `github <https://github.com/mozilla-services/pywebpush>`__.
99

1010
Installation
1111
------------
1212

1313
You'll need to run ``python virtualenv``. Then
1414

15-
::
15+
.. code:: commandline
1616
1717
bin/pip install -r requirements.txt
1818
bin/python setup.py develop
@@ -27,45 +27,150 @@ returns a
2727
object. This object has a .toJSON() method that will return a JSON
2828
object that contains all the info we need to encrypt and push data.
2929

30-
As illustration, a subscription info object may look like:
30+
As illustration, a ``subscription_info`` object may look like:
3131

32-
::
32+
.. code:: json
3333
3434
{"endpoint": "https://updates.push.services.mozilla.com/push/v1/gAA...", "keys": {"auth": "k8J...", "p256dh": "BOr..."}}
3535
3636
How you send the PushSubscription data to your backend, store it
37-
referenced to the user who requested it, and recall it when there's new
38-
a new push subscription update is left as an excerise for the reader.
37+
referenced to the user who requested it, and recall it when there's a
38+
new push subscription update is left as an exercise for the reader.
3939

40-
The data can be any serial content (string, bit array, serialized JSON,
40+
Sending Data using ``webpush()`` One Call
41+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42+
43+
In many cases, your code will be sending a single message to many
44+
recipients. There's a "One Call" function which will make things easier.
45+
46+
.. code:: pythonstub
47+
48+
from pywebpush import webpush
49+
50+
webpush(subscription_info,
51+
data,
52+
vapid_private_key="Private Key or File Path[1]",
53+
vapid_claims={"sub": "mailto:YourEmailAddress"})
54+
55+
This will encode ``data``, add the appropriate VAPID auth headers if
56+
required and send it to the push server identified in the
57+
``subscription_info`` block.
58+
59+
**Parameters**
60+
61+
*subscription\_info* - The ``dict`` of the subscription info (described
62+
above).
63+
64+
*data* - can be any serial content (string, bit array, serialized JSON,
4165
etc), but be sure that your receiving application is able to parse and
4266
understand it. (e.g. ``data = "Mary had a little lamb."``)
4367

44-
gcm\_key is the API key obtained from the Google Developer Console. It
45-
is only needed if endpoint is https://android.googleapis.com/gcm/send
68+
*vapid\_claims* - a ``dict`` containing the VAPID claims required for
69+
authorization (See
70+
`py\_vapid <https://github.com/web-push-libs/vapid/tree/master/python>`__
71+
for more details)
72+
73+
*vapid\_private\_key* - Either a path to a VAPID EC2 private key PEM
74+
file, or a string containing the DER representation. (See
75+
`py\_vapid <https://github.com/web-push-libs/vapid/tree/master/python>`__
76+
for more details.) The ``private_key`` may be a base64 encoded DER
77+
formatted private key, or the path to an OpenSSL exported private key
78+
file.
79+
80+
e.g. the output of:
81+
82+
.. code:: commandline
83+
84+
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
85+
86+
**Example**
87+
88+
.. code:: pythonstub
89+
90+
from pywebpush import webpush, WebPushException
91+
92+
try:
93+
webpush(
94+
subscription_info={
95+
"endpoint": "https://push.example.com/v1/12345",
96+
"keys": {
97+
"p256dh": "0123abcde...",
98+
"auth": "abc123..."
99+
}},
100+
data="Mary had a little lamb, with a nice mint jelly",
101+
vapid_private_key="path/to/vapid_private.pem",
102+
vapid_claims={
103+
104+
}
105+
)
106+
except WebPushException as ex:
107+
print("I'm sorry, Dave, but I can't do that: {}", repr(ex))
46108
47-
``headers`` is a ``dict``\ ionary of additional HTTP header values (e.g.
48-
`VAPID <https://github.com/mozilla-services/vapid/tree/master/python>`__
49-
self identification headers). It is optional and may be omitted.
109+
Methods
110+
~~~~~~~
50111

51-
to send:
112+
If you expect to resend to the same recipient, or have more needs than
113+
just sending data quickly, you can pass just
114+
``wp = WebPusher(subscription_info)``. This will return a ``WebPusher``
115+
object.
52116

53-
::
117+
The following methods are available:
54118

55-
WebPusher(subscription_info).send(data, headers)
119+
``.send(data, headers={}, ttl=0, gcm_key="", reg_id="", content_encoding="aesgcm", curl=False)``
120+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
56121

57-
to send for Chrome:
122+
Send the data using additional parameters. On error, returns a
123+
``WebPushException``
58124

59-
::
125+
**Parameters**
126+
127+
*data* Binary string of data to send
128+
129+
*headers* A ``dict`` containing any additional headers to send
130+
131+
*ttl* Message Time To Live on Push Server waiting for the client to
132+
reconnect (in seconds)
133+
134+
*gcm\_key* Google Cloud Messaging key (if using the older GCM push
135+
system) This is the API key obtained from the Google Developer Console.
136+
137+
*reg\_id* Google Cloud Messaging registration ID (will be extracted from
138+
endpoint if not specified)
139+
140+
*content\_encoding* ECE content encoding type (defaults to "aesgcm")
141+
142+
*curl* Do not execute the POST, but return as a ``curl`` command. This
143+
will write the encrypted content to a local file named
144+
``encrpypted.data``. This command is meant to be used for debugging
145+
purposes.
146+
147+
**Example**
148+
149+
to send from Chrome using the old GCM mode:
150+
151+
.. code:: pythonstub
60152
61153
WebPusher(subscription_info).send(data, headers, ttl, gcm_key)
62154
63-
You can also simply encode the data to send later by calling
155+
``.encode(data, content_encoding="aesgcm")``
156+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
157+
158+
Encode the ``data`` for future use. On error, returns a
159+
``WebPushException``
160+
161+
**Parameters**
162+
163+
*data* Binary string of data to send
164+
165+
*content\_encoding* ECE content encoding type (defaults to "aesgcm")
166+
167+
**Example**
64168

65-
::
169+
.. code:: pythonstub
66170
67-
encoded = WebPush(subscription_info).encode(data)
171+
encoded_data = WebPush(subscription_info).encode(data)
68172
69173
.. |Build\_Status| image:: https://travis-ci.org/web-push-libs/pywebpush.svg?branch=master
70174
:target: https://travis-ci.org/web-push-libs/pywebpush
71-
.. |Requirements Status| image:: https://requires.io/github/web-push-libs/pywebpush/requirements.svg?branch=master
175+
.. |Requirements Status| image:: https://requires.io/github/web-push-libs/pywebpush/requirements.svg?branch=feat%2F44
176+
:target: https://requires.io/github/web-push-libs/pywebpush/requirements/?branch=master

convert_readme.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
pandoc --from=markdown --to=rst --output README.rst README.md
1+
pandoc --from=markdown --to=rst --output README.rst README.md

0 commit comments

Comments
 (0)