pywebpush 2.1.2__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pywebpush-2.1.2 → pywebpush-2.2.0}/CHANGELOG.md +14 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/PKG-INFO +51 -15
- {pywebpush-2.1.2 → pywebpush-2.2.0}/README.md +49 -14
- {pywebpush-2.1.2 → pywebpush-2.2.0}/README.rst +99 -33
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pyproject.toml +2 -1
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush/__init__.py +6 -49
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush/__main__.py +15 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush/tests/test_webpush.py +0 -30
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush.egg-info/PKG-INFO +51 -15
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush.egg-info/SOURCES.txt +0 -1
- pywebpush-2.1.2/PULL_REQUEST_TEMPLATE.md +0 -13
- {pywebpush-2.1.2 → pywebpush-2.2.0}/CODE_OF_CONDUCT.md +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/LICENSE +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/MANIFEST.in +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/entry_points.txt +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/local_test.txt +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush/foo.py +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush/tests/__init__.py +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush.egg-info/dependency_links.txt +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush.egg-info/entry_points.txt +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush.egg-info/requires.txt +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/pywebpush.egg-info/top_level.txt +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/requirements.txt +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/setup.cfg +0 -0
- {pywebpush-2.1.2 → pywebpush-2.2.0}/test-requirements.txt +0 -0
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
# I am terrible at keeping this up-to-date.
|
|
2
2
|
|
|
3
|
+
## 2.2.0 (2026-)
|
|
4
|
+
|
|
5
|
+
- Update `rst` files to reflect `md` file changes
|
|
6
|
+
|
|
7
|
+
Add comment discussing additional work for Windows Notification Service (WNS)
|
|
8
|
+
|
|
9
|
+
- Update the README.md file to mention the required, non-standard headers.
|
|
10
|
+
|
|
11
|
+
_BREAKING_CHANGE_
|
|
12
|
+
This version also drops legacy support for GCM/FCM authorization keys, since those items
|
|
13
|
+
are obsolete according to Google.
|
|
14
|
+
See https://firebase.google.com/docs/cloud-messaging/auth-server#authorize-legacy-protocol-send-requests
|
|
15
|
+
|
|
3
16
|
## 2.1.2 (2025-11-10)
|
|
17
|
+
|
|
4
18
|
chore: fix formatting
|
|
5
19
|
chore: update CHANGELOG
|
|
6
20
|
chore: note admin update
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pywebpush
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: WebPush publication library
|
|
5
5
|
Author-email: JR Conlin <src+webpusher@jrconlin.com>
|
|
6
6
|
License: MPL-2.0
|
|
@@ -10,6 +10,7 @@ Classifier: Topic :: Internet :: WWW/HTTP
|
|
|
10
10
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
11
11
|
Classifier: Programming Language :: Python
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Requires-Python: >=3.10
|
|
13
14
|
Description-Content-Type: text/markdown
|
|
14
15
|
License-File: LICENSE
|
|
15
16
|
Requires-Dist: aiohttp
|
|
@@ -26,9 +27,6 @@ Dynamic: license-file
|
|
|
26
27
|
|
|
27
28
|
# Webpush Data encryption library for Python
|
|
28
29
|
|
|
29
|
-
[](https://travis-ci.org/web-push-libs/pywebpush)
|
|
30
|
-
[](https://requires.io/github/web-push-libs/pywebpush/requirements/?branch=main)
|
|
31
|
-
|
|
32
30
|
This library is available on [pypi as pywebpush](https://pypi.python.org/pypi/pywebpush).
|
|
33
31
|
Source is available on [github](https://github.com/mozilla-services/pywebpush).
|
|
34
32
|
Please note: This library was designated as a `Critical Project` by PyPi, it is currently
|
|
@@ -64,6 +62,11 @@ referenced to the user who requested it, and recall it when there's
|
|
|
64
62
|
a new push subscription update is left as an exercise for the
|
|
65
63
|
reader.
|
|
66
64
|
|
|
65
|
+
_*Note:*_ Some platforms (like Microsoft Windows) require additional
|
|
66
|
+
headers specified for the Push call. These additional headers are not
|
|
67
|
+
standard and may be rejected by other Push services. Please see
|
|
68
|
+
[Special Instructions](#special-instructions) below.
|
|
69
|
+
|
|
67
70
|
### Sending Data using `webpush()` One Call
|
|
68
71
|
|
|
69
72
|
In many cases, your code will be sending a single message to many
|
|
@@ -82,7 +85,7 @@ webpush(subscription_info,
|
|
|
82
85
|
This will encode `data`, add the appropriate VAPID auth headers if required and send it to the push server identified
|
|
83
86
|
in the `subscription_info` block.
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
#### Parameters
|
|
86
89
|
|
|
87
90
|
_subscription_info_ - The `dict` of the subscription info (described above).
|
|
88
91
|
|
|
@@ -107,7 +110,7 @@ e.g. the output of:
|
|
|
107
110
|
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
|
|
108
111
|
```
|
|
109
112
|
|
|
110
|
-
|
|
113
|
+
#### Example
|
|
111
114
|
|
|
112
115
|
```python
|
|
113
116
|
from pywebpush import webpush, WebPushException
|
|
@@ -145,7 +148,7 @@ can pass just `wp = WebPusher(subscription_info)`. This will return a `WebPusher
|
|
|
145
148
|
|
|
146
149
|
The following methods are available:
|
|
147
150
|
|
|
148
|
-
#### `.send(data, headers={}, ttl=0,
|
|
151
|
+
#### `.send(data, headers={}, ttl=0, reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)`
|
|
149
152
|
|
|
150
153
|
Send the data using additional parameters. On error, returns a `WebPushException`
|
|
151
154
|
|
|
@@ -157,9 +160,6 @@ _headers_ A `dict` containing any additional headers to send
|
|
|
157
160
|
|
|
158
161
|
_ttl_ Message Time To Live on Push Server waiting for the client to reconnect (in seconds)
|
|
159
162
|
|
|
160
|
-
_gcm_key_ Google Cloud Messaging key (if using the older GCM push system) This is the API key obtained from the Google
|
|
161
|
-
Developer Console.
|
|
162
|
-
|
|
163
163
|
_reg_id_ Google Cloud Messaging registration ID (will be extracted from endpoint if not specified)
|
|
164
164
|
|
|
165
165
|
_content_encoding_ ECE content encoding type (defaults to "aes128gcm")
|
|
@@ -172,10 +172,10 @@ See [requests documentation](http://docs.python-requests.org/en/master/user/quic
|
|
|
172
172
|
|
|
173
173
|
##### Example
|
|
174
174
|
|
|
175
|
-
to send
|
|
175
|
+
to send to a user on Chrome:
|
|
176
176
|
|
|
177
177
|
```python
|
|
178
|
-
WebPusher(subscription_info).send(data, headers, ttl
|
|
178
|
+
WebPusher(subscription_info).send(data, headers, ttl)
|
|
179
179
|
```
|
|
180
180
|
|
|
181
181
|
#### `.encode(data, content_encoding="aes128gcm")`
|
|
@@ -188,7 +188,7 @@ _data_ Binary string of data to send
|
|
|
188
188
|
|
|
189
189
|
_content_encoding_ ECE content encoding type (defaults to "aes128gcm")
|
|
190
190
|
|
|
191
|
-
*Note* This will return a `NoData` exception if the data is not present or empty. It is completely
|
|
191
|
+
_*Note*_ This will return a `NoData` exception if the data is not present or empty. It is completely
|
|
192
192
|
valid to send a WebPush notification with no data, but encoding is a no-op in that case. Best not
|
|
193
193
|
to call it if you don't have data.
|
|
194
194
|
|
|
@@ -200,8 +200,7 @@ encoded_data = WebPush(subscription_info).encode(data)
|
|
|
200
200
|
|
|
201
201
|
## Stand Alone Webpush
|
|
202
202
|
|
|
203
|
-
If you're not really into coding your own solution, there's also a "stand-alone" `pywebpush` command in the
|
|
204
|
-
./bin directory.
|
|
203
|
+
If you're not really into coding your own solution, there's also a "stand-alone" `pywebpush` command in the `./bin` directory.
|
|
205
204
|
|
|
206
205
|
This uses two files:
|
|
207
206
|
|
|
@@ -227,3 +226,40 @@ If you're interested in just testing your applications WebPush interface, you co
|
|
|
227
226
|
which will encrypt and send the contents of `stuff_to_send.data`.
|
|
228
227
|
|
|
229
228
|
See `./bin/pywebpush --help` for available commands and options.
|
|
229
|
+
|
|
230
|
+
## Special Instructions
|
|
231
|
+
|
|
232
|
+
### Windows
|
|
233
|
+
|
|
234
|
+
[Microsoft requires](https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/push-request-response-headers#request-parameters)
|
|
235
|
+
one extra header and suggests several additional headers. Users have reported that not including
|
|
236
|
+
these headers can cause notifications to fail to appear. These additional headers are non-standard
|
|
237
|
+
and may be rejected by other platforms. You should be cautious including them with calls to
|
|
238
|
+
non-Microsoft platforms, or to non-Microsoft destinations.
|
|
239
|
+
|
|
240
|
+
As of 2024-Apr-19, Microsoft requires an `X-WNS-Type` header. As an example, you can include this
|
|
241
|
+
header within the command line call:
|
|
242
|
+
|
|
243
|
+
Content of the `windows_headers.json` file:
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{"X-WNS-Type":"wns/toast", "TTL":600, "Content-Type": "text/xml"}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
_*Note*_ : This includes both the `TTL` set to 10 minutes and the required matching `Content-Type` header for `wns/toast`.
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
pywebpush --data stuff_to_send.xml \
|
|
253
|
+
--info edge_user_info.json \
|
|
254
|
+
--head windows_headers.json \
|
|
255
|
+
--claims vapid_claims.json
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Google Cloud Messaging (GCM)
|
|
259
|
+
|
|
260
|
+
Please note that GCM has been sunset by Google. Providers should
|
|
261
|
+
use [Firebase Cloud Messaging](https://firebase.google.com/support/troubleshooter/fcm/tokens/gcm) instead.
|
|
262
|
+
|
|
263
|
+
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).
|
|
264
|
+
|
|
265
|
+
Sending WebPush messages to Google Chrome users should not be impacted by this change.
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
# Webpush Data encryption library for Python
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.org/web-push-libs/pywebpush)
|
|
4
|
-
[](https://requires.io/github/web-push-libs/pywebpush/requirements/?branch=main)
|
|
5
|
-
|
|
6
3
|
This library is available on [pypi as pywebpush](https://pypi.python.org/pypi/pywebpush).
|
|
7
4
|
Source is available on [github](https://github.com/mozilla-services/pywebpush).
|
|
8
5
|
Please note: This library was designated as a `Critical Project` by PyPi, it is currently
|
|
@@ -38,6 +35,11 @@ referenced to the user who requested it, and recall it when there's
|
|
|
38
35
|
a new push subscription update is left as an exercise for the
|
|
39
36
|
reader.
|
|
40
37
|
|
|
38
|
+
_*Note:*_ Some platforms (like Microsoft Windows) require additional
|
|
39
|
+
headers specified for the Push call. These additional headers are not
|
|
40
|
+
standard and may be rejected by other Push services. Please see
|
|
41
|
+
[Special Instructions](#special-instructions) below.
|
|
42
|
+
|
|
41
43
|
### Sending Data using `webpush()` One Call
|
|
42
44
|
|
|
43
45
|
In many cases, your code will be sending a single message to many
|
|
@@ -56,7 +58,7 @@ webpush(subscription_info,
|
|
|
56
58
|
This will encode `data`, add the appropriate VAPID auth headers if required and send it to the push server identified
|
|
57
59
|
in the `subscription_info` block.
|
|
58
60
|
|
|
59
|
-
|
|
61
|
+
#### Parameters
|
|
60
62
|
|
|
61
63
|
_subscription_info_ - The `dict` of the subscription info (described above).
|
|
62
64
|
|
|
@@ -81,7 +83,7 @@ e.g. the output of:
|
|
|
81
83
|
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
|
|
82
84
|
```
|
|
83
85
|
|
|
84
|
-
|
|
86
|
+
#### Example
|
|
85
87
|
|
|
86
88
|
```python
|
|
87
89
|
from pywebpush import webpush, WebPushException
|
|
@@ -119,7 +121,7 @@ can pass just `wp = WebPusher(subscription_info)`. This will return a `WebPusher
|
|
|
119
121
|
|
|
120
122
|
The following methods are available:
|
|
121
123
|
|
|
122
|
-
#### `.send(data, headers={}, ttl=0,
|
|
124
|
+
#### `.send(data, headers={}, ttl=0, reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)`
|
|
123
125
|
|
|
124
126
|
Send the data using additional parameters. On error, returns a `WebPushException`
|
|
125
127
|
|
|
@@ -131,9 +133,6 @@ _headers_ A `dict` containing any additional headers to send
|
|
|
131
133
|
|
|
132
134
|
_ttl_ Message Time To Live on Push Server waiting for the client to reconnect (in seconds)
|
|
133
135
|
|
|
134
|
-
_gcm_key_ Google Cloud Messaging key (if using the older GCM push system) This is the API key obtained from the Google
|
|
135
|
-
Developer Console.
|
|
136
|
-
|
|
137
136
|
_reg_id_ Google Cloud Messaging registration ID (will be extracted from endpoint if not specified)
|
|
138
137
|
|
|
139
138
|
_content_encoding_ ECE content encoding type (defaults to "aes128gcm")
|
|
@@ -146,10 +145,10 @@ See [requests documentation](http://docs.python-requests.org/en/master/user/quic
|
|
|
146
145
|
|
|
147
146
|
##### Example
|
|
148
147
|
|
|
149
|
-
to send
|
|
148
|
+
to send to a user on Chrome:
|
|
150
149
|
|
|
151
150
|
```python
|
|
152
|
-
WebPusher(subscription_info).send(data, headers, ttl
|
|
151
|
+
WebPusher(subscription_info).send(data, headers, ttl)
|
|
153
152
|
```
|
|
154
153
|
|
|
155
154
|
#### `.encode(data, content_encoding="aes128gcm")`
|
|
@@ -162,7 +161,7 @@ _data_ Binary string of data to send
|
|
|
162
161
|
|
|
163
162
|
_content_encoding_ ECE content encoding type (defaults to "aes128gcm")
|
|
164
163
|
|
|
165
|
-
*Note* This will return a `NoData` exception if the data is not present or empty. It is completely
|
|
164
|
+
_*Note*_ This will return a `NoData` exception if the data is not present or empty. It is completely
|
|
166
165
|
valid to send a WebPush notification with no data, but encoding is a no-op in that case. Best not
|
|
167
166
|
to call it if you don't have data.
|
|
168
167
|
|
|
@@ -174,8 +173,7 @@ encoded_data = WebPush(subscription_info).encode(data)
|
|
|
174
173
|
|
|
175
174
|
## Stand Alone Webpush
|
|
176
175
|
|
|
177
|
-
If you're not really into coding your own solution, there's also a "stand-alone" `pywebpush` command in the
|
|
178
|
-
./bin directory.
|
|
176
|
+
If you're not really into coding your own solution, there's also a "stand-alone" `pywebpush` command in the `./bin` directory.
|
|
179
177
|
|
|
180
178
|
This uses two files:
|
|
181
179
|
|
|
@@ -201,3 +199,40 @@ If you're interested in just testing your applications WebPush interface, you co
|
|
|
201
199
|
which will encrypt and send the contents of `stuff_to_send.data`.
|
|
202
200
|
|
|
203
201
|
See `./bin/pywebpush --help` for available commands and options.
|
|
202
|
+
|
|
203
|
+
## Special Instructions
|
|
204
|
+
|
|
205
|
+
### Windows
|
|
206
|
+
|
|
207
|
+
[Microsoft requires](https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/push-request-response-headers#request-parameters)
|
|
208
|
+
one extra header and suggests several additional headers. Users have reported that not including
|
|
209
|
+
these headers can cause notifications to fail to appear. These additional headers are non-standard
|
|
210
|
+
and may be rejected by other platforms. You should be cautious including them with calls to
|
|
211
|
+
non-Microsoft platforms, or to non-Microsoft destinations.
|
|
212
|
+
|
|
213
|
+
As of 2024-Apr-19, Microsoft requires an `X-WNS-Type` header. As an example, you can include this
|
|
214
|
+
header within the command line call:
|
|
215
|
+
|
|
216
|
+
Content of the `windows_headers.json` file:
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{"X-WNS-Type":"wns/toast", "TTL":600, "Content-Type": "text/xml"}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
_*Note*_ : This includes both the `TTL` set to 10 minutes and the required matching `Content-Type` header for `wns/toast`.
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
pywebpush --data stuff_to_send.xml \
|
|
226
|
+
--info edge_user_info.json \
|
|
227
|
+
--head windows_headers.json \
|
|
228
|
+
--claims vapid_claims.json
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Google Cloud Messaging (GCM)
|
|
232
|
+
|
|
233
|
+
Please note that GCM has been sunset by Google. Providers should
|
|
234
|
+
use [Firebase Cloud Messaging](https://firebase.google.com/support/troubleshooter/fcm/tokens/gcm) instead.
|
|
235
|
+
|
|
236
|
+
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).
|
|
237
|
+
|
|
238
|
+
Sending WebPush messages to Google Chrome users should not be impacted by this change.
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
Webpush Data encryption library for Python
|
|
2
2
|
==========================================
|
|
3
3
|
|
|
4
|
-
|Build Status| |Requirements Status|
|
|
5
|
-
|
|
6
4
|
This library is available on `pypi as
|
|
7
5
|
pywebpush <https://pypi.python.org/pypi/pywebpush>`__. Source is
|
|
8
6
|
available on `github <https://github.com/mozilla-services/pywebpush>`__.
|
|
@@ -14,12 +12,8 @@ make of that what you will.
|
|
|
14
12
|
Installation
|
|
15
13
|
------------
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
.. code:: bash
|
|
20
|
-
|
|
21
|
-
venv/bin/pip install -r requirements.txt
|
|
22
|
-
venv/bin/python -m pip install -e .
|
|
15
|
+
To work with this repo locally, you’ll need to run
|
|
16
|
+
``python -m venv venv``. Then ``venv/bin/pip install --editable .``
|
|
23
17
|
|
|
24
18
|
Usage
|
|
25
19
|
-----
|
|
@@ -35,12 +29,20 @@ As illustration, a ``subscription_info`` object may look like:
|
|
|
35
29
|
|
|
36
30
|
.. code:: json
|
|
37
31
|
|
|
38
|
-
{
|
|
32
|
+
{
|
|
33
|
+
"endpoint": "https://updates.push.services.mozilla.com/push/v1/gAA...",
|
|
34
|
+
"keys": { "auth": "k8J...", "p256dh": "BOr..." }
|
|
35
|
+
}
|
|
39
36
|
|
|
40
37
|
How you send the PushSubscription data to your backend, store it
|
|
41
38
|
referenced to the user who requested it, and recall it when there’s a
|
|
42
39
|
new push subscription update is left as an exercise for the reader.
|
|
43
40
|
|
|
41
|
+
*Note:* Some platforms (like Microsoft Windows) require additional
|
|
42
|
+
headers specified for the Push call. These additional headers are not
|
|
43
|
+
standard and may be rejected by other Push services. Please see `Special
|
|
44
|
+
Instructions <#special-instructions>`__ below.
|
|
45
|
+
|
|
44
46
|
Sending Data using ``webpush()`` One Call
|
|
45
47
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
46
48
|
|
|
@@ -60,7 +62,8 @@ This will encode ``data``, add the appropriate VAPID auth headers if
|
|
|
60
62
|
required and send it to the push server identified in the
|
|
61
63
|
``subscription_info`` block.
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
Parameters
|
|
66
|
+
^^^^^^^^^^
|
|
64
67
|
|
|
65
68
|
*subscription_info* - The ``dict`` of the subscription info (described
|
|
66
69
|
above).
|
|
@@ -78,7 +81,9 @@ standard form.
|
|
|
78
81
|
authorization (See
|
|
79
82
|
`py_vapid <https://github.com/web-push-libs/vapid/tree/master/python>`__
|
|
80
83
|
for more details). If ``aud`` is not specified, pywebpush will attempt
|
|
81
|
-
to auto-fill from the ``endpoint``.
|
|
84
|
+
to auto-fill from the ``endpoint``. If ``exp`` is not specified or set
|
|
85
|
+
in the past, it will be set to 12 hours from now. In both cases, the
|
|
86
|
+
passed ``dict`` **will be mutated** after the call.
|
|
82
87
|
|
|
83
88
|
*vapid_private_key* - Either a path to a VAPID EC2 private key PEM file,
|
|
84
89
|
or a string containing the DER representation. (See
|
|
@@ -93,7 +98,8 @@ e.g. the output of:
|
|
|
93
98
|
|
|
94
99
|
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
|
|
95
100
|
|
|
96
|
-
|
|
101
|
+
Example
|
|
102
|
+
^^^^^^^
|
|
97
103
|
|
|
98
104
|
.. code:: python
|
|
99
105
|
|
|
@@ -134,13 +140,16 @@ object.
|
|
|
134
140
|
|
|
135
141
|
The following methods are available:
|
|
136
142
|
|
|
137
|
-
``.send(data, headers={}, ttl=0,
|
|
138
|
-
|
|
143
|
+
``.send(data, headers={}, ttl=0, reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)``
|
|
144
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
139
145
|
|
|
140
146
|
Send the data using additional parameters. On error, returns a
|
|
141
147
|
``WebPushException``
|
|
142
148
|
|
|
143
|
-
|
|
149
|
+
.. _parameters-1:
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
''''''''''
|
|
144
153
|
|
|
145
154
|
*data* Binary string of data to send
|
|
146
155
|
|
|
@@ -149,9 +158,6 @@ Send the data using additional parameters. On error, returns a
|
|
|
149
158
|
*ttl* Message Time To Live on Push Server waiting for the client to
|
|
150
159
|
reconnect (in seconds)
|
|
151
160
|
|
|
152
|
-
*gcm_key* Google Cloud Messaging key (if using the older GCM push
|
|
153
|
-
system) This is the API key obtained from the Google Developer Console.
|
|
154
|
-
|
|
155
161
|
*reg_id* Google Cloud Messaging registration ID (will be extracted from
|
|
156
162
|
endpoint if not specified)
|
|
157
163
|
|
|
@@ -165,13 +171,16 @@ purposes.
|
|
|
165
171
|
*timeout* timeout for requests POST query. See `requests
|
|
166
172
|
documentation <http://docs.python-requests.org/en/master/user/quickstart/#timeouts>`__.
|
|
167
173
|
|
|
168
|
-
|
|
174
|
+
.. _example-1:
|
|
169
175
|
|
|
170
|
-
|
|
176
|
+
Example
|
|
177
|
+
'''''''
|
|
178
|
+
|
|
179
|
+
to send to a user on Chrome:
|
|
171
180
|
|
|
172
181
|
.. code:: python
|
|
173
182
|
|
|
174
|
-
WebPusher(subscription_info).send(data, headers, ttl
|
|
183
|
+
WebPusher(subscription_info).send(data, headers, ttl)
|
|
175
184
|
|
|
176
185
|
``.encode(data, content_encoding="aes128gcm")``
|
|
177
186
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
@@ -179,13 +188,24 @@ to send from Chrome using the old GCM mode:
|
|
|
179
188
|
Encode the ``data`` for future use. On error, returns a
|
|
180
189
|
``WebPushException``
|
|
181
190
|
|
|
182
|
-
|
|
191
|
+
.. _parameters-2:
|
|
192
|
+
|
|
193
|
+
Parameters
|
|
194
|
+
''''''''''
|
|
183
195
|
|
|
184
196
|
*data* Binary string of data to send
|
|
185
197
|
|
|
186
198
|
*content_encoding* ECE content encoding type (defaults to “aes128gcm”)
|
|
187
199
|
|
|
188
|
-
|
|
200
|
+
*Note* This will return a ``NoData`` exception if the data is not
|
|
201
|
+
present or empty. It is completely valid to send a WebPush notification
|
|
202
|
+
with no data, but encoding is a no-op in that case. Best not to call it
|
|
203
|
+
if you don’t have data.
|
|
204
|
+
|
|
205
|
+
.. _example-2:
|
|
206
|
+
|
|
207
|
+
Example
|
|
208
|
+
'''''''
|
|
189
209
|
|
|
190
210
|
.. code:: python
|
|
191
211
|
|
|
@@ -195,7 +215,7 @@ Stand Alone Webpush
|
|
|
195
215
|
-------------------
|
|
196
216
|
|
|
197
217
|
If you’re not really into coding your own solution, there’s also a
|
|
198
|
-
“stand-alone” ``pywebpush`` command in the
|
|
218
|
+
“stand-alone” ``pywebpush`` command in the ``./bin`` directory.
|
|
199
219
|
|
|
200
220
|
This uses two files:
|
|
201
221
|
|
|
@@ -207,11 +227,13 @@ This uses two files:
|
|
|
207
227
|
|
|
208
228
|
.. code:: json
|
|
209
229
|
|
|
210
|
-
{
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
230
|
+
{
|
|
231
|
+
"endpoint": "https://push...",
|
|
232
|
+
"keys": {
|
|
233
|
+
"auth": "ab01...",
|
|
234
|
+
"p256dh": "aa02..."
|
|
235
|
+
}
|
|
236
|
+
}
|
|
215
237
|
|
|
216
238
|
If you’re interested in just testing your applications WebPush
|
|
217
239
|
interface, you could use the Command Line:
|
|
@@ -224,7 +246,51 @@ which will encrypt and send the contents of ``stuff_to_send.data``.
|
|
|
224
246
|
|
|
225
247
|
See ``./bin/pywebpush --help`` for available commands and options.
|
|
226
248
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
249
|
+
Special Instructions
|
|
250
|
+
--------------------
|
|
251
|
+
|
|
252
|
+
Windows
|
|
253
|
+
~~~~~~~
|
|
254
|
+
|
|
255
|
+
`Microsoft
|
|
256
|
+
requires <https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/push-request-response-headers#request-parameters>`__
|
|
257
|
+
one extra header and suggests several additional headers. Users have
|
|
258
|
+
reported that not including these headers can cause notifications to
|
|
259
|
+
fail to appear. These additional headers are non-standard and may be
|
|
260
|
+
rejected by other platforms. You should be cautious including them with
|
|
261
|
+
calls to non-Microsoft platforms, or to non-Microsoft destinations.
|
|
262
|
+
|
|
263
|
+
As of 2024-Apr-19, Microsoft requires an ``X-WNS-Type`` header. As an
|
|
264
|
+
example, you can include this header within the command line call:
|
|
265
|
+
|
|
266
|
+
Content of the ``windows_headers.json`` file:
|
|
267
|
+
|
|
268
|
+
.. code:: json
|
|
269
|
+
|
|
270
|
+
{"X-WNS-Type":"wns/toast", "TTL":600, "Content-Type": "text/xml"}
|
|
271
|
+
|
|
272
|
+
*Note* : This includes both the ``TTL`` set to 10 minutes and the
|
|
273
|
+
required matching ``Content-Type`` header for ``wns/toast``.
|
|
274
|
+
|
|
275
|
+
.. code:: bash
|
|
276
|
+
|
|
277
|
+
pywebpush --data stuff_to_send.xml \
|
|
278
|
+
--info edge_user_info.json \
|
|
279
|
+
--head windows_headers.json \
|
|
280
|
+
--claims vapid_claims.json
|
|
281
|
+
|
|
282
|
+
Google Cloud Messaging (GCM)
|
|
283
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
284
|
+
|
|
285
|
+
Please note that GCM has been sunset by Google. Providers should use
|
|
286
|
+
`Firebase Cloud
|
|
287
|
+
Messaging <https://firebase.google.com/support/troubleshooter/fcm/tokens/gcm>`__
|
|
288
|
+
instead.
|
|
289
|
+
|
|
290
|
+
Please also note that sending messages directly to FCM is not supported
|
|
291
|
+
by this library. In the past, you could use an insecure ``gcm_key`` as a
|
|
292
|
+
proxy for the authentication service. `This was disabled in June
|
|
293
|
+
2024 <https://firebase.google.com/docs/cloud-messaging/auth-server#authorize-legacy-protocol-send-requests>`__.
|
|
294
|
+
|
|
295
|
+
Sending WebPush messages to Google Chrome users should not be impacted
|
|
296
|
+
by this change.
|
|
@@ -9,7 +9,8 @@ build-backend = "setuptools.build_meta"
|
|
|
9
9
|
|
|
10
10
|
[project]
|
|
11
11
|
name = "pywebpush"
|
|
12
|
-
version = "2.
|
|
12
|
+
version = "2.2.0"
|
|
13
|
+
requires-python = ">= 3.10"
|
|
13
14
|
license = { text = "MPL-2.0" }
|
|
14
15
|
authors = [{ name = "JR Conlin", email = "src+webpusher@jrconlin.com" }]
|
|
15
16
|
description = "WebPush publication library"
|
|
@@ -19,7 +19,6 @@ except ImportError: # pragma nocover
|
|
|
19
19
|
import aiohttp
|
|
20
20
|
import http_ece
|
|
21
21
|
import requests
|
|
22
|
-
import six
|
|
23
22
|
from cryptography.hazmat.backends import default_backend
|
|
24
23
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
25
24
|
from cryptography.hazmat.primitives import serialization
|
|
@@ -175,7 +174,7 @@ class WebPusher:
|
|
|
175
174
|
for k in ["p256dh", "auth"]:
|
|
176
175
|
if keys.get(k) is None:
|
|
177
176
|
raise WebPushException("Missing keys value: {}".format(k))
|
|
178
|
-
if isinstance(keys[k],
|
|
177
|
+
if isinstance(keys[k], str):
|
|
179
178
|
keys[k] = bytes(cast(str, keys[k]).encode("utf8"))
|
|
180
179
|
receiver_raw = base64.urlsafe_b64decode(
|
|
181
180
|
self._repad(cast(bytes, keys["p256dh"]))
|
|
@@ -236,7 +235,7 @@ class WebPusher:
|
|
|
236
235
|
format=serialization.PublicFormat.UncompressedPoint,
|
|
237
236
|
)
|
|
238
237
|
|
|
239
|
-
if isinstance(data,
|
|
238
|
+
if isinstance(data, str):
|
|
240
239
|
data = bytes(data.encode("utf8"))
|
|
241
240
|
if content_encoding == "aes128gcm":
|
|
242
241
|
self.verb("Encrypting to aes128gcm...")
|
|
@@ -304,10 +303,7 @@ class WebPusher:
|
|
|
304
303
|
data: Union[None, bytes] = None,
|
|
305
304
|
headers: Union[None, Dict[str, str]] = None,
|
|
306
305
|
ttl: int = 0,
|
|
307
|
-
gcm_key: Union[None, str] = None,
|
|
308
|
-
reg_id: Union[None, str] = None,
|
|
309
306
|
content_encoding: str = "aes128gcm",
|
|
310
|
-
curl: bool = False,
|
|
311
307
|
) -> dict:
|
|
312
308
|
"""Encode and send the data to the Push Service.
|
|
313
309
|
|
|
@@ -319,16 +315,8 @@ class WebPusher:
|
|
|
319
315
|
recipient is not online. (Defaults to "0", which discards the
|
|
320
316
|
message immediately if the recipient is unavailable.)
|
|
321
317
|
:type ttl: int
|
|
322
|
-
:param gcm_key: API key obtained from the Google Developer Console.
|
|
323
|
-
Needed if endpoint is https://android.googleapis.com/gcm/send
|
|
324
|
-
:type gcm_key: string
|
|
325
|
-
:param reg_id: registration id of the recipient. If not provided,
|
|
326
|
-
it will be extracted from the endpoint.
|
|
327
|
-
:type reg_id: str
|
|
328
318
|
:param content_encoding: ECE content encoding (defaults to "aes128gcm")
|
|
329
319
|
:type content_encoding: str
|
|
330
|
-
:param curl: Display output as `curl` command instead of sending
|
|
331
|
-
:type curl: bool
|
|
332
320
|
"""
|
|
333
321
|
# Encode the data.
|
|
334
322
|
if headers is None:
|
|
@@ -355,40 +343,8 @@ class WebPusher:
|
|
|
355
343
|
"content-encoding": content_encoding,
|
|
356
344
|
}
|
|
357
345
|
)
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
# gcm keys are all about 40 chars (use 100 for confidence),
|
|
361
|
-
# fcm keys are 153-175 chars
|
|
362
|
-
if len(gcm_key) < 100:
|
|
363
|
-
self.verb("Guessing this is legacy GCM...")
|
|
364
|
-
endpoint = "https://android.googleapis.com/gcm/send"
|
|
365
|
-
else:
|
|
366
|
-
self.verb("Guessing this is FCM...")
|
|
367
|
-
endpoint = "https://fcm.googleapis.com/fcm/send"
|
|
368
|
-
reg_ids = []
|
|
369
|
-
if not reg_id:
|
|
370
|
-
reg_id = cast(str, self.subscription_info["endpoint"]).rsplit("/", 1)[
|
|
371
|
-
-1
|
|
372
|
-
]
|
|
373
|
-
self.verb("Fetching out registration id: {}", reg_id)
|
|
374
|
-
reg_ids.append(reg_id)
|
|
375
|
-
gcm_data = dict()
|
|
376
|
-
gcm_data["registration_ids"] = reg_ids
|
|
377
|
-
if data:
|
|
378
|
-
buffer = encoded.get("body")
|
|
379
|
-
if buffer:
|
|
380
|
-
gcm_data["raw_data"] = base64.b64encode(buffer).decode("utf8")
|
|
381
|
-
gcm_data["time_to_live"] = int(headers["ttl"] if "ttl" in headers else ttl)
|
|
382
|
-
encoded_data = json.dumps(gcm_data)
|
|
383
|
-
headers.update(
|
|
384
|
-
{
|
|
385
|
-
"Authorization": "key=" + gcm_key,
|
|
386
|
-
"Content-Type": "application/json",
|
|
387
|
-
}
|
|
388
|
-
)
|
|
389
|
-
else:
|
|
390
|
-
encoded_data = encoded.get("body")
|
|
391
|
-
endpoint = self.subscription_info["endpoint"]
|
|
346
|
+
encoded_data = encoded.get("body")
|
|
347
|
+
endpoint = self.subscription_info["endpoint"]
|
|
392
348
|
|
|
393
349
|
if "ttl" not in headers or ttl:
|
|
394
350
|
self.verb("Generating TTL of 0...")
|
|
@@ -424,9 +380,10 @@ class WebPusher:
|
|
|
424
380
|
**params,
|
|
425
381
|
)
|
|
426
382
|
self.verb(
|
|
427
|
-
"\nResponse:\n\tcode: {}\n\tbody: {}\n",
|
|
383
|
+
"\nResponse:\n\tcode: {}\n\tbody: {}\n\theaders: {}",
|
|
428
384
|
resp.status_code,
|
|
429
385
|
resp.text or "Empty",
|
|
386
|
+
resp.headers or "None"
|
|
430
387
|
)
|
|
431
388
|
return resp
|
|
432
389
|
|
|
@@ -2,6 +2,7 @@ import argparse
|
|
|
2
2
|
import os
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
5
|
+
import math
|
|
5
6
|
|
|
6
7
|
from requests import JSONDecodeError
|
|
7
8
|
|
|
@@ -15,6 +16,11 @@ def get_config():
|
|
|
15
16
|
parser.add_argument("--head", help="Header Info JSON file")
|
|
16
17
|
parser.add_argument("--claims", help="Vapid claim file")
|
|
17
18
|
parser.add_argument("--key", help="Vapid private key file path")
|
|
19
|
+
parser.add_argument(
|
|
20
|
+
"--wns",
|
|
21
|
+
help="Include WNS cache header based on TTL",
|
|
22
|
+
default=False,
|
|
23
|
+
action="store_true")
|
|
18
24
|
parser.add_argument(
|
|
19
25
|
"--curl",
|
|
20
26
|
help="Don't send, display as curl command",
|
|
@@ -53,6 +59,15 @@ def get_config():
|
|
|
53
59
|
args.head = json.loads(r.read())
|
|
54
60
|
except JSONDecodeError as e:
|
|
55
61
|
raise WebPushException("Could not read the header arguments: {}", e)
|
|
62
|
+
# Set the default "TTL"
|
|
63
|
+
args.head["ttl"] = args.head.get("ttl", "0")
|
|
64
|
+
if args.wns:
|
|
65
|
+
# NOTE: Microsoft also requires `X-WNS-Type` as
|
|
66
|
+
# `tile`, `toast`, `badge` or `raw`. This is not provided by this code.
|
|
67
|
+
if int(args.head.get("ttl", "0")) > 0:
|
|
68
|
+
args.head["x-wns-cache-policy"] = "cache"
|
|
69
|
+
else:
|
|
70
|
+
args.head["x-wns-cache-policy"] = "no-cache"
|
|
56
71
|
if args.claims:
|
|
57
72
|
if not args.key:
|
|
58
73
|
raise WebPushException("No private --key specified for claims")
|
|
@@ -329,21 +329,6 @@ class WebpushTestUtils(unittest.TestCase):
|
|
|
329
329
|
del ci["FOO"]
|
|
330
330
|
assert ci.get("Foo") is None
|
|
331
331
|
|
|
332
|
-
@patch("requests.post")
|
|
333
|
-
def test_gcm(self, mock_post):
|
|
334
|
-
subscription_info = self._gen_subscription_info(
|
|
335
|
-
None, endpoint="https://android.googleapis.com/gcm/send/regid123"
|
|
336
|
-
)
|
|
337
|
-
headers = {"Crypto-Key": "pre-existing", "Authentication": "bearer vapid"}
|
|
338
|
-
data = "Mary had a little lamb"
|
|
339
|
-
wp = WebPusher(subscription_info)
|
|
340
|
-
wp.send(data, headers, gcm_key="gcm_key_value")
|
|
341
|
-
pdata = json.loads(mock_post.call_args[1].get("data"))
|
|
342
|
-
pheaders = mock_post.call_args[1].get("headers")
|
|
343
|
-
assert pdata["registration_ids"][0] == "regid123"
|
|
344
|
-
assert pheaders.get("authorization") == "key=gcm_key_value"
|
|
345
|
-
assert pheaders.get("content-type") == "application/json"
|
|
346
|
-
|
|
347
332
|
@patch("requests.post")
|
|
348
333
|
def test_timeout(self, mock_post):
|
|
349
334
|
mock_post.return_value.status_code = 200
|
|
@@ -406,21 +391,6 @@ class WebPusherAsyncTestCase(WebpushTestUtils, unittest.IsolatedAsyncioTestCase)
|
|
|
406
391
|
assert pheaders.get("ttl") == "0"
|
|
407
392
|
assert pheaders.get("content-encoding") == "aes128gcm"
|
|
408
393
|
|
|
409
|
-
@patch("aiohttp.ClientSession.post", new_callable=AsyncMock)
|
|
410
|
-
async def test_fcm(self, mock_post):
|
|
411
|
-
subscription_info = self._gen_subscription_info(
|
|
412
|
-
None, endpoint="https://android.googleapis.com/fcm/send/regid123"
|
|
413
|
-
)
|
|
414
|
-
headers = {"Crypto-Key": "pre-existing", "Authentication": "bearer vapid"}
|
|
415
|
-
data = "Mary had a little lamb"
|
|
416
|
-
wp = WebPusher(subscription_info)
|
|
417
|
-
await wp.send_async(data, headers, gcm_key="gcm_key_value")
|
|
418
|
-
pdata = json.loads(mock_post.call_args[1].get("data"))
|
|
419
|
-
pheaders = mock_post.call_args[1].get("headers")
|
|
420
|
-
assert pdata["registration_ids"][0] == "regid123"
|
|
421
|
-
assert pheaders.get("authorization") == "key=gcm_key_value"
|
|
422
|
-
assert pheaders.get("content-type") == "application/json"
|
|
423
|
-
|
|
424
394
|
@patch("aiohttp.ClientSession.post", new_callable=AsyncMock)
|
|
425
395
|
async def test_timeout(self, mock_post):
|
|
426
396
|
mock_post.return_value.status_code = 200
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pywebpush
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: WebPush publication library
|
|
5
5
|
Author-email: JR Conlin <src+webpusher@jrconlin.com>
|
|
6
6
|
License: MPL-2.0
|
|
@@ -10,6 +10,7 @@ Classifier: Topic :: Internet :: WWW/HTTP
|
|
|
10
10
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
11
11
|
Classifier: Programming Language :: Python
|
|
12
12
|
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Requires-Python: >=3.10
|
|
13
14
|
Description-Content-Type: text/markdown
|
|
14
15
|
License-File: LICENSE
|
|
15
16
|
Requires-Dist: aiohttp
|
|
@@ -26,9 +27,6 @@ Dynamic: license-file
|
|
|
26
27
|
|
|
27
28
|
# Webpush Data encryption library for Python
|
|
28
29
|
|
|
29
|
-
[](https://travis-ci.org/web-push-libs/pywebpush)
|
|
30
|
-
[](https://requires.io/github/web-push-libs/pywebpush/requirements/?branch=main)
|
|
31
|
-
|
|
32
30
|
This library is available on [pypi as pywebpush](https://pypi.python.org/pypi/pywebpush).
|
|
33
31
|
Source is available on [github](https://github.com/mozilla-services/pywebpush).
|
|
34
32
|
Please note: This library was designated as a `Critical Project` by PyPi, it is currently
|
|
@@ -64,6 +62,11 @@ referenced to the user who requested it, and recall it when there's
|
|
|
64
62
|
a new push subscription update is left as an exercise for the
|
|
65
63
|
reader.
|
|
66
64
|
|
|
65
|
+
_*Note:*_ Some platforms (like Microsoft Windows) require additional
|
|
66
|
+
headers specified for the Push call. These additional headers are not
|
|
67
|
+
standard and may be rejected by other Push services. Please see
|
|
68
|
+
[Special Instructions](#special-instructions) below.
|
|
69
|
+
|
|
67
70
|
### Sending Data using `webpush()` One Call
|
|
68
71
|
|
|
69
72
|
In many cases, your code will be sending a single message to many
|
|
@@ -82,7 +85,7 @@ webpush(subscription_info,
|
|
|
82
85
|
This will encode `data`, add the appropriate VAPID auth headers if required and send it to the push server identified
|
|
83
86
|
in the `subscription_info` block.
|
|
84
87
|
|
|
85
|
-
|
|
88
|
+
#### Parameters
|
|
86
89
|
|
|
87
90
|
_subscription_info_ - The `dict` of the subscription info (described above).
|
|
88
91
|
|
|
@@ -107,7 +110,7 @@ e.g. the output of:
|
|
|
107
110
|
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
|
|
108
111
|
```
|
|
109
112
|
|
|
110
|
-
|
|
113
|
+
#### Example
|
|
111
114
|
|
|
112
115
|
```python
|
|
113
116
|
from pywebpush import webpush, WebPushException
|
|
@@ -145,7 +148,7 @@ can pass just `wp = WebPusher(subscription_info)`. This will return a `WebPusher
|
|
|
145
148
|
|
|
146
149
|
The following methods are available:
|
|
147
150
|
|
|
148
|
-
#### `.send(data, headers={}, ttl=0,
|
|
151
|
+
#### `.send(data, headers={}, ttl=0, reg_id="", content_encoding="aes128gcm", curl=False, timeout=None)`
|
|
149
152
|
|
|
150
153
|
Send the data using additional parameters. On error, returns a `WebPushException`
|
|
151
154
|
|
|
@@ -157,9 +160,6 @@ _headers_ A `dict` containing any additional headers to send
|
|
|
157
160
|
|
|
158
161
|
_ttl_ Message Time To Live on Push Server waiting for the client to reconnect (in seconds)
|
|
159
162
|
|
|
160
|
-
_gcm_key_ Google Cloud Messaging key (if using the older GCM push system) This is the API key obtained from the Google
|
|
161
|
-
Developer Console.
|
|
162
|
-
|
|
163
163
|
_reg_id_ Google Cloud Messaging registration ID (will be extracted from endpoint if not specified)
|
|
164
164
|
|
|
165
165
|
_content_encoding_ ECE content encoding type (defaults to "aes128gcm")
|
|
@@ -172,10 +172,10 @@ See [requests documentation](http://docs.python-requests.org/en/master/user/quic
|
|
|
172
172
|
|
|
173
173
|
##### Example
|
|
174
174
|
|
|
175
|
-
to send
|
|
175
|
+
to send to a user on Chrome:
|
|
176
176
|
|
|
177
177
|
```python
|
|
178
|
-
WebPusher(subscription_info).send(data, headers, ttl
|
|
178
|
+
WebPusher(subscription_info).send(data, headers, ttl)
|
|
179
179
|
```
|
|
180
180
|
|
|
181
181
|
#### `.encode(data, content_encoding="aes128gcm")`
|
|
@@ -188,7 +188,7 @@ _data_ Binary string of data to send
|
|
|
188
188
|
|
|
189
189
|
_content_encoding_ ECE content encoding type (defaults to "aes128gcm")
|
|
190
190
|
|
|
191
|
-
*Note* This will return a `NoData` exception if the data is not present or empty. It is completely
|
|
191
|
+
_*Note*_ This will return a `NoData` exception if the data is not present or empty. It is completely
|
|
192
192
|
valid to send a WebPush notification with no data, but encoding is a no-op in that case. Best not
|
|
193
193
|
to call it if you don't have data.
|
|
194
194
|
|
|
@@ -200,8 +200,7 @@ encoded_data = WebPush(subscription_info).encode(data)
|
|
|
200
200
|
|
|
201
201
|
## Stand Alone Webpush
|
|
202
202
|
|
|
203
|
-
If you're not really into coding your own solution, there's also a "stand-alone" `pywebpush` command in the
|
|
204
|
-
./bin directory.
|
|
203
|
+
If you're not really into coding your own solution, there's also a "stand-alone" `pywebpush` command in the `./bin` directory.
|
|
205
204
|
|
|
206
205
|
This uses two files:
|
|
207
206
|
|
|
@@ -227,3 +226,40 @@ If you're interested in just testing your applications WebPush interface, you co
|
|
|
227
226
|
which will encrypt and send the contents of `stuff_to_send.data`.
|
|
228
227
|
|
|
229
228
|
See `./bin/pywebpush --help` for available commands and options.
|
|
229
|
+
|
|
230
|
+
## Special Instructions
|
|
231
|
+
|
|
232
|
+
### Windows
|
|
233
|
+
|
|
234
|
+
[Microsoft requires](https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/push-request-response-headers#request-parameters)
|
|
235
|
+
one extra header and suggests several additional headers. Users have reported that not including
|
|
236
|
+
these headers can cause notifications to fail to appear. These additional headers are non-standard
|
|
237
|
+
and may be rejected by other platforms. You should be cautious including them with calls to
|
|
238
|
+
non-Microsoft platforms, or to non-Microsoft destinations.
|
|
239
|
+
|
|
240
|
+
As of 2024-Apr-19, Microsoft requires an `X-WNS-Type` header. As an example, you can include this
|
|
241
|
+
header within the command line call:
|
|
242
|
+
|
|
243
|
+
Content of the `windows_headers.json` file:
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{"X-WNS-Type":"wns/toast", "TTL":600, "Content-Type": "text/xml"}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
_*Note*_ : This includes both the `TTL` set to 10 minutes and the required matching `Content-Type` header for `wns/toast`.
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
pywebpush --data stuff_to_send.xml \
|
|
253
|
+
--info edge_user_info.json \
|
|
254
|
+
--head windows_headers.json \
|
|
255
|
+
--claims vapid_claims.json
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Google Cloud Messaging (GCM)
|
|
259
|
+
|
|
260
|
+
Please note that GCM has been sunset by Google. Providers should
|
|
261
|
+
use [Firebase Cloud Messaging](https://firebase.google.com/support/troubleshooter/fcm/tokens/gcm) instead.
|
|
262
|
+
|
|
263
|
+
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).
|
|
264
|
+
|
|
265
|
+
Sending WebPush messages to Google Chrome users should not be impacted by this change.
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
## Description
|
|
2
|
-
|
|
3
|
-
*_NOTE_*: All commits MUST be signed! See https://docs.github.com/en/github/authenticating-to-github/signing-commits
|
|
4
|
-
|
|
5
|
-
_Describe these changes._
|
|
6
|
-
|
|
7
|
-
## Testing
|
|
8
|
-
|
|
9
|
-
_How should reviewers test?_
|
|
10
|
-
|
|
11
|
-
## Issue(s)
|
|
12
|
-
|
|
13
|
-
Closes _#IssueNumber_
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|