Search code examples
iosdjangopython-3.xapple-push-notificationsdjango-push-notifications

APNS_CERTIFICATE - Push Notification does not send in production


I've had this issue for about 2 weeks, when I suddenly stopped sending notifications in production. I am using the django-push-notifications library and by django admin I can send a test message, but it does not send messages through the system.

On my local computer, everything works flawlessly. I discovered a command to test the certificate:

openssl s_client -connect gateway.push.apple.com:2195 -cert apns-cert.pem

With this one I had the return: Timeout: 7200 (sec) Verify return code: 20 (unable to get local issuer certificate) Extended master secret: yes

So with a lot of research, I discovered that I needed to put the path of "CA":

openssl s_client -CApath /etc/ssl/certs/ -connect gateway.push.apple.com:2195 -cert apns-cert.pem

Who was taking me to: Verify return code: 0 (ok)

However, for use in the library, I needed to put the full path of a .pem file. Then I found this command:

ls /etc/ssl/certs/Entrust*

I tested all the .pem files that were there, until I reached what appeared to have worked perfectly:

openssl s_client -CAfile /etc/ssl/certs/Entrust.net_Premium_2048_Secure_Server_CA.pem -connect gateway.push.apple.com:2195 -cert apns-cert.pem

Soon, I formatted my PUSH_NOTIFICATIONS_SETTINGS:

PUSH_NOTIFICATIONS_SETTINGS = {
     "GCM_API_KEY": "xxxx",
    "APNS_CERTIFICATE": os.path.join(BASE_DIR, "apns-cert.pem"),
    "APNS_CA_CERTIFICATES": "/etc/ssl/certs/Entrust.net_Premium_2048_Secure_Server_CA.pem",
    "APNS_ERROR_TIMEOUT": 3,
}


IOS_VERIFY_RECEIPT_API = 'https://buy.itunes.apple.com/verifyReceipt'
ANDROID_VERIFY_RECEIPT_API = 'https://www.googleapis.com/androidpublisher/v2/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}' 

Unfortunately it still does not send PUSH, and no error because I have configured it to pop errors to send by email.

PS: Remembering that by sending a test text via django admin: OK. Sending via sandbox (debug): OK.


Solution

  • In fact it was not an SSL issue, it was a bulk upload error by the library.

    The tokens registered in the system were expired and the library does not know how to work with it and canceled the action, causing no other token to be attempted. I corrected the problem by looping and ignoring the individual error by sending a test to my email:

     def send_push(self):
        errors = []
    
        # IOS
        queryset_ios = APNSDevice.objects.filter(user=self.authentication)
        for device in queryset_ios:
            try:
                device.send_message(self.subject, badge=1, sound=self.kind.sound)
            except APNSServerError as e:
                errors.append(APNS_ERROR_MESSAGES[e.status])
            except Exception:
                pass
    
        # ANDROID
        queryset_android = GCMDevice.objects.filter(user=self.authentication)
        extra = {'notification': self.pk, 'kind': self.kind.kind, 'sound': self.kind.sound}
    
        for device in queryset_android:
            try:
                queryset_android.send_message(self.subject, badge=1, extra=extra)
            except GCMError as e:
                errors.append(str(e))
            except Exception:
                pass
    
        if errors:
            send_mail("Push Error",
                      "Push: %s \n User: %s \n\n Errors: %s" % (self.subject, self.authentication.full_name, errors),
                      settings.DEFAULT_FROM_EMAIL, ["[email protected]"])