web-push-libs / pywebpush Goto Github PK
View Code? Open in Web Editor NEWPython Webpush Data encryption library
License: Mozilla Public License 2.0
Python Webpush Data encryption library
License: Mozilla Public License 2.0
Im trying to use pywebpush under python 2.7 (and 3.5) without any success. I am getting the error UnauthorizedRegistration
with a 400
response code. Using the Push Companion, everything works just fine (with the same key and same subscription info).
Also, my internal clock is synced (some people reported having issues if your clock is not synced).
My code :
from pywebpush import WebPusher
import json
sub = json.loads('{"endpoint":"https://fcm.googleapis.com/fcm/send/<redacted>","keys":{"p256dh":"<redacted>","auth":"<redacted>"}}')
r = WebPusher(sub).send(data='hey')
Which returns :
> r.text
u'<HTML>\n<HEAD>\n<TITLE>UnauthorizedRegistration</TITLE>\n</HEAD>\n<BODY BGCOLOR="#FFFFFF" TEXT="#000000">\n<H1>UnauthorizedRegistration</H1>\n<H2>Error 400</H2>\n</BODY>\n</HTML>\n'
> r.status_code
400
I am getting the same result no matter which Python version I use.
Any help debugging this would be really really appreciated...
In my experience, the default expiry of 24hours might be causing errors on the push backends of Google and Mozilla. They reject the request, with Mozilla reporting that the expiry is too far in the future, probably due to slight clock differences.
I would suggest to reduce the default expiry time in order to avoid such problems.
Hey there, I'm trying to make a webpush call, but its giving me the error:
'unicode' object has no attribute 'get'
It looks like that error is being triggered by
url = urlparse(subscription_info.get('endpoint'))
'
Any idea what might be causing this?
Is there any way to get the HTTP response code / or the response object on WebPushException.
Mozilla for example sends a 410 code when the subscription isn't valid anymore.
In this case I want to delete the subscription from my list.
raise WebPushException("Push failed: {}: {}".format( result, result.text))
You format the result to string which of course could be parsed. I wonder if there is a better solution.
Hi @jrconlin
I am trying to send Push Notification to Chrome Browser using Pywebpush Library. But the call seems to be not working.
I am trying the following code:
subscription_info = {'endpoint': endpoint, 'keys': {'p256dh': p256dh_key, 'auth': auth_key}}
notify_data = {"data": "Hello"}
headers = {'Content-Type': 'application/json'}
gcm_key = "AIzaSXXXXXXXXXXXXXXXXXXXXX"
resp = WebPusher(subscription_info).send(notify_data, headers, 3600, gcm_key)
And I am getting this as the Error:
TypeError: send() takes at most 4 arguments (5 given)
Can you please suggest how can I use Pywebpush send() to send Push Notification to Chrome Browser ?
Thanks,
I was just trying to pywebpush on appengine and one of the problems I was hitting is an issue with cryptography module:
ImportError: No module named cryptography.hazmat.bindings._constant_time
After googling it is either an issue with my setup (which generally has mixed solutions), or it could be appengine running in a weird environment / container that means the compiled library for my machine fails to work on App Engine.
Looking at the docs for AppEngine it looks like the make crypto library is pycrypto. I was just wondering if that could* be an option for this library?
I'm not a Python developer so if cryptography is the main module developers use then please close this issue, but if there is no strong opinion would you be open to taking a PR to switch?
Is that possible to do push notifications in serviceworker without depending on thirdparty like
GCM or mozilla push services?
Is that possible to have our own push servers?
If TTL is specified (as an integer) then the associated header value is in error (since it's not a string).
Seems str(ttl) should be used?
if 'ttl' not in headers or ttl:
headers['ttl'] = str(ttl)
Add in GCM compatibility per gobletsky's fork.
I have installed pywebpush globally. My code is below config.py
from pywebpush import WebPusher
subscription_info = {"endpoint":"https://android.googleapis.com/gcm/send/e8N4w87NpOE:APA91bFmYdTBaeROOmBbzKoHD6X6QsQfJEA_Jvrzbsgc0gm-6eKlJOb20H0CQ47v6_CLIXPstre6r-7X06ea_Vm_EtTkGMKAc_e2tBN7WhaiNzhspuKcr1IHKz6ucyxe8FWrvRXyFWwr","keys":{"p256dh":"BE0i3dGxDr4aJ0ACZ-JQtcPieaXZaAS1eYqRHP4kJKGzxNe8SEd8En_JtyY7ZEB8COPVUD4wM4AAzuGS7GZBvPY=","auth":"7Gg9jurx6AUPAwD3hA0ZwQ=="}}
data = "{test:'hello'}"
headers = {'Authorization' : 'key=firebase_server_key'}
gcm = 'firebase_server_key'
wp = WebPusher(subscription_info)
wp.send(data, headers,ttl=0,gcm_key=gcm)
my python version 2.7.10
When I tried to run the above code giving error
Webpush supports sending empty payloads.
For most use case we have with Kinto it makes sense to just try to resync on push notifications and not worry about any payload.
It would be nice for pywebpush to handle send(data=None )
Make the library Python 3+ compliant
I have done some tests with push notification and works. But when I integrate with django, I get this error:
File "/Users/myuser/.virtualenvs/myenv/lib/python3.6/site-packages/pywebpush/__init__.py", line 359, in webpush
vv = Vapid.from_string(private_key=vapid_private_key)
File "/Users/myuser/.virtualenvs/myenv/lib/python3.6/site-packages/py_vapid/__init__.py", line 142, in from_string
return cls.from_der(pkey)
File "/Users/myuser/.virtualenvs/myenv/lib/python3.6/site-packages/py_vapid/__init__.py", line 99, in from_der
backend=default_backend())
File "/Users/myuser/.virtualenvs/myenv/lib/python3.6/site-packages/cryptography/hazmat/primitives/serialization.py", line 28, in load_der_private_key
return backend.load_der_private_key(data, password)
File "/Users/myuser/.virtualenvs/myenv/lib/python3.6/site-packages/cryptography/hazmat/backends/multibackend.py", line 323, in load_der_private_key
return b.load_der_private_key(data, password)
File "/Users/myuser/.virtualenvs/myenv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1018, in load_der_private_key
password,
File "/Users/myuser/.virtualenvs/myenv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1160, in _load_key
self._handle_key_loading_error()
File "/Users/myuser/.virtualenvs/myenv/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1229, in _handle_key_loading_error
raise ValueError("Could not deserialize key data.")
ValueError: Could not deserialize key data.
Why?
Hi @jrconlin
I am trying to use PyWebpush Library in my python code and I am seeing these 3 kind of issues on the server side logs for chrome notifications(working absolutely fine in all cases on local server):
ConnectionError(ProtocolError('Connection aborted.', error(0, 'Error')),)
'[OpenSSL] EC_KEY_generate_key FAIL ... error:00000000:lib(0):func(0):reason(0)',)
extern "Python": function Cryptography_rand_bytes() called, but @ffi.def_extern() was not called in the current subinterpreter. Returning 0.
Can you please suggest how can these issues be resolved ?
Thanks,
using the urlparse library:
aud_parsed = urlparse(_curr_user.push.subscription_info.endpoint)
aud = ("{}://{}").format(aud_parsed.scheme, aud_parsed.netloc)
<WebPusher object>.aud => https://fcm.googleapis.com
(Or mozilla or whatever endpoint is defined)
Please add ttl option to webpush function. It's too complicated to call WebPusher.
webpush function is great, but if I need to set TTL, then I can't use it.
Thank you.
The README is using Markdown which works well for Github that handles both Markdown and ReStructuredText.
But since the README is used as the long_description in the setup.py
the content is also used in Pypi which only understand ReStructuredText.
This might be a StackOverflow-type question but I'm constantly getting 401 Unauthorized
, errcode 109 (Invalid authentication) and message: "Request did not validate missing authorization header". I'm using VAPID headers to a Mozilla push endpoint as suggested in #30
I use this line to send the notification:
x = pywebpush.WebPusher(subscription_info).send(data, vapid_headers, 60*60)
The authorization header appears to be present (logged x.request.headers
):
{ 'Accept': '*/*', 'authorization': 'WebPush eyJ0eXAiOi...', 'crypto-key': "p256ecdsa=b'Nz2H1lIDt...7b7OAfMA-bwZP6qk_WonOnahzw7iDx4rA';keyid=p256dh;dh=BCvGo_YbulU_xUnT-U...", 'ttl': '3600', 'Accept-Encoding': 'gzip, deflate', 'content-encoding': 'aesgcm', 'encryption': 'keyid=p256dh;salt=azMk5vK0...', 'User-Agent': 'python-requests/2.11.1', 'Connection': 'keep-alive', 'Content-Length': '370' }
The lengthy details (sorry) below show what I do:
subscription_info = {'endpoint': 'https://updates.push.services.mozilla.com/wpush/v2/gAA...', 'keys': {'p256dh': 'BJv7nI...p31z4Qvt86+oeQMfZk5Nb/fhko...wmPXvo99A=', 'auth': '2Y4...+WA=='}}
data = json.loads({'abc': 'def'})
vapid_headers = _make_vapid_headers(endpoint)
(endpoint
is from subscription_info
)
Relevant definitions below (and possibly where an error lies, as I attempted to fix an issue I got in python3 running the original code from https://blog.mozilla.org/services/2016/04/04/using-vapid-with-webpush/ )
# generated with openssl ecparam -name prime256v1 -genkey -noout -out vapid_private.pem
VAPID_PRIVATE_KEY_PATH = 'vapid_private.pem'
priv_key = open(VAPID_PRIVATE_KEY_PATH, 'r', encoding='utf-8').read()
VAPID_PRIVATE_KEY_CONTENTS = SigningKey.from_pem(priv_key) # from ecdsa import SigningKey
# As seen in https://blog.mozilla.org/services/2016/04/04/using-vapid-with-webpush/
def _make_jwt(header, claims, key):
vk = key.get_verifying_key()
jwt = jws.sign(
claims,
key,
algorithm=header.get('alg', 'ES256')).strip('=')
raw_public_key = b'\x04' + vk.to_string() # need to work with bytes
public_key = base64.urlsafe_b64encode(raw_public_key).strip(b'=')
return (jwt, public_key)
def _make_vapid_headers(endpoint):
header = {'typ': 'JWT', 'alg': 'ES256'}
origin = endpoint.split('.com')[0] + '.com'
claims = {
'aud': origin,
'exp': '{}'.format(int(time()) + 60*60*12), # import time from time
'sub': 'mailto:[email protected]'
}
my_key = settings.VAPID_PRIVATE_KEY_CONTENTS
(jwt, public_key) = _make_jwt(header, claims, my_key)
headers = {
'Authorization': 'WebPush {}'.format(jwt),
'Crypto-Key': 'p256ecdsa={}'.format(public_key)
}
return headers
I followed the instructions for getting the public key to send to the frontend from https://blog.mozilla.org/services/2016/08/23/sending-vapid-identified-webpush-notifications-via-mozillas-push-service/ where I removed -----BEGIN PUBLIC KEY
, made the key urlsafe, etc.
Payload in web push is not necessary. Also for this case not necessary encription keys.
Please check the following links:
https://tools.ietf.org/html/draft-thomson-webpush-vapid-02#page-6
https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe
I believe option is necessary to send encrypted messages.
The server key is currently used for WebPusher.encode()
The comment says
The server key is an ephemeral ECDH key used only for this transaction
However, I believe this key is not only for this transaction but also for the subscribe method.
Please introduce the above features in it.
IDEs like PyCharm and others use typing and doc hints very well.
RFC 8188 has been out for over a year. It's high time to set the default encoding method to "aes128gcm".
Be aware that support for the RFC draft "aesgcm" content encoding may be terminated without warning.
Hello all, I am trying to install pywebpush
using pip install pywebpush
but I am unable to do so. I am getting following error.
kapil@sohan:~/Projects/pywebpush$ pip install pywebpush
Downloading/unpacking pywebpush
Downloading pywebpush-1.0.5.tar.gz
Running setup.py (path:/tmp/pip_build_kapil/pywebpush/setup.py) egg_info for package pywebpush
Downloading/unpacking cryptography>=1.8.1,<1.10 (from pywebpush)
Downloading cryptography-1.9.tar.gz (409kB): 409kB downloaded
Running setup.py (path:/tmp/pip_build_kapil/cryptography/setup.py) egg_info for package cryptography
no previously-included directories found matching 'docs/_build'
warning: no previously-included files matching '*' found under directory 'vectors'
Downloading/unpacking http-ece>=1.0.1 (from pywebpush)
Downloading http_ece-1.0.2.tar.gz
Running setup.py (path:/tmp/pip_build_kapil/http-ece/setup.py) egg_info for package http-ece
error in http_ece setup command: 'install_requires' must be a string or list of strings containing valid project/version requirement specifiers
Complete output from command python setup.py egg_info:
error in http_ece setup command: 'install_requires' must be a string or list of strings containing valid project/version requirement specifiers
----------------------------------------
Cleaning up...
Command python setup.py egg_info failed with error code 1 in /tmp/pip_build_kapil/http-ece
Storing debug log for failure in /tmp/tmpaWU6LN
And complete log file is error.log
And if I try to install it as it said in the README
file I get this error
I am unable to install it by any way.
Is there a reason that pywebpush
depends on specific version of requests
?
When I run pip check
after upgrading requests
, I get this error:
$ pip check
pywebpush 1.0.2 has requirement requests==2.13.0, but you have requests 2.14.2.
Is there a reason that install_requires
in setup.py
pins the dependencies to certain version numbers? (Related: install_requires vs Requirements files)
Any kind of documentation is available on how to use this library?
Chrome supports VAPID headers, announced:
https://developers.google.com/web/updates/2016/07/web-push-interop-wins
Switch to check for VAPID headers OR gcm_id when sending out subscription updates for Chrome.
https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-04 has introduced a new encoding method. This has not yet elevated to all clients, but we should add it as an optional format for when it is available.
Switch to cryptography to solve abandoned library problems like #48 as well as become faster.
Can we send web push to multiple devices with chrome and firefox ? It takes too long to send to a few thousand subscriber ?
If you are open to the idea, I'd be interested in adding integration tests for Chrome and Firefox for pywebpush using web-push-testing-service.
It's a node script that starts a server that accepts REST api calls, you can then request starting of a browser, getting a subscription and then request the last push received (i.e. after you sent a push message, request what was received).
The node cli app works fine:
web-push send-notification \
--endpoint="https://fcm.googleapis.com/fcm/send/<ENDPOINT>" \
--key="<KEY>" \
--auth="<AUTH>" \
--vapid-subject="mailto:[email protected]" \
--vapid-pubkey="<VAPID_PUBKEY>" \
--vapid-pvtkey="<VAPID_PRIVATEKEY>" \
--payload='{"version":"1"}'
but pywebpush fails using the same keys:
subscription_info = {
'endpoint': 'https://fcm.googleapis.com/fcm/send/<ENDPOINT>',
'keys': {
'auth': '<AUTH>',
'p256dh': '<KEY>',
}
}
webpush(
subscription_info,
json.dumps({'version': '1'}),
vapid_private_key='<VAPID_PRIVATEKEY>',
vapid_claims={
'sub': 'mailto:[email protected]'
},
)
throws an exception:
Push failed: <Response [400]>: <HTML>
<HEAD>
<TITLE>UnauthorizedRegistration</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>UnauthorizedRegistration</H1>
<H2>Error 400</H2>
</BODY>
</HTML>
Using chrome version 57. Get 400s with chrome and not on Firefox. Have tried just about everything under the sun. I know there have complaints about this before. Any solutions to the problems before?
Hi @jrconlin ,
I am trying to use Pywebpush Library in my Project.
When I try:
from pywebpush import WebPusher
resp = WebPusher(subscription_info).send(data, headers)
this code works
But if I try:
from pywebpush import WebPush
It doesn't work. Can you please suggest how can I use WebPush for just encrypting the Data (and not sending the actual notification)?
Thanks,
cryptography 1.8.2 will not compile with libressl because of some bugs that was fixed on 1.9.0. Is it possible to change requirements.txt to use cryptography>=1.8.2 so the latest will be used?
I am using invalid aud (Getting exception because of this)
Here's my endpoint -
https://fcm.googleapis.com/fcm/send/fqMtZMP5GqE:APA91bEKyYNmx83T2_IruAg1olf4zNnyVqL0hpiz8wkVy0ltIxBZ-Dcl4LMg86YBSek9fWhphZIRMqr03G6uonTHF-nyZwypO8JV-sPlDEzjvS9_ce7bGuLYdCnxmhSC6ZYxhFat0sI1
How to find out it's aud?
I am trying to send this block as notification:
{
"title": "Hello",
"body": "World",
"renotify": true
}
But it gets compiled into:
{"notification":{"title":"{'renotify': True, 'title': 'Hello', 'body': 'World'}"}}
Please advise
When trying to send a push message to a firefox endpoint I get this error no matter what I try:
Traceback (most recent call last):
File "/Users/Lieuwe/projects/hydra/venv/lib/python3.5/site-packages/channels/worker.py", line 119, in run
consumer(message, **kwargs)
File "/Users/Lieuwe/projects/hydra/venv/lib/python3.5/site-packages/channels/sessions.py", line 78, in inner
return func(*args, **kwargs)
File "/Users/Lieuwe/projects/hydra/venv/lib/python3.5/site-packages/channels/auth.py", line 42, in inner
return func(message, *args, **kwargs)
File "/Users/Lieuwe/projects/wendchat/consumers.py", line 61, in ws_message
getattr(message_handlers, cmd)(message, data)
File "/Users/Lieuwe/projects/wendchat/message_handlers.py", line 142, in on_message
send_push_message(target, "Hallo wereld!")
File "/Users/Lieuwe/projects/wendchat/methods.py", line 123, in send_push_message
vapid_claims=chat_settings.CHAT_VAPID_CLAIM
File "/Users/Lieuwe/projects/hydra/venv/lib/python3.5/site-packages/pywebpush/__init__.py", line 370, in webpush
result, result.text))
pywebpush.WebPushException: Push failed: <Response [401]>: {"code": 401, "errno": 109, "error": "Unauthorized", "more_info": "http://autopush.readthedocs.io/en/latest/http.html#error-codes", "message": "Request did not validate missing authorization header"}
I'm generating the vapid keys as follows:
vapid = Vapid()
vapid.generate_keys()
vapid.save_key('vapid.private.pem')
vapid.save_public_key(vapid.public.pem)
The client then returns a subscription like
{"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/gAAAAABaJRho_CagHOmnZA_qWzmKYyHuKCLL5cWTgNPZ8kx9AN6eKoyTr-sQYxcfmLnx_ddeE3GhlCgvELYu4a8sFOAihmCf0PzF_uaVMcAmOr7z1O8RKk006sEnK0qOULpumVOkMWQB1y237gQodOl686nwVvfefYHnVh_rY73f_jh8pLod-iY","keys":{"auth":"ImHBySkqpnaySV_PUbGKzQ","p256dh":"BOghS7L240dUayNDc0NP8jI-iEqLBWFOqElCRJyWyLEDEezNYwtyobd5JUFPv536o_YiB_zUwT8RRJLYYZXRaAM"}}
And I send a push notification like this
webpush(
json.loads(sub.info),
message,
vapid_private_key='vapid.private.pem',
vapid_claims=CHAT_VAPID_CLAIM = {"sub": "mailto:<redacted>", 'aud': 'https://localhost:8000'}
)
When dumping the sent request using the curl option I do see an authorization header, so I'm not sure why the error is complaining about that header missing.
Any help would be greatly appreciated.
I have an object in my Django config for vapid claims and I'm using it in the webpush method.
I couldn't realize why after sending push messages on Firefox I was constantly getting "unauthorized registration" errors on Chrome, until I saw that the object passed as vapid_claims
parameter gets modified from something like this:
{
'sub': 'mailto:<my_email>'
}
to this :
{
'aud': 'https://updates.push.services.mozilla.com',
'exp': '1508309139',
'sub': 'mailto:<my_email>'
}
I tried passing every time a new object and everything works fine, but now I'm wondering, is this expected behavior, and am I supposed to store that modified object?
This package is on pypi:
https://pypi.python.org/pypi/pywebpush/
It's unclear whether that's an official package, seeing as there are no git-tagged releases and README.md does not mention it. If it is an official package, I would suggest doing both of those.
Edit: As a sidenote, this repo should really be deleted or turned into just a README.
Use case
I'm using this lib and especially the WebPusher object to send Vapid Web Push.
Why don't I use the webpush function ? Because my app can use the same WebPusher instance throughout its entire lifetime. That is why, for optimisation reason, I prefer using the same requests.Session() object each time I need WebPush.
The issue is that the subscription_info changes almost every time but I don't want to instanciate a new WebPusher;
Current workaround
in my wrapper, I have this method :
def _update_subscription_info(self, subscription_info):
# Here we naively copy the operations linked to subscription_info
# from WebPusher.__init__()
# aka validate subscription_info and store keys
# Mandatory because subscription_info keeps changing
if 'endpoint' not in subscription_info:
raise WebPushException(
"subscription_info missing endpoint URL"
)
self.webpusher.subscription_info = deepcopy(subscription_info)
self.webpusher.auth_key = self.webpusher.receiver_key = None
if 'keys' in subscription_info:
keys = self.webpusher.subscription_info['keys']
for k in ['p256dh', 'auth']:
if keys.get(k) is None:
raise WebPushException(
"Missing keys value: {}".format(k))
if isinstance(keys[k], six.string_types):
keys[k] = bytes(keys[k].encode('utf8'))
receiver_raw = base64.urlsafe_b64decode(
self.webpusher._repad(keys['p256dh']))
if len(receiver_raw) != 65 and receiver_raw[0] != "\x04":
raise WebPushException("Invalid p256dh key specified")
self.webpusher.receiver_key = receiver_raw
self.webpusher.auth_key = base64.urlsafe_b64decode(
self.webpusher._repad(keys['auth']))
which is quite a dirty hack as it's just a copy/paste.
Question
Would you implement such a method in a more graceful way directly in the WebPusher, in order to simply be able to do a my_web_pusher.update_subscription_info(subscription_info)
?
If needed, I could spend a bit of time to suggest a PR.
Currently the keyid for aes128gcm is being passed as base64 encoded instead of raw values. We shouldn't pass a keyid at all, really.
See webpush-wg/webpush-encryption#6
Due to some confusion about how keys should be specified, some Push Service providers reject "," separated components. A work around is to use ";" for all fields.
When I try to get push messaging to clients working I get the following error produced by OpenSSL probably.
Traceback (most recent call last):
File "manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 367, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 359, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 294, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 345, in execute
output = self.handle(*args, **options)
File "/home/sem/scorpios-web/ScorpiosWeb/sc/management/commands/updateborrels.py", line 36, in handle
webpush(subscription_info, data=str(message), vapid_private_key=vapid_path, vapid_claims=claims)
File "/usr/local/lib/python2.7/dist-packages/pywebpush/__init__.py", line 356, in webpush
curl=curl,
File "/usr/local/lib/python2.7/dist-packages/pywebpush/__init__.py", line 288, in send
headers=headers)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 112, in post
return request('post', url, data=data, json=json, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/api.py", line 58, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 513, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/sessions.py", line 623, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/requests/adapters.py", line 514, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE', 'certificate verify failed')],)",)
import os
from datetime import date
from pywebpush import webpush, WebPushException, WebPusher
from django.core.management import BaseCommand
from sc.models import PushSubscription
from sc.models.Drinks import DrinksDag, DrinksEvening
class Command(BaseCommand):
help = 'Cronjob to automatically update this drinks evening'
def handle(self, *args, **options):
now = date.today()
drinks_day = DrinksDay.get_is_drinks_date(now)
if drinks_day:
DrinksEvening(date=now).save()
if not drinks_day.is_recurring():
drinks_day.delete()
devices = PushSubscription.objects.all()
for device in devices:
subscription_info = {'endpoint': device.endpoint, 'keys': {'auth': device.auth, 'p256dh': device.p256dh}}
message_title = "Drinks evening update"
message_body = "Good evening participant"
message = {'title': message_title, 'body': message_body}
try:
vapid_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../../private_key.pem')
claims = {'sub': '[email protected]', 'aud': 'https://fcm.googleapis.com'}
webpush(subscription_info, data=str(message), vapid_private_key=vapid_path, vapid_claims=claims)
except WebPushException as e:
print("Unable to webpush: {}", repr(e))
My endpoint is in the form of https://fcm.googleapis.com/fcm/send/ { private endpoint }.
Do you have an idea what is going wrong, I have generated the private_key.pem with this vapid library (python) and I also generated the application server public key and pasted that in the javascript client side. Thanks
Requests is a popular requirement. By pinning the version you require all other packages that want to depend on you to use the same version. Could the requirement be made more flexible?
And now as a counter argument to this request, pywebpush currently does not work with Requests 2.11.0 due to the following change:
Some previous releases accidentally accepted non-strings as acceptable header values. This release does not.
This breaks as ttl
header defaults to the integer 0
.
VAPID r3 introduces a content type of "application/webpush-options+json".
May add an option to use this, but depends on how strict push services are about content types.
Any idea how to solve or debug this error? I'm using the latest version from master.
I get the following traceback:
pytest test_push.py
====================================================== test session starts =======================================================
platform darwin -- Python 3.6.2, pytest-3.9.1, py-1.7.0, pluggy-0.8.0
rootdir: /Users/kayibal/Downloads, inifile:
plugins: django-3.4.3
collected 1 item
test_push.py F [100%]
============================================================ FAILURES ============================================================
___________________________________________________________ test_push ____________________________________________________________
subs = {'endpoint': 'https://fcm.googleapis.com/fcm/send/cvNVGGLtZVo:APA91bFqfRXSHhqdzv6MXFKu7SFUvqyPSRlSNxER2B9cIj5OQZAC1THz...w1dNBzuNYFG7FMA', 'p256dh': 'BDz4O5Lb96W133iNj7uEmN0nnZuCDQKg8DTqa4P50stLUJ0vXBhwLker4EyMtf_U2Hr-UFf084QCxwZSR_3F70A'}}
vapid_data = {'privateKey': 'Ew2kli-56Ps6FEspgshs9MnFhhuX2mlMdXqhZqisN5w', 'publicKey': 'BEtyWjkXAXTOTN-5X018konhbR5KpAaQbM4jcWptLDzO2Ia-tm93NCY72TMh5kYAjYDThYY40FGh2BFHJeSX-04', 'subject': 'mailto:[email protected]'}
def test_push(subs, vapid_data):
webpush(subs,
'Your Push Payload Text',
vapid_private_key=vapid_data['privateKey'],
vapid_claims={"sub": "mailto:[email protected]"},
> ttl=2419200,
)
test_push.py:27:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
subscription_info = {'endpoint': 'https://fcm.googleapis.com/fcm/send/cvNVGGLtZVo:APA91bFqfRXSHhqdzv6MXFKu7SFUvqyPSRlSNxER2B9cIj5OQZAC1THz...w1dNBzuNYFG7FMA', 'p256dh': 'BDz4O5Lb96W133iNj7uEmN0nnZuCDQKg8DTqa4P50stLUJ0vXBhwLker4EyMtf_U2Hr-UFf084QCxwZSR_3F70A'}}
data = 'Your Push Payload Text', vapid_private_key = 'Ew2kli-56Ps6FEspgshs9MnFhhuX2mlMdXqhZqisN5w'
vapid_claims = {'aud': 'https://fcm.googleapis.com', 'exp': 1548326836, 'sub': 'mailto:[email protected]'}
content_encoding = 'aes128gcm', curl = False, timeout = None, ttl = 2419200
def webpush(subscription_info,
data=None,
vapid_private_key=None,
vapid_claims=None,
content_encoding="aes128gcm",
curl=False,
timeout=None,
ttl=0):
"""
One call solution to endcode and send `data` to the endpoint
contained in `subscription_info` using optional VAPID auth headers.
in example:
.. code-block:: python
from pywebpush import python
webpush(
subscription_info={
"endpoint": "https://push.example.com/v1/abcd",
"keys": {"p256dh": "0123abcd...",
"auth": "001122..."}
},
data="Mary had a little lamb, with a nice mint jelly",
vapid_private_key="path/to/key.pem",
vapid_claims={"sub": "[email protected]"}
)
No additional method call is required. Any non-success will throw a
`WebPushException`.
:param subscription_info: Provided by the client call
:type subscription_info: dict
:param data: Serialized data to send
:type data: str
:param vapid_private_key: Vapid instance or path to vapid private key PEM \
or encoded str
:type vapid_private_key: Union[Vapid, str]
:param vapid_claims: Dictionary of claims ('sub' required)
:type vapid_claims: dict
:param content_encoding: Optional content type string
:type content_encoding: str
:param curl: Return as "curl" string instead of sending
:type curl: bool
:param timeout: POST requests timeout
:type timeout: float or tuple
:param ttl: Time To Live
:type ttl: int
:return requests.Response or string
"""
vapid_headers = None
if vapid_claims:
if not vapid_claims.get('aud'):
url = urlparse(subscription_info.get('endpoint'))
aud = "{}://{}".format(url.scheme, url.netloc)
vapid_claims['aud'] = aud
if not vapid_claims.get('exp'):
# encryption lives for 12 hours
vapid_claims['exp'] = int(time.time()) + (12 * 60 * 60)
if not vapid_private_key:
raise WebPushException("VAPID dict missing 'private_key'")
if isinstance(vapid_private_key, Vapid):
vv = vapid_private_key
elif os.path.isfile(vapid_private_key):
# Presume that key from file is handled correctly by
# py_vapid.
vv = Vapid.from_file(
private_key_file=vapid_private_key) # pragma no cover
else:
vv = Vapid.from_string(private_key=vapid_private_key)
vapid_headers = vv.sign(vapid_claims)
response = WebPusher(subscription_info).send(
data,
vapid_headers,
ttl=ttl,
content_encoding=content_encoding,
curl=curl,
timeout=timeout,
)
if not curl and response.status_code > 202:
raise WebPushException("Push failed: {} {}".format(
response.status_code, response.reason),
> response=response)
E pywebpush.WebPushException: WebPushException: Push failed: 403 MismatchSenderId
I'm facing with error happens when import this library caused by the dependency 'http_ece' 0.7.1 uses the deprecated 'pyelliptic'. It seems this fixed in 'http_ece' 0.7.3
Please check here for more details.
Thank you very much.
Python pywebpush requires cryptography < 1.10, but cryptography 2.0 (up to 2.0.3) has been released. Here are the changes:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.