Coder Social home page Coder Social logo

python-apns's Introduction

python-apns

A library for interacting with APNs using HTTP/2 and token based authentication.

Installation

pip install gobiko.apns

Usage

Create a client:

from gobiko.apns import APNsClient

client = APNsClient(
    team_id=TEAM_ID,
    bundle_id=BUNDLE_ID,
    auth_key_id=APNS_KEY_ID,
    auth_key_filepath=APNS_KEY_FILEPATH,
    use_sandbox=True
)

Alternatively, you can create a client with the contents of the auth key file directly:

client = APNsClient(
    team_id=TEAM_ID,
    bundle_id=BUNDLE_ID,
    auth_key_id=APNS_KEY_ID,
    auth_key=APNS_KEY,
    use_sandbox=True
)

If you run into any problems deserializing the key, try wrapping it to 64 lines:

client = APNsClient(
    team_id=TEAM_ID,
    bundle_id=BUNDLE_ID,
    auth_key_id=APNS_KEY_ID,
    auth_key=APNS_KEY,
    use_sandbox=True,
    wrap_key=True
)

In Python 2.x environments, you may need to force the communication protocol to 'h2':

client = APNsClient(
    team_id=TEAM_ID,
    bundle_id=BUNDLE_ID,
    auth_key_id=APNS_KEY_ID,
    auth_key=APNS_KEY,
    use_sandbox=True,
    force_proto='h2'
)

Now you can send a message to a device by specifying its registration ID:

client.send_message(
    registration_id,
    "All your base are belong to us."
)

Or you can send bulk messages to a list of devices:

client.send_bulk_message(
    [registration_id_1, registration_id_2],
    "You have no chance to survive, make your time."
)

Payload

Additional APNs payload values can be passed as kwargs:

client.send_message(
    registration_id,
    "All your base are belong to us.",
    badge=None,
    sound=None,
    category=None,
    content_available=False,
    action_loc_key=None,
    loc_key=None,
    loc_args=[],
    extra={},
    identifier=None,
    expiration=None,
    priority=10,
    topic=None
)

Pruning

The legacy binary interface APNs provided an endpoint to check whether a registration ID had become inactive. Now the service returns a BadDeviceToken error when you attempt to deliver an alert to an inactive registration ID. If you need to prune inactive IDs from a database you can handle the BadDeviceToken exception to do so:

from gobiko.apns.exceptions import BadDeviceToken

try:
    client.send_message(OLD_REGISTRATION_ID, "Message to an invalid registration ID.")
except BadDeviceToken:
    # Handle invalid ID here
    pass

Same approach if sending by bulk:

from gobiko.apns.exceptions import PartialBulkMessage

try:
    client.send_bulk_message([registration_id1, registration_id2], "Message")
except PartialBulkMessage as e:
    # Handle list of invalid IDs using e.bad_registration_ids
    pass

Documentation

  • More information on APNs and an explanation of the above can be found in this blog post.
  • Apple documentation for APNs can be found here.

Credits

python-apns's People

Contributors

belkka avatar d-ross avatar dependabot[bot] avatar emlync avatar forfolias avatar genesluder avatar jacse avatar jwlehman93 avatar nurockplayer avatar oaosman84 avatar sbusch-mobivention avatar sebatyler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

python-apns's Issues

APNS Payload getting to device is in different format which sent to client

Hi,

We are facing issue with payload message what server sending is not retrieving at device. Could someone please let me know where we are missing in the below payload structure.

This is the server side code sending to client :

if tuser.apns_token:
                    token = tuser.apns_token
                    message = {
                        "title": from_tuser.name,
                        "body": message,//"Fdfdsf"
                        "jid": message_from,
                        "content-available": 1,
                        "xml": xml,
                        "sound": "default",
                    }
                    logger.info('Payload: %s' % message)
                    result = client.send_message(token, message)

But receiving this payload in device :

{
"body": Fdfdsf, 
"google.c.fid": xxxxxxxx,
 "google.c.sender.id": xxxxxxxxx,
 "gcm.message_id": xxxxxxxx,
 "aps": {
    "content-available" = 1;
},
 "Nick": DeepthiJonna
}

Expecting Payload is :

{
"body": {
"title": from_tuser.name,
"body": "Fdfdsf",
"jid": message_from,
"content-available": 1,
"xml": xml
"sound": "default",
},
"google.c.fid": xxxxxxxx,
"google.c.sender.id": xxxxxxxxx,
"gcm.message_id": xxxxxxxx,
"aps": {
"content-available" = 1;
},
"Nick": DeepthiJonna
}

issue with hyper library

I have been using your lib without error for a few months until it recently stopped working. We are using Apex (for Lambda) and simply redeployed the function that included 'gobiko.apns' in our requirements.txt

The error is;

GoAway frame could not be sent: 'NoneType' object has no attribute 'sendall'

and the traceback is;

local variable 'res' referenced before assignment: UnboundLocalError
Traceback (most recent call last):
File "/var/task/main.py", line 79, in handle
send_ios_push(params, developer_id, ios_devices, bundle_id)
File "/var/task/main.py", line 149, in send_ios_push
extra=formatted_params['extra']
File "/var/task/gobiko/apns/client.py", line 78, in send_bulk_message
return res
UnboundLocalError: local variable 'res' referenced before assignment

I think it may be failing to establish an SSL connection but not sure how to fix it.

AWS Lambda runs on python 2.7.12.

Notifications not being delivered due to url-args missing

Issue: APNS request sends and returns a 200 status, but fails to deliver because "url-args" not present in the json_data sent in the request.

Resolution: Enable kwargs url-args argument that injects into json_data before request is made. Example of working request structure:

{"aps": {"alert": {"title": "My Title", "body": "This is my body text"}, "url-args": ["a", "b", "c"]}}

This assumes that the Push Notifications package website.json file has a urlFormatString with three %@ swapouts corresponding to a, b and c.

If I've just missed this then my apologies, but I can't see support for these anywhere. It makes it fail quite silently, relying on the webServiceUrl error reporting to get the feedback about the missing url-args.

Thank you!

Cannot import

I believe there is an issue with not being able to import this when pip installed, maybe because the name contains '.'

Issue when call send_message function

I there, I have got the issue below when using p8 file. I'm not sure how to fix it, hopefully we have a solution for it.

Thanks in advance

File "/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1084, in load_pem_private_key
password,
File "/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1253, in _load_key
self._handle_key_loading_error()
File "/venv/lib/python2.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1325, in _handle_key_loading_error
raise ValueError("Could not unserialize key data.")
ValueError: Could not unserialize key data.

My apns.p8 file has content as below
-----BEGIN PRIVATE KEY-----
MIGTAgeeca...................
-----END PRIVATE KEY-----

wrapping the auth_key to 64 char lines on Windows

On windows it seems you need to comment out the wrap_private_key code in client.py and it processes the .p8 fine.
If you leave the wrap code in, you get the error 'Could not deserialize key data'

Keep getting bad device Token

I keep getting BadDeviceToken, the registration_id I pass into send_message(registration_id,"My String"), where do I find the registration_id and is it the registration_id that keeps giving me a bad device token?

Even after installing gobiko.apns I have the same error

I installed gobiko.apns on my CentOS machine with:

sudo pip install gobiko.apns

but I keep receiving error:

python3 gobikoAPN.py

Traceback (most recent call last):
File "/usr/local/lib/python3.5/site-packages/jwt/algorithms.py", line 224, in prepare_key
key = load_pem_public_key(key, backend=default_backend())
File "/usr/local/lib/python3.5/site-packages/cryptography/hazmat/primitives/serialization.py", line 24, in load_pem_public_key
return backend.load_pem_public_key(data)
File "/usr/local/lib/python3.5/site-packages/cryptography/hazmat/backends/multibackend.py", line 314, in load_pem_public_key
return b.load_pem_public_key(data)
File "/usr/local/lib/python3.5/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1110, in load_pem_public_key
self._handle_key_loading_error()
File "/usr/local/lib/python3.5/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1325, in _handle_key_loading_error
raise ValueError("Could not unserialize key data.")
ValueError: Could not unserialize key data.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "gobikoAPN.py", line 28, in
'kid': APNS_KEY_ID,
File "/usr/local/lib/python3.5/site-packages/jwt/api_jwt.py", line 56, in encode
json_payload, key, algorithm, headers, json_encoder
File "/usr/local/lib/python3.5/site-packages/jwt/api_jws.py", line 98, in encode
key = alg_obj.prepare_key(key)
File "/usr/local/lib/python3.5/site-packages/jwt/algorithms.py", line 226, in prepare_key
key = load_pem_private_key(key, password=None, backend=default_backend())
File "/usr/local/lib/python3.5/site-packages/cryptography/hazmat/primitives/serialization.py", line 20, in load_pem_private_key
return backend.load_pem_private_key(data, password)
File "/usr/local/lib/python3.5/site-packages/cryptography/hazmat/backends/multibackend.py", line 305, in load_pem_private_key
return b.load_pem_private_key(data, password)
File "/usr/local/lib/python3.5/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1084, in load_pem_private_key
password,
File "/usr/local/lib/python3.5/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1253, in _load_key
self._handle_key_loading_error()
File "/usr/local/lib/python3.5/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1325, in _handle_key_loading_error
raise ValueError("Could not unserialize key data.")
ValueError: Could not unserialize key data.

what else should I do to have it working?

Voip push?

Hi,

Is there any way to use this library for voip push?

Could not deserialize key data

I have the same issue as #10 but on Ubuntu 16.04.
Commenting out auth_key = wrap_private_key(auth_key) # Some have had issues with keys that aren't wrappd to 64 lines solves it.

PyJWT 2 breaks _create_token function

PyJWT has released version 2.0.0 (and newer versions), removing python2 and python < 3.6 compatibily.
This means the jwt.encode() function now returns a string. string type in python3 has no .decode() method.

This can be fixed 2 ways:

  • add <2 to the pyjwt in setup.py install_requires
  • fix the code to not run .decode() on the created jwt

Returning response in the method, APNsClient._send_push_request() instead of True

Hi,

I wonder there is any reason why it returns True instead of response in the method, _send_push_request() in the class, APNsClient.

def _send_push_request(self, connection, registration_id, json_data, request_headers):
    connection.request(
        'POST', 
        '/3/device/{0}'.format(registration_id), 
        json_data, 
        headers=request_headers
    )
    response = connection.get_response()

    if response.status != APNSResponse.Success:
        identifier = response.headers['apns-id']
        body = json.loads(response.read().decode('utf-8'))
        reason = body["reason"] if "reason" in body else None

        if reason:
            exceptions_module = importlib.import_module("gobiko.apns.exceptions")
            ExceptionClass = None
            try:
                ExceptionClass = getattr(exceptions_module, reason)
            except AttributeError:
                ExceptionClass = InternalException
            raise ExceptionClass()

    return True

And, how about changing it into returning response?

Thanks.

gobiko.apns.exceptions.TopicDisallowed

I tried launching the tool and i got an exception gobiko.apns.exceptions.TopicDisallowed. Did I missed something ?

  File "client.py", line 13, in <module>
    client.send_message("7f8d621ccc541666XXXXX", "this is my message")
  File "/Users/gros/Downloads/python-apns-master/gobiko/apns/client.py", line 66, in send_message
    return self._send_message(registration_id, alert, **kwargs)
  File "/Users/gros/Downloads/python-apns-master/gobiko/apns/client.py", line 168, in _send_message
    response = self._send_push_request(connection, registration_id, json_data, request_headers)
  File "/Users/gros/Downloads/python-apns-master/gobiko/apns/client.py", line 193, in _send_push_request
    raise ExceptionClass()
gobiko.apns.exceptions.TopicDisallowed

Configuration is:


client = APNsClient(
   team_id="GTWXXXXXXX",
   bundle_id="com.xxx.xxx.xxx",
   auth_key_id="J85XXXXXX",
   auth_key_filepath="/Users/xxx/ophtaplus.p8",
   use_sandbox=False,
   force_proto='h2'
)


client.send_message("7f8d621ccc5XXXXXXXXX", "this is my message")

Python 2.7.13

Version bump and submit 0.1.4 to PyPi

It looks like master has been modified since the 0.1.3 release, any chance we can get the version bumped and a new release submitted to PyPi with the new updates?

send_bulk_message needs more refined error handling

Right now send_bulk_message can emit BadDeviceToken and a PartialBulkMessage exceptions. When filling the good_registration_ids and bad_registration_ids the exception is pac-man style (catch all) and doesn't really distinguish between various types of errors. Only those 403 TokenError and 410 TokenInactive should be considered as id problems. Otherwise the user's APNs server will inactivate such device tokens which are still valid!

Inconsistent cryptography version in dependencies

The version for the cryptography dependency was pinned in 81fe921 to force a version that does not depend on rust during build-time.
But, in the version number in requirements.txt is not the same as the one in setup.py

Which one should it be?

Note: This is a build-time only dependency, and on most platforms users should use the whl packages provided by cryptography. So, dropping the version number is, in my humble opinion, the way froward

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.