使用Python连接到iPhone的APNS

时间:2021-12-13 17:30:54

I'm trying to send push notifications to an iPhone using Python. I've exported my certificate and private key into a p12 file from keychain access and then converted it into pem file using the following command:

我正在尝试使用Python向iPhone发送推送通知。我已将证书和私钥从keychain访问导出到p12文件中,然后使用以下命令将其转换为pem文件:

openssl pkcs12 -in cred.p12 -out cert.pem -nodes -clcerts

I'm using APNSWrapper in Python for the connection.

我在Python中使用APNSWrapper进行连接。

I run the following code:

我运行以下代码:

deviceToken = 'Qun\xaa\xd ... c0\x9c\xf6\xca' 

# create wrapper
wrapper = APNSNotificationWrapper('/path/to/cert/cert.pem', True)

# create message
message = APNSNotification()
message.token(deviceToken)
message.badge(5)

# add message to tuple and send it to APNS server
wrapper.append(message)
wrapper.notify()

And then I get the error message:

然后我收到错误消息:

ssl.SSLError: (1, '_ssl.c:485: 
error:14094416:SSL routines:SSL3_READ_BYTES:sslv3 alert certificate unknown')

Can anyone help me out on this?

任何人都可以帮我解决这个问题吗?

5 个解决方案

#1


8  

I recently did this using Django - http://leecutsco.de/2009/07/14/push-on-the-iphone/

我最近使用Django做到了这一点 - http://leecutsco.de/2009/07/14/push-on-the-iphone/

May be useful? It's making use of no extra libraries other than those included with Python already. Wouldn't take much to extract the send_message() method out.

可能有用吗?除了Python中包含的库以外,它没有使用额外的库。提取send_message()方法并不需要太多。

#2


2  

Have you considered the Twisted package? The below code is taken from here:

你考虑过Twisted包吗?以下代码取自以下代码:

from struct import pack
from OpenSSL import SSL
from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory, Protocol
from twisted.internet.ssl import ClientContextFactory

APNS_SERVER_HOSTNAME = "<insert the push hostname from your iPhone developer portal>"
APNS_SERVER_PORT = 2195
APNS_SSL_CERTIFICATE_FILE = "<your ssl certificate.pem>"
APNS_SSL_PRIVATE_KEY_FILE = "<your ssl private key.pem>"

class APNSClientContextFactory(ClientContextFactory):
    def __init__(self):
        self.ctx = SSL.Context(SSL.SSLv3_METHOD)
        self.ctx.use_certificate_file(APNS_SSL_CERTIFICATE_FILE)
        self.ctx.use_privatekey_file(APNS_SSL_PRIVATE_KEY_FILE)

    def getContext(self):
        return self.ctx

class APNSProtocol(Protocol):
    def sendMessage(self, deviceToken, payload):
        # notification messages are binary messages in network order
        # using the following format:
        # <1 byte command> <2 bytes length><token> <2 bytes length><payload>
        fmt = "!cH32cH%dc" % len(payload)
        command = 0
        msg = struct.pack(fmt, command, deviceToken,
                          len(payload), payload)
        self.transport.write(msg)

class APNSClientFactory(ClientFactory):
    def buildProtocol(self, addr):
        print "Connected to APNS Server %s:%u" % (addr.host, addr.port)
        return APNSProtocol()

    def clientConnectionLost(self, connector, reason):
        print "Lost connection. Reason: %s" % reason

    def clientConnectionFailed(self, connector, reason):
        print "Connection failed. Reason: %s" % reason

if __name__ == '__main__':
    reactor.connectSSL(APNS_SERVER_HOSTNAME, 
                       APNS_SERVER_PORT,
                       APNSClientFactory(), 
                       APNSClientContextFactory())
    reactor.run()

#3


1  

there were a few bugs in the originally posted code, so here's a corrected version that works for me.

最初发布的代码中有一些错误,所以这是一个适合我的修正版本。

from struct import pack
from OpenSSL import SSL
from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory, Protocol
from twisted.internet.ssl import ClientContextFactory
import binascii
import struct

APNS_SERVER_HOSTNAME = "gateway.sandbox.push.apple.com"
APNS_SERVER_PORT = 2195
APNS_SSL_CERTIFICATE_FILE = "<your ssl certificate.pem>"
APNS_SSL_PRIVATE_KEY_FILE = "<your ssl private key.pem>"
DEVICE_TOKEN = "<hexlified device token>"
MESSAGE = '{"aps":{"alert":"twisted test"}}'

class APNSClientContextFactory(ClientContextFactory):
    def __init__(self):
        self.ctx = SSL.Context(SSL.SSLv3_METHOD)
        self.ctx.use_certificate_file(APNS_SSL_CERTIFICATE_FILE)
        self.ctx.use_privatekey_file(APNS_SSL_PRIVATE_KEY_FILE)

    def getContext(self):
        return self.ctx

class APNSProtocol(Protocol):

    def connectionMade(self):
        print "connection made"
        self.sendMessage(binascii.unhexlify(DEVICE_TOKEN), MESSAGE)
        self.transport.loseConnection()

    def sendMessage(self, deviceToken, payload):
        # notification messages are binary messages in network order
        # using the following format:
        # <1 byte command> <2 bytes length><token> <2 bytes length><payload>
        fmt = "!cH32sH%ds" % len(payload)
        command = '\x00'
        msg = struct.pack(fmt, command, 32, deviceToken,
                          len(payload), payload)
        print "%s: %s" %(binascii.hexlify(deviceToken), binascii.hexlify(msg))
        self.transport.write(msg)

class APNSClientFactory(ClientFactory):
    def buildProtocol(self, addr):
        print "Connected to APNS Server %s:%u" % (addr.host, addr.port)
        return APNSProtocol()

    def clientConnectionLost(self, connector, reason):
        print "Lost connection. Reason: %s" % reason

    def clientConnectionFailed(self, connector, reason):
        print "Connection failed. Reason: %s" % reason

if __name__ == '__main__':
    reactor.connectSSL(APNS_SERVER_HOSTNAME,
                       APNS_SERVER_PORT,
                       APNSClientFactory(),
                       APNSClientContextFactory())
    reactor.run()

#4


1  

Try to update to latest APNSWrapper version (0.4). There is build-in support of openssl command line tool (openssl s_client) now.

尝试更新到最新的APNSWrapper版本(0.4)。现在有openssl命令行工具(openssl s_client)的内置支持。

#5


0  

I tried both APNSWrapper and Lee Peckham's code and couldn't get it to work under Snow Leopard with Python 2.6. After a lot of trial and error it finally worked with pyOpenSSL.

我尝试了APNSWrapper和Lee Peckham的代码,并且无法使用Python 2.6在Snow Leopard下工作。经过大量的反复试验后,它终于与py​​OpenSSL一起工作了。

I already did a post with details and code snippets here so I'll just refer you there.

我已经在这里发了一篇详细信息和代码片段的帖子,所以我会在那里推荐你。

#1


8  

I recently did this using Django - http://leecutsco.de/2009/07/14/push-on-the-iphone/

我最近使用Django做到了这一点 - http://leecutsco.de/2009/07/14/push-on-the-iphone/

May be useful? It's making use of no extra libraries other than those included with Python already. Wouldn't take much to extract the send_message() method out.

可能有用吗?除了Python中包含的库以外,它没有使用额外的库。提取send_message()方法并不需要太多。

#2


2  

Have you considered the Twisted package? The below code is taken from here:

你考虑过Twisted包吗?以下代码取自以下代码:

from struct import pack
from OpenSSL import SSL
from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory, Protocol
from twisted.internet.ssl import ClientContextFactory

APNS_SERVER_HOSTNAME = "<insert the push hostname from your iPhone developer portal>"
APNS_SERVER_PORT = 2195
APNS_SSL_CERTIFICATE_FILE = "<your ssl certificate.pem>"
APNS_SSL_PRIVATE_KEY_FILE = "<your ssl private key.pem>"

class APNSClientContextFactory(ClientContextFactory):
    def __init__(self):
        self.ctx = SSL.Context(SSL.SSLv3_METHOD)
        self.ctx.use_certificate_file(APNS_SSL_CERTIFICATE_FILE)
        self.ctx.use_privatekey_file(APNS_SSL_PRIVATE_KEY_FILE)

    def getContext(self):
        return self.ctx

class APNSProtocol(Protocol):
    def sendMessage(self, deviceToken, payload):
        # notification messages are binary messages in network order
        # using the following format:
        # <1 byte command> <2 bytes length><token> <2 bytes length><payload>
        fmt = "!cH32cH%dc" % len(payload)
        command = 0
        msg = struct.pack(fmt, command, deviceToken,
                          len(payload), payload)
        self.transport.write(msg)

class APNSClientFactory(ClientFactory):
    def buildProtocol(self, addr):
        print "Connected to APNS Server %s:%u" % (addr.host, addr.port)
        return APNSProtocol()

    def clientConnectionLost(self, connector, reason):
        print "Lost connection. Reason: %s" % reason

    def clientConnectionFailed(self, connector, reason):
        print "Connection failed. Reason: %s" % reason

if __name__ == '__main__':
    reactor.connectSSL(APNS_SERVER_HOSTNAME, 
                       APNS_SERVER_PORT,
                       APNSClientFactory(), 
                       APNSClientContextFactory())
    reactor.run()

#3


1  

there were a few bugs in the originally posted code, so here's a corrected version that works for me.

最初发布的代码中有一些错误,所以这是一个适合我的修正版本。

from struct import pack
from OpenSSL import SSL
from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory, Protocol
from twisted.internet.ssl import ClientContextFactory
import binascii
import struct

APNS_SERVER_HOSTNAME = "gateway.sandbox.push.apple.com"
APNS_SERVER_PORT = 2195
APNS_SSL_CERTIFICATE_FILE = "<your ssl certificate.pem>"
APNS_SSL_PRIVATE_KEY_FILE = "<your ssl private key.pem>"
DEVICE_TOKEN = "<hexlified device token>"
MESSAGE = '{"aps":{"alert":"twisted test"}}'

class APNSClientContextFactory(ClientContextFactory):
    def __init__(self):
        self.ctx = SSL.Context(SSL.SSLv3_METHOD)
        self.ctx.use_certificate_file(APNS_SSL_CERTIFICATE_FILE)
        self.ctx.use_privatekey_file(APNS_SSL_PRIVATE_KEY_FILE)

    def getContext(self):
        return self.ctx

class APNSProtocol(Protocol):

    def connectionMade(self):
        print "connection made"
        self.sendMessage(binascii.unhexlify(DEVICE_TOKEN), MESSAGE)
        self.transport.loseConnection()

    def sendMessage(self, deviceToken, payload):
        # notification messages are binary messages in network order
        # using the following format:
        # <1 byte command> <2 bytes length><token> <2 bytes length><payload>
        fmt = "!cH32sH%ds" % len(payload)
        command = '\x00'
        msg = struct.pack(fmt, command, 32, deviceToken,
                          len(payload), payload)
        print "%s: %s" %(binascii.hexlify(deviceToken), binascii.hexlify(msg))
        self.transport.write(msg)

class APNSClientFactory(ClientFactory):
    def buildProtocol(self, addr):
        print "Connected to APNS Server %s:%u" % (addr.host, addr.port)
        return APNSProtocol()

    def clientConnectionLost(self, connector, reason):
        print "Lost connection. Reason: %s" % reason

    def clientConnectionFailed(self, connector, reason):
        print "Connection failed. Reason: %s" % reason

if __name__ == '__main__':
    reactor.connectSSL(APNS_SERVER_HOSTNAME,
                       APNS_SERVER_PORT,
                       APNSClientFactory(),
                       APNSClientContextFactory())
    reactor.run()

#4


1  

Try to update to latest APNSWrapper version (0.4). There is build-in support of openssl command line tool (openssl s_client) now.

尝试更新到最新的APNSWrapper版本(0.4)。现在有openssl命令行工具(openssl s_client)的内置支持。

#5


0  

I tried both APNSWrapper and Lee Peckham's code and couldn't get it to work under Snow Leopard with Python 2.6. After a lot of trial and error it finally worked with pyOpenSSL.

我尝试了APNSWrapper和Lee Peckham的代码,并且无法使用Python 2.6在Snow Leopard下工作。经过大量的反复试验后,它终于与py​​OpenSSL一起工作了。

I already did a post with details and code snippets here so I'll just refer you there.

我已经在这里发了一篇详细信息和代码片段的帖子,所以我会在那里推荐你。