web-push-libs / pywebpush

Python Webpush Data encryption library
Mozilla Public License 2.0
316 stars 54 forks source link

Getting an SSLError #66

Closed SemvandenBroek closed 7 years ago

SemvandenBroek commented 7 years ago

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': 'my-email@outlook.com', '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

ricardovsilva commented 7 years ago

I'm getting same problem. D=

jrconlin commented 7 years ago

Not sure what happened to a comment I left earlier, but I think the problem might be with your local OpenSSL config. The error: bad handshake: Error([('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE', 'certificate verify failed')],)" tells me that you're trying to connect using the old, insecure SSL3 connection, and not something like TLS 1.2. I believe that Google has dropped support for SSL3. You may need to recompile SSL3 with a "no_ssl3" flag. I'm not really sure why the library is trying to connect using SSL3, since I don't think it's included in the protocol headers.

I think you may want to update your installed OpenSSL library, or modify the config to prefer TLS 1.2.

SemvandenBroek commented 7 years ago

@jrconlin Thanks for pointing this out to me, I was already Dockerizing my app and in fresh containers with a proper Python install it does no longer give me the SSLError. Thanks!

deepakkumareverest commented 6 years ago

Hi all. Very new to this but have to push notification with python. I have an html file, a main.js, a sw.js file. I have a subscription_info, a private key and a public key. Need to send notification data from python code. I have created a python file also. But dont know where to put this python file. I am running this python file but says "Traceback (most recent call last): File "/root/Documents/SampleCodesProjects/pywebpush-master/pywebpush/main.py", line 5, in from pywebpush import webpush File "/root/Documents/SampleCodesProjects/pywebpush-master/pywebpush/init.py", line 16, in import http_ece ImportError: No module named http_ece"

My Python code is : import argparse import os import json

from pywebpush import webpush

def get_config(): parser = argparse.ArgumentParser(description="WebPush tool") parser.add_argument("--data", '-d', help="Data file") parser.add_argument("--info", "-i", help="Subscription Info JSON file") parser.add_argument("--head", help="Header Info JSON file") parser.add_argument("--claims", help="Vapid claim file") parser.add_argument("--key", help="Vapid private key file path") parser.add_argument("--curl", help="Don't send, display as curl command", default=False, action="store_true") parser.add_argument("--encoding", default="aesgcm")

args = parser.parse_args()

if not args.info:
    raise Exception("Subscription Info argument missing.")
if not os.path.exists(args.info):
    raise Exception("Subscription Info file missing.")
try:
    with open(args.info) as r:
        args.sub_info = json.loads(r.read())
    if args.data:
        with open(args.data) as r:
            args.data = r.read()
    if args.head:
        with open(args.head) as r:
            args.head = json.loads(r.read())
    if args.claims:
        if not args.key:
            raise Exception("No private --key specified for claims")
        with open(args.claims) as r:
            args.claims = json.loads(r.read())
except Exception as ex:
    print("Couldn't read input {}.".format(ex))
    raise ex
return args

def main(): """ Send data """

try:
    #args = get_config()
    # result = webpush(
    #     args.sub_info,
    #     data=args.data,
    #     vapid_private_key=args.key,
    #     vapid_claims=args.claims,
    #     curl=args.curl,
    #     content_encoding=args.encoding)
    result = webpush(
        {"endpoint":"something","expirationTime":null,"keys":{"p256dh":"Something","auth":"something"}},
        data="Deepak",
        vapid_private_key='something',
        vapid_claims={"sub": "mailto:something@gmail.com"},
        curl="openssl ecparam -name prime256v1 -genkey -noout -out 'private_key'.pem",
        #content_encoding=args.encoding
    )
    print(result)
except Exception as ex:
    print("ERROR: {}".format(ex))

if name == "main": main()

I have a project with HTML, main.js and sw.js only (Not the python file). The python file is somewhere else. If i run the HTML. it works fine . I am using "https://codelabs.developers.google.com/codelabs/push-notifications/#6" tutorial. And if i send notification data from "https://web-push-codelab.glitch.me/" this site after giving subscription_info, then it works fine. Please say how to do it with python code. Where to put python file in my project? Any help will be heartly appreciated.

jrconlin commented 6 years ago

@deepakkumareverest Unfortunately, I don't really have the time right now to help you as much as I would need to.

First off, Welcome to Python! It's a fun language, but like all new things, it has it's own quirks. You might do well over on https://www.python.org/doc/ or checking for local Python meetups.

Secondly: I'd STRONGLY urge you not to run programs as "root". It's a bit like taking the doors off your house and keeping your savings on the table. While you're learning, you might want to run things in a "safe" account that has permission to only run what it needs to. You can look for tutorials about how to do this by searching for "unix security network ports". This can be a bit tricky as well, so again, if you can find someone who can help teach you, it's a tremendous advantage.

Finally, there are server backends in a variety of languages, including node.js (which is javascript that can be run on the server). If you just want to get things going quickly, and you're more comfortable writing in javascript, that might be a good option as well. With all the new things you'll be learning, it might be nice to remove a few if you can. ;)

Best of luck!

Iazzetta commented 6 years ago

I have the same problem. Requirements:

requests==2.18.4
pyOpenSSL==18.0.0
pywebpush==1.7.0
Django==2.0.3
cryptography==2.2.2
http-ece==1.0.5
py-vapid==1.4.0
jrconlin commented 6 years ago

@lazzetta: Does the above TLS 1.2 fix not work for you? If not, what is the exact error you're seeing? Also, what version of openssllib are you running?

Iazzetta commented 6 years ago

@jrconlin

Does the above TLS 1.2 fix not work for you?

I change this now in AWS configs, but did not work

Also, what version of openssllib are you running?

In python, pyOpenSSL==17.5.0, in my AWS EC2: OpenSSL 1.0.2k 26 Jan 2017

... exact error you're seeing?

requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'SSL3_GET_SERVER_CERTIFICATE', 'certificate verify failed')],)",)

jrconlin commented 6 years ago

Ok, that's a very different error. That error is returned if the server you're connecting to has an expired, mis-labeled, or otherwise invalid certificate. A quick search produced this link which might be useful.

I don't know what server you're trying to connect to, or the route you might be taking, but I'd probably investigate that first.