Use only one JWT token per connection (#80)

This fixes #76 where you a TooManyProviderTokenUpdates if you send
notifications to multiple topics over one connection.

As Apple states here https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns#2943374
one connection shall use only one single JWT token which should be
refreshed no more than once every 20 minutes and no less than once every
60 minutes.
This commit is contained in:
shintonik
2019-05-23 02:01:31 +03:00
committed by Sergey Petrov
parent 95c19c64d7
commit fbcf36f955
2 changed files with 5 additions and 13 deletions
+5 -6
View File
@@ -44,14 +44,11 @@ class TokenCredentials(Credentials):
self.__token_lifetime = token_lifetime self.__token_lifetime = token_lifetime
# Dictionary of {topic: (issue time, ascii decoded token)} # Dictionary of {topic: (issue time, ascii decoded token)}
self.__topicTokens = {} self.__jwt_token = None
# Use the default constructor because we don't have an SSL context # Use the default constructor because we don't have an SSL context
super(TokenCredentials, self).__init__() super(TokenCredentials, self).__init__()
def get_tokens(self):
return [val[1] for val in self.__topicTokens]
def get_authorization_header(self, topic): def get_authorization_header(self, topic):
token = self._get_or_create_topic_token(topic) token = self._get_or_create_topic_token(topic)
return 'bearer %s' % token return 'bearer %s' % token
@@ -70,7 +67,7 @@ class TokenCredentials(Credentials):
def _get_or_create_topic_token(self, topic): def _get_or_create_topic_token(self, topic):
# dict of topic to issue date and JWT token # dict of topic to issue date and JWT token
token_pair = self.__topicTokens.get(topic) token_pair = self.__jwt_token
if token_pair is None or self._is_expired_token(token_pair[0]): if token_pair is None or self._is_expired_token(token_pair[0]):
# Create a new token # Create a new token
issued_at = time.time() issued_at = time.time()
@@ -86,7 +83,9 @@ class TokenCredentials(Credentials):
algorithm=self.__encryption_algorithm, algorithm=self.__encryption_algorithm,
headers=headers).decode('ascii') headers=headers).decode('ascii')
self.__topicTokens[topic] = (issued_at, jwt_token) # Cache JWT token for later use. One JWT token per connection.
# https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns
self.__jwt_token = (issued_at, jwt_token)
return jwt_token return jwt_token
else: else:
return token_pair[1] return token_pair[1]
-7
View File
@@ -39,13 +39,6 @@ class TokenCredentialsTestCase(TestCase):
self.expiring_header = self.expiring_creds.get_authorization_header( self.expiring_header = self.expiring_creds.get_authorization_header(
self.topics[0]) self.topics[0])
def test_create_multiple_topics(self):
h1 = self.normal_creds.get_authorization_header(self.topics[0])
self.assertEqual(len(self.normal_creds.get_tokens()), 1)
h2 = self.normal_creds.get_authorization_header(self.topics[1])
self.assertNotEqual(h1, h2)
self.assertEqual(len(self.normal_creds.get_tokens()), 2)
def test_token_expiration(self): def test_token_expiration(self):
# As long as the token lifetime hasn't elapsed, this should work. To # As long as the token lifetime hasn't elapsed, this should work. To
# be really careful, we should check how much time has elapsed to # be really careful, we should check how much time has elapsed to