Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle exception on history unencrypted message #175

Merged
merged 3 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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='[email protected]',
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
Loading