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

NIAD-3252: External attachment filename containing equals sign throws exception #198

Merged
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- Fix issue where an error occurred if the attachment filenames contained and equal sign.

## [1.3.2] - 2024-09-09

### Fixed
Expand Down
14 changes: 10 additions & 4 deletions mhs/common/mhs_common/messages/ebxml_envelope.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,15 +227,21 @@ def parse_external_attachments(xml_tree: Element) -> Dict[str, str]:
variables = descriptionParams = re.findall("(?:\".*?\"|\S)+", description.strip())

filename = None
description_variables = dict(pair.split("=") for pair in variables)

description_variables = {}
for pair in variables:
if "=" in pair:
key, value = pair.split("=", 1)
description_variables[key] = value

if "Filename" in description_variables:
filename = description_variables["Filename"].replace('\\', '')

mid = mid_attribute.split(":")[1]
external_attachment = {
external_attachment = {
EXTERNAL_ATTACHMENT_DOCUMENT_ID :document_id_attribute,
EXTERNAL_ATTACHMENT_MESSAGE_ID :mid_attribute.split(":")[1],
EXTERNAL_ATTACHMENT_DESCRIPTION: description,
EXTERNAL_ATTACHMENT_DESCRIPTION: description,
EXTERNAL_ATTACHMENT_TITLE: filename
}

Expand Down
146 changes: 146 additions & 0 deletions mhs/common/mhs_common/messages/tests/test_ebxml_envelope.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
ebxml_envelope.RECEIVED_MESSAGE_ID: "F106022D-758B-49A9-A80A-8FF211C32A43"
}


class BaseTestEbxmlEnvelope(TestCase):
current_dir = os.path.dirname(os.path.abspath(__file__))
message_dir = Path(current_dir) / MESSAGE_DIR
Expand All @@ -44,3 +45,148 @@ def test_cant_find_optional_text_value_during_parsing(self):
)

self.assertEqual({}, values_dict)

def test_filename_contains_equals_sign(self):
expected_external_attachment = {
'document_id': '_735BB673-D9C0-4B85-951E-98DD045C4713',
'message_id': 'E54DEC57-6BA5-40AB-ACD0-1E383209C034',
'description': 'Filename="735BB673-D9C0-4B85-951E-98DD045C4713_adrian=marbles2.BMP" '
'ContentType=application/octet-stream Compressed=Yes LargeAttachment=No '
'OriginalBase64=No Length=3345444',
'title': '"735BB673-D9C0-4B85-951E-98DD045C4713_adrian=marbles2.BMP"'
}

description = ('Filename="735BB673-D9C0-4B85-951E-98DD045C4713_adrian=marbles2.BMP" '
'ContentType=application/octet-stream Compressed=Yes LargeAttachment=No OriginalBase64=No '
'Length=3345444')

xml_tree = self.generate_soap_envelope_from_description(description)

external_attachments = ebxml_envelope.EbxmlEnvelope.parse_external_attachments(xml_tree)['external_attachments']

self.assertEqual(external_attachments[0], expected_external_attachment)

def test_description_does_not_contain_filename(self):
expected_external_attachment = {
'document_id': '_735BB673-D9C0-4B85-951E-98DD045C4713',
'message_id': 'E54DEC57-6BA5-40AB-ACD0-1E383209C034',
'description': 'ContentType=application/octet-stream Compressed=Yes LargeAttachment=No '
'OriginalBase64=No Length=3345444',
'title': None
}

description = (
'ContentType=application/octet-stream Compressed=Yes LargeAttachment=No OriginalBase64=No '
'Length=3345444'
)

xml_tree = self.generate_soap_envelope_from_description(description)
external_attachments = ebxml_envelope.EbxmlEnvelope.parse_external_attachments(xml_tree)['external_attachments']

self.assertEqual(external_attachments[0], expected_external_attachment)

def test_description_contains_filename_in_uppercase(self):
expected_external_attachment = {
'document_id': '_735BB673-D9C0-4B85-951E-98DD045C4713',
'message_id': 'E54DEC57-6BA5-40AB-ACD0-1E383209C034',
'description': 'FILENAME="735BB673-D9C0-4B85-951E-98DD045C4713_adrian=marbles2.BMP" '
'ContentType=application/octet-stream Compressed=Yes LargeAttachment=No '
'OriginalBase64=No Length=3345444',
'title': None
}

description = (
'FILENAME="735BB673-D9C0-4B85-951E-98DD045C4713_adrian=marbles2.BMP" '
'ContentType=application/octet-stream Compressed=Yes LargeAttachment=No OriginalBase64=No '
'Length=3345444'
)

xml_tree = self.generate_soap_envelope_from_description(description)

external_attachments = ebxml_envelope.EbxmlEnvelope.parse_external_attachments(xml_tree)['external_attachments']

self.assertEqual(external_attachments[0], expected_external_attachment)

def test_description_is_not_a_valid_gp2gp_message(self):
expected_external_attachment = {
'document_id': '_735BB673-D9C0-4B85-951E-98DD045C4713',
'message_id': 'E54DEC57-6BA5-40AB-ACD0-1E383209C034',
'description': 'This is not a valid GP2GP Message',
'title': None
}

description = 'This is not a valid GP2GP Message'

xml_tree = self.generate_soap_envelope_from_description(description)

external_attachments = ebxml_envelope.EbxmlEnvelope.parse_external_attachments(xml_tree)['external_attachments']

self.assertEqual(external_attachments[0], expected_external_attachment)

def test_description_contains_duplicated_filename_key(self):
expected_external_attachment = {
'document_id': '_735BB673-D9C0-4B85-951E-98DD045C4713',
'message_id': 'E54DEC57-6BA5-40AB-ACD0-1E383209C034',
'description': 'Filename="marbles.BMP" Filename="marbles2.BMP" '
'ContentType=application/octet-stream Compressed=Yes LargeAttachment=No '
'OriginalBase64=No Length=3345444',
'title': '"marbles2.BMP"'
}

description = (
'Filename="marbles.BMP" Filename="marbles2.BMP" ContentType=application/octet-stream '
'Compressed=Yes LargeAttachment=No OriginalBase64=No Length=3345444'
)

xml_tree = self.generate_soap_envelope_from_description(description)

external_attachments = ebxml_envelope.EbxmlEnvelope.parse_external_attachments(xml_tree)['external_attachments']

self.assertEqual(external_attachments[0], expected_external_attachment)

@staticmethod
def generate_soap_envelope_from_description(description):
message = '''
<soap:Envelope xmlns:eb="http://www.oasis-open.org/committees/ebxml-msg/schema/msg-header-2_0.xsd"
xmlns:hl7ebxml="urn:hl7-org:transport/ebxml/DSTUv1.0"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<eb:MessageHeader eb:version="2.0" soap:mustUnderstand="1">
<eb:From>
<eb:PartyId eb:type="urn:nhs:names:partyType:ocs+serviceInstance">C88046-807354</eb:PartyId>
</eb:From>
<eb:To>
<eb:PartyId eb:type="urn:nhs:names:partyType:ocs+serviceInstance">P83007-822482</eb:PartyId>
</eb:To>
<eb:CPAId>d434c95b662b941a59f9</eb:CPAId>
<eb:ConversationId>A0000131-351C-452F-BEDB-3ED4759A0800</eb:ConversationId>
<eb:Service>urn:nhs:names:services:gp2gp</eb:Service>
<eb:Action>RCMR_IN030000UK07</eb:Action>
<eb:MessageData>
<eb:MessageId>F01D21CB-31A3-49C6-B0FC-A64C858149AA</eb:MessageId>
<eb:Timestamp>2024-12-10T08:02:33.405Z</eb:Timestamp>
<eb:TimeToLive>2024-12-10T14:17:33.405Z</eb:TimeToLive>
</eb:MessageData>
<eb:DuplicateElimination />
</eb:MessageHeader>
<eb:AckRequested eb:version="2.0" soap:mustUnderstand="1"
soap:actor="urn:oasis:names:tc:ebxml-msg:actor:nextMSH" eb:signed="false" />
</soap:Header>
<soap:Body>
<eb:Manifest eb:version="2.0" soap:mustUnderstand="1">
<eb:Reference xlink:href="cid:[email protected]/EMISWeb/GP2GP2.2A"
xmlns:xlink="http://www.w3.org/1999/xlink">
<eb:Description xml:lang="en">RCMR_IN030000UK07</eb:Description>
<hl7ebxml:Payload style="HL7" encoding="XML" version="3.0" />
</eb:Reference>
<eb:Reference xlink:href="mid:E54DEC57-6BA5-40AB-ACD0-1E383209C034"
eb:id="_735BB673-D9C0-4B85-951E-98DD045C4713"
xmlns:xlink="http://www.w3.org/1999/xlink">
<eb:Description xml:lang="en">%s</eb:Description>
</eb:Reference>
</eb:Manifest>
</soap:Body>
</soap:Envelope>''' % description

xml_tree = ElementTree.fromstring(message)
return xml_tree