Skip to content

Commit

Permalink
Handle exception on history unencrypted message (#175)
Browse files Browse the repository at this point in the history
* Handle exception on history unencrypted message

* PubNub SDK v7.3.2 release.

---------

Co-authored-by: PubNub Release Bot <120067856+pubnub-release-bot@users.noreply.github.com>
  • Loading branch information
seba-aln and pubnub-release-bot authored Nov 27, 2023
1 parent 5164d88 commit 57360f2
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 16 deletions.
13 changes: 9 additions & 4 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: python
version: 7.3.1
version: 7.3.2
schema: 1
scm: github.com/pubnub/python
sdks:
Expand All @@ -18,7 +18,7 @@ sdks:
distributions:
- distribution-type: library
distribution-repository: package
package-name: pubnub-7.3.1
package-name: pubnub-7.3.2
location: https://pypi.org/project/pubnub/
supported-platforms:
supported-operating-systems:
Expand Down Expand Up @@ -97,8 +97,8 @@ sdks:
-
distribution-type: library
distribution-repository: git release
package-name: pubnub-7.3.1
location: https://github.com/pubnub/python/releases/download/v7.3.1/pubnub-7.3.1.tar.gz
package-name: pubnub-7.3.2
location: https://github.com/pubnub/python/releases/download/v7.3.2/pubnub-7.3.2.tar.gz
supported-platforms:
supported-operating-systems:
Linux:
Expand Down Expand Up @@ -169,6 +169,11 @@ sdks:
license-url: https://github.com/aio-libs/aiohttp/blob/master/LICENSE.txt
is-required: Required
changelog:
- date: 2023-11-27
version: v7.3.2
changes:
- type: bug
text: "Gracefully handle decrypting an unencrypted method. If a decryption error occurs when trying to decrypt plain text, the plain text message will be returned and an error field will be set in the response. This works for both history and subscription messages."
- date: 2023-10-30
version: v7.3.1
changes:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v7.3.2
November 27 2023

#### Fixed
- Gracefully handle decrypting an unencrypted method. If a decryption error occurs when trying to decrypt plain text, the plain text message will be returned and an error field will be set in the response. This works for both history and subscription messages.

## v7.3.1
October 30 2023

Expand Down
9 changes: 8 additions & 1 deletion pubnub/models/consumer/history.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import binascii


class PNHistoryResult(object):
def __init__(self, messages, start_timetoken, end_timetoken):
self.messages = messages
Expand Down Expand Up @@ -44,12 +47,16 @@ def __init__(self, entry, crypto, timetoken=None, meta=None):
self.meta = meta
self.entry = entry
self.crypto = crypto
self.error = None

def __str__(self):
return "History item with tt: %s and content: %s" % (self.timetoken, self.entry)

def decrypt(self, cipher_key):
self.entry = self.crypto.decrypt(cipher_key, self.entry)
try:
self.entry = self.crypto.decrypt(cipher_key, self.entry)
except binascii.Error as e:
self.error = e


class PNFetchMessagesResult(object):
Expand Down
3 changes: 2 additions & 1 deletion pubnub/models/consumer/pubsub.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


class PNMessageResult(object):
def __init__(self, message, subscription, channel, timetoken, user_metadata=None, publisher=None):
def __init__(self, message, subscription, channel, timetoken, user_metadata=None, publisher=None, error=None):

if subscription is not None:
assert isinstance(subscription, str)
Expand All @@ -29,6 +29,7 @@ def __init__(self, message, subscription, channel, timetoken, user_metadata=None
self.timetoken = timetoken
self.user_metadata = user_metadata
self.publisher = publisher
self.error = error


class PNSignalMessageResult(PNMessageResult):
Expand Down
2 changes: 1 addition & 1 deletion pubnub/pubnub_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@

class PubNubCore:
"""A base class for PubNub Python API implementations"""
SDK_VERSION = "7.3.1"
SDK_VERSION = "7.3.2"
SDK_NAME = "PubNub-Python"

TIMESTAMP_DIVIDER = 1000
Expand Down
14 changes: 8 additions & 6 deletions pubnub/workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,23 @@ def _get_url_for_file_event_message(self, channel, extracted_message):

def _process_message(self, message_input):
if self._pubnub.config.cipher_key is None:
return message_input
return message_input, None
else:
try:
return self._pubnub.config.crypto.decrypt(
self._pubnub.config.cipher_key,
message_input
)
), None
except Exception as exception:
logger.warning("could not decrypt message: \"%s\", due to error %s" % (message_input, str(exception)))

pn_status = PNStatus()
pn_status.category = PNStatusCategory.PNDecryptionErrorCategory
pn_status.error_data = PNErrorData(str(exception), exception)
pn_status.error = True
pn_status.operation = PNOperationType.PNSubscribeOperation
self._listener_manager.announce_status(pn_status)
return message_input
return message_input, exception

def _process_incoming_payload(self, message):
assert isinstance(message, SubscribeMessage)
Expand Down Expand Up @@ -125,7 +126,7 @@ def _process_incoming_payload(self, message):
)
self._listener_manager.announce_membership(membership_result)
elif message.type == SubscribeMessageWorker.TYPE_FILE_MESSAGE:
extracted_message = self._process_message(message.payload)
extracted_message, _ = self._process_message(message.payload)
download_url = self._get_url_for_file_event_message(channel, extracted_message)

pn_file_result = PNFileMessageResult(
Expand All @@ -142,7 +143,7 @@ def _process_incoming_payload(self, message):
self._listener_manager.announce_file_message(pn_file_result)

else:
extracted_message = self._process_message(message.payload)
extracted_message, error = self._process_message(message.payload)
publisher = message.issuing_client_id

if extracted_message is None:
Expand Down Expand Up @@ -172,6 +173,7 @@ def _process_incoming_payload(self, message):
channel=channel,
subscription=subscription_match,
timetoken=publish_meta_data.publish_timetoken,
publisher=publisher
publisher=publisher,
error=error
)
self._listener_manager.announce_message(pn_message_result)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name='pubnub',
version='7.3.1',
version='7.3.2',
description='PubNub Real-time push service in the cloud',
author='PubNub',
author_email='support@pubnub.com',
Expand Down
185 changes: 185 additions & 0 deletions tests/integrational/fixtures/native_sync/history/unencrypted.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
{
"version": 1,
"interactions": [
{
"request": {
"method": "DELETE",
"uri": "https://ps.pndsn.com/v3/history/sub-key/{PN_KEY_SUBSCRIBE}/channel/test_unencrypted",
"body": null,
"headers": {
"User-Agent": [
"PubNub-Python/7.3.0"
],
"Accept-Encoding": [
"gzip, deflate"
],
"Accept": [
"*/*"
],
"Connection": [
"keep-alive"
],
"Content-Length": [
"0"
]
}
},
"response": {
"status": {
"code": 200,
"message": "OK"
},
"headers": {
"Age": [
"0"
],
"Connection": [
"keep-alive"
],
"Content-Type": [
"text/javascript; charset=\"UTF-8\""
],
"Content-Length": [
"52"
],
"Cache-Control": [
"no-cache"
],
"Server": [
"Pubnub Storage"
],
"Date": [
"Wed, 22 Nov 2023 15:33:23 GMT"
],
"Access-Control-Allow-Origin": [
"*"
],
"Access-Control-Allow-Methods": [
"GET, POST, DELETE, OPTIONS"
],
"Accept-Ranges": [
"bytes"
]
},
"body": {
"string": "{\"status\": 200, \"error\": false, \"error_message\": \"\"}"
}
}
},
{
"request": {
"method": "GET",
"uri": "https://ps.pndsn.com/publish/{PN_KEY_PUBLISH}/{PN_KEY_SUBSCRIBE}/0/test_unencrypted/0/%22Lorem%20Ipsum%22?seqn=1",
"body": null,
"headers": {
"User-Agent": [
"PubNub-Python/7.3.0"
],
"Accept-Encoding": [
"gzip, deflate"
],
"Accept": [
"*/*"
],
"Connection": [
"keep-alive"
]
}
},
"response": {
"status": {
"code": 200,
"message": "OK"
},
"headers": {
"Connection": [
"keep-alive"
],
"Content-Type": [
"text/javascript; charset=\"UTF-8\""
],
"Content-Length": [
"30"
],
"Cache-Control": [
"no-cache"
],
"Date": [
"Wed, 22 Nov 2023 15:33:23 GMT"
],
"Access-Control-Allow-Origin": [
"*"
],
"Access-Control-Allow-Methods": [
"GET"
]
},
"body": {
"string": "[1,\"Sent\",\"17006672033304156\"]"
}
}
},
{
"request": {
"method": "GET",
"uri": "https://ps.pndsn.com/v2/history/sub-key/{PN_KEY_SUBSCRIBE}/channel/test_unencrypted?count=100",
"body": null,
"headers": {
"User-Agent": [
"PubNub-Python/7.3.0"
],
"Accept-Encoding": [
"gzip, deflate"
],
"Accept": [
"*/*"
],
"Connection": [
"keep-alive"
]
}
},
"response": {
"status": {
"code": 200,
"message": "OK"
},
"headers": {
"Age": [
"0"
],
"Connection": [
"keep-alive"
],
"Content-Type": [
"text/javascript; charset=\"UTF-8\""
],
"Content-Length": [
"53"
],
"Cache-Control": [
"no-cache"
],
"Server": [
"Pubnub Storage"
],
"Date": [
"Wed, 22 Nov 2023 15:33:25 GMT"
],
"Access-Control-Allow-Origin": [
"*"
],
"Access-Control-Allow-Methods": [
"GET, POST, DELETE, OPTIONS"
],
"Accept-Ranges": [
"bytes"
]
},
"body": {
"string": "[[\"Lorem Ipsum\"],17006672033304156,17006672033304156]"
}
}
}
]
}
30 changes: 29 additions & 1 deletion tests/integrational/native_sync/test_history.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import binascii
import logging
import time
import unittest
Expand All @@ -9,7 +10,7 @@
from pubnub.models.consumer.history import PNHistoryResult
from pubnub.models.consumer.pubsub import PNPublishResult
from pubnub.pubnub import PubNub
from tests.helper import pnconf_copy, pnconf_enc_copy, pnconf_pam_copy
from tests.helper import pnconf_copy, pnconf_enc_copy, pnconf_enc_env_copy, pnconf_env_copy, pnconf_pam_copy
from tests.integrational.vcr_helper import use_cassette_and_stub_time_sleep_native

pubnub.set_stream_logger('pubnub', logging.DEBUG)
Expand Down Expand Up @@ -104,3 +105,30 @@ def test_super_call_with_all_params(self):
assert isinstance(envelope.result, PNHistoryResult)

assert not envelope.status.is_error()


class TestHistoryCrypto(unittest.TestCase):
@use_cassette_and_stub_time_sleep_native('tests/integrational/fixtures/native_sync/history/unencrypted.json',
serializer='pn_json', filter_query_parameters=['uuid', 'pnsdk'])
def test_unencrypted(self):
ch = "test_unencrypted"
pubnub = PubNub(pnconf_env_copy())
pubnub.config.uuid = "history-native-sync-uuid"
pubnub.delete_messages().channel(ch).sync()
envelope = pubnub.publish().channel(ch).message("Lorem Ipsum").sync()
assert isinstance(envelope.result, PNPublishResult)
assert envelope.result.timetoken > 0

time.sleep(2)

pubnub_enc = PubNub(pnconf_enc_env_copy())
pubnub_enc.config.uuid = "history-native-sync-uuid"
envelope = pubnub_enc.history().channel(ch).sync()

assert isinstance(envelope.result, PNHistoryResult)
assert envelope.result.start_timetoken > 0
assert envelope.result.end_timetoken > 0
assert len(envelope.result.messages) == 1

assert envelope.result.messages[0].entry == 'Lorem Ipsum'
assert isinstance(envelope.result.messages[0].error, binascii.Error)
Loading

0 comments on commit 57360f2

Please sign in to comment.