djacobs / PyAPNs

Python library for interacting with the Apple Push Notification service (APNs)
http://pypi.python.org/pypi/apns/
MIT License
1.22k stars 376 forks source link

Friendlier errors for invalid cert_file, key_file #107

Closed adamatan closed 9 years ago

adamatan commented 9 years ago

The problems - Cryptic error message for inexistent files

When the APNs class is initialized with an invalid cert_file or key_file (for example, by calling apns-send):

$ ./apns-send --certificate-file /tmp/new_prod_cert/certificates.peem --push-token <token> --message "Test"

The cryptic ssl.SSLError error message is shown:

 Traceback (most recent call last):
   File "./apns-send", line 36, in <module>
     apns.gateway_server.send_notification(options.push_token, payload)
   File "/private/tmp/PyAPNsOldver/apns.py", line 536, in send_notification
     self.write(self._get_notification(token_hex, payload))
   File "/private/tmp/PyAPNsOldver/apns.py", line 270, in write
     return self._connection().write(string)
   File "/private/tmp/PyAPNsOldver/apns.py", line 252, in _connection
     self._connect()
   File "/private/tmp/PyAPNsOldver/apns.py", line 228, in _connect
     self._ssl = wrap_socket(self._socket, self.key_file, self.cert_file)
   File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 387, in wrap_socket
     ciphers=ciphers)
   File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 141, in __init__
     ciphers)
 ssl.SSLError: [Errno 336265218] _ssl.c:354: error:140B0002:SSL routines:SSL_CTX_use_PrivateKey_file:system lib

I spent a few frustrating hours trying to understand this, till I found out that I had a typo (certificates.peem instad of certificates.pem).

Suggested fix

The suggested fix attempts to open and read the cert_file and key_file, so that it fails with a matching error message.

Inexistent file

Traceback (most recent call last):
  File "./apns-send", line 32, in <module>
    apns = APNs(cert_file=options.certificate_file)
  File "/private/tmp/PyAPNsPR/apns.py", line 106, in __init__
    open(cert_file).read()
IOError: [Errno 2] No such file or directory: '/tmp/new_prod_cert/certificates.peem'

Permission error

Traceback (most recent call last):
  File "./apns-send", line 32, in <module>
    apns = APNs(cert_file=options.certificate_file)
  File "/private/tmp/PyAPNsPR/apns.py", line 106, in __init__
    open(cert_file).read()
IOError: [Errno 13] Permission denied: '/tmp/unreadable_file_owned_by_root'

Possible caveats

The only caveat I can think of is that this message will fail when providing files that can only be read once (e.g. sockets or streams). However, I think it is likely to expect filenames passed as an argument to be readable more than once.

adamatan commented 9 years ago

I see that it fails two tests because the instantiate the class with certificate.pem.