From 97832d6a0d1c574666a4f110f54e0782220a0d8f Mon Sep 17 00:00:00 2001 From: Brandon Joyce Date: Wed, 22 Nov 2023 23:47:43 -0500 Subject: [PATCH 1/3] Add message_id parameter --- AUTHORS.md | 9 +++++---- pyas2lib/as2.py | 16 ++++++++++++---- pyas2lib/tests/test_basic.py | 8 ++++++++ 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/AUTHORS.md b/AUTHORS.md index 3c75246..f8b47d9 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -1,4 +1,5 @@ -* Abhishek Ram @abhishek-ram -* Chad Gates @chadgates -* Bruno Ribeiro da Silva @loop0 -* Robin C Samuel @robincsamuel \ No newline at end of file +- Abhishek Ram @abhishek-ram +- Chad Gates @chadgates +- Bruno Ribeiro da Silva @loop0 +- Robin C Samuel @robincsamuel +- Brandon Joyce @brandonjoyce diff --git a/pyas2lib/as2.py b/pyas2lib/as2.py index cb058ad..dec3144 100644 --- a/pyas2lib/as2.py +++ b/pyas2lib/as2.py @@ -330,6 +330,7 @@ def build( content_type="application/edi-consent", additional_headers=None, disposition_notification_to="no-reply@pyas2.com", + message_id=None, ): """Function builds the AS2 message. Compresses, signs and encrypts @@ -354,6 +355,10 @@ def build( :param disposition_notification_to: Email address for disposition-notification-to header entry. (default "no-reply@pyas2.com") + + :param message_id: + The message id to be used for the message. If not provided a + unique message id is generated. (default None) """ # Validations @@ -372,10 +377,13 @@ def build( "Encryption of messages is enabled but encrypt key is not set for the receiver." ) - # Generate message id using UUID 1 as it uses both hostname and time - self.message_id = ( - email_utils.make_msgid(domain=self.sender.domain).lstrip("<").rstrip(">") - ) + if message_id: + self.message_id = message_id + else: + # Generate message id using UUID 1 as it uses both hostname and time + self.message_id = ( + email_utils.make_msgid(domain=self.sender.domain).lstrip("<").rstrip(">") + ) # Set up the message headers as2_headers = { diff --git a/pyas2lib/tests/test_basic.py b/pyas2lib/tests/test_basic.py index 3eadbb8..3a90e98 100644 --- a/pyas2lib/tests/test_basic.py +++ b/pyas2lib/tests/test_basic.py @@ -200,6 +200,14 @@ def test_plain_message_without_domain(self): out_message.build(self.test_data) self.assertEqual(out_message.message_id.split("@")[1], socket.getfqdn()) + def test_plain_message_with_custom_message_id(self): + """Test Message building with a custom message id""" + + # Build an As2 message to be transmitted to partner + out_message = as2.Message(self.org, self.partner) + out_message.build(self.test_data, message_id="some_custom_id") + self.assertEqual(out_message.message_id, "some_custom_id") + def find_org(self, as2_id): return self.org From ef49efe7029011ed8475af6a563dae4bfcbdf830 Mon Sep 17 00:00:00 2001 From: Brandon Joyce Date: Fri, 24 Nov 2023 01:43:36 -0500 Subject: [PATCH 2/3] Validate length of message id when user provided --- pyas2lib/as2.py | 14 ++++++++++---- pyas2lib/tests/test_basic.py | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/pyas2lib/as2.py b/pyas2lib/as2.py index dec3144..d81fa1d 100644 --- a/pyas2lib/as2.py +++ b/pyas2lib/as2.py @@ -357,8 +357,8 @@ def build( (default "no-reply@pyas2.com") :param message_id: - The message id to be used for the message. If not provided a - unique message id is generated. (default None) + A value to be used for the left side of the message id. If not provided a + unique id is generated. (default None) """ # Validations @@ -378,13 +378,19 @@ def build( ) if message_id: - self.message_id = message_id + self.message_id = f"{message_id}@{self.sender.domain}" else: - # Generate message id using UUID 1 as it uses both hostname and time self.message_id = ( email_utils.make_msgid(domain=self.sender.domain).lstrip("<").rstrip(">") ) + # ensure the total length of the message id is no more than 255 characters + if len(self.message_id) > 255: + raise ValueError( + f"Message ID must be no more than 255 characters for compatibility with some AS2 servers. " + f"Current message ID length is {len(self.message_id)}." + ) + # Set up the message headers as2_headers = { "AS2-Version": AS2_VERSION, diff --git a/pyas2lib/tests/test_basic.py b/pyas2lib/tests/test_basic.py index 3a90e98..aac10fc 100644 --- a/pyas2lib/tests/test_basic.py +++ b/pyas2lib/tests/test_basic.py @@ -1,4 +1,5 @@ """Module for testing the basic features of pyas2.""" +import pytest import socket from pyas2lib import as2 from . import Pyas2TestCase @@ -204,9 +205,21 @@ def test_plain_message_with_custom_message_id(self): """Test Message building with a custom message id""" # Build an As2 message to be transmitted to partner + self.org.domain = "example.com" out_message = as2.Message(self.org, self.partner) out_message.build(self.test_data, message_id="some_custom_id") - self.assertEqual(out_message.message_id, "some_custom_id") + self.assertEqual(out_message.message_id, "some_custom_id@example.com") + + def test_invalid_message_id_length_raises_error(self): + """Test Message building with a custom message id that's invalid""" + + # Build an As2 message to be transmitted to partner + self.org.domain = "example.com" + out_message = as2.Message(self.org, self.partner) + very_long_message_id = "a" * 1000 + with pytest.raises(ValueError) as excinfo: + out_message.build(self.test_data, message_id=very_long_message_id) + assert "Message ID must be no more than 255 characters for compatibility" in str(excinfo.value) def find_org(self, as2_id): return self.org From 9cf7bd451d011b42a2c2bc692047fd8569510f1c Mon Sep 17 00:00:00 2001 From: Brandon Joyce Date: Mon, 27 Nov 2023 16:42:05 -0500 Subject: [PATCH 3/3] Formatting --- pyas2lib/as2.py | 7 +++++-- pyas2lib/tests/test_basic.py | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pyas2lib/as2.py b/pyas2lib/as2.py index d81fa1d..12ebac7 100644 --- a/pyas2lib/as2.py +++ b/pyas2lib/as2.py @@ -381,13 +381,16 @@ def build( self.message_id = f"{message_id}@{self.sender.domain}" else: self.message_id = ( - email_utils.make_msgid(domain=self.sender.domain).lstrip("<").rstrip(">") + email_utils.make_msgid(domain=self.sender.domain) + .lstrip("<") + .rstrip(">") ) # ensure the total length of the message id is no more than 255 characters if len(self.message_id) > 255: raise ValueError( - f"Message ID must be no more than 255 characters for compatibility with some AS2 servers. " + "Message ID must be no more than 255 characters for " + "compatibility with some AS2 servers. " f"Current message ID length is {len(self.message_id)}." ) diff --git a/pyas2lib/tests/test_basic.py b/pyas2lib/tests/test_basic.py index aac10fc..fed94b9 100644 --- a/pyas2lib/tests/test_basic.py +++ b/pyas2lib/tests/test_basic.py @@ -219,7 +219,10 @@ def test_invalid_message_id_length_raises_error(self): very_long_message_id = "a" * 1000 with pytest.raises(ValueError) as excinfo: out_message.build(self.test_data, message_id=very_long_message_id) - assert "Message ID must be no more than 255 characters for compatibility" in str(excinfo.value) + assert ( + "Message ID must be no more than 255 characters for compatibility" + in str(excinfo.value) + ) def find_org(self, as2_id): return self.org