Skip to content

Instantly share code, notes, and snippets.

@dkong dkong/Help.md Secret forked from aaronlevy/push_debug.py
Last active May 5, 2019

Embed
What would you like to do?
APNS push debug script

Usage

usage: push_debug.py [-h] [-s] certificate device_id

Send test APNS notifications to device using cert

positional arguments:
  certificate    Push certificate
  device_id      Device ID

optional arguments:
  -h, --help     show this help message and exit
  -s, --sandbox  Use APNS sandbox environment

The push certificate file is the same file that would be uploaded to PubNub. Read the iOS docs for more instructions.

Examples

Send notification through production environment

python push_debug.py my_certificate.pem c35124fd2676d646423705b0721004e3b8426d163e10dbf76b46347a4477f12b

Send notification through sandbox environment

python push_debug.py -s my_certificate.pem 3f3980225497e1846fb5c2db9e0b3510023402c7a772011106c702d2aec20cc5
import json
import logging
import os
import socket
import ssl
import struct
import sys
import time
import uuid
import argparse
APNS_HOST = 'gateway.push.apple.com'
APNS_HOST_SANDBOX = 'gateway.sandbox.push.apple.com'
APNS_PORT = 2195
APNS_ERRORS = {
1:'Processing error',
2:'Missing device token',
3:'missing topic',
4:'missing payload',
5:'invalid token size',
6:'invalid topic size',
7:'invalid payload size',
8:'invalid token',
255:'Unknown'
}
def push(cert_path, device, sandbox):
if not os.path.exists(cert_path):
logging.error("Invalid certificate path: %s" % cert_path)
sys.exit(1)
device = device.decode('hex')
expiry = time.time() + 3600
try:
sock = ssl.wrap_socket(
socket.socket(socket.AF_INET, socket.SOCK_STREAM),
certfile=cert_path
)
host = APNS_HOST_SANDBOX if sandbox else APNS_HOST
sock.connect((host, APNS_PORT))
sock.settimeout(1)
except Exception as e:
logging.error("Failed to connect: %s" % e)
sys.exit(1)
logging.info("Connected to APNS\n")
for ident in range(1,4):
logging.info("Sending %d of 3 push notifications" % ident)
payload = json.dumps({
'aps': {
'alert': 'Push Test %d: %s' % (ident, str(uuid.uuid4())[:8])
}
})
items = [1, ident, expiry, 32, device, len(payload), payload]
try:
sent = sock.write(struct.pack('!BIIH32sH%ds'%len(payload), *items))
if sent:
logging.info("Message sent\n")
else:
logging.error("Unable to send message\n")
except socket.error as e:
logging.error("Socket write error: %s", e)
# If there was an error sending, we will get a response on socket
try:
response = sock.read(6)
command, status, failed_ident = struct.unpack('!BBI',response[:6])
logging.info("APNS Error: %s\n", APNS_ERRORS.get(status))
sys.exit(1)
except socket.timeout:
pass
except ssl.SSLError:
pass
sock.close()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Send test APNS notifications to device using cert")
parser.add_argument("certificate", help="Push certificate")
parser.add_argument("device_id", help="Device ID")
parser.add_argument("-s", "--sandbox", action="store_true", help="Use APNS sandbox environment")
args = parser.parse_args()
logging.basicConfig(level=logging.INFO)
push(args.certificate, args.device_id, args.sandbox)
logging.info("Complete\n")
@shahankit

This comment has been minimized.

Copy link

commented Feb 7, 2016

gives me error

command, status, failed_ident = struct.unpack('=BBI',response[:6])
struct.error: unpack requires a string argument of length 6
@elcolie

This comment has been minimized.

Copy link

commented May 5, 2019

Please revise to Python3

Traceback (most recent call last):
  File "push_debug.py", line 117, in <module>
    push(args.certificate, args.device_id, args.sandbox)
  File "push_debug.py", line 58, in push
    device = device.decode('hex')
AttributeError: 'str' object has no attribute 'decode'
@elcolie

This comment has been minimized.

Copy link

commented May 5, 2019

Python3 user needs to modify code as follows

import codecs
decode_hex = codecs.getdecoder('hex_codec')
device = decode_hex(device)[0]

items

items = [1, ident, expiry, 32, device, len(payload), payload.encode('utf-8')]

And last one struck.pack change from int to float

'!BIfH32sH%ds'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.