Skip to content

Commit 8f87430

Browse files
authored
Merge pull request #119 from NHSDigital/mm-mesh-1629-fix-mesh-auth-pseudocode-and-send-message-payload
mesh-1629: fix auth pseudocode and add request body / response schema…
2 parents 10e4289 + 4f16e08 commit 8f87430

1 file changed

Lines changed: 93 additions & 35 deletions

File tree

specification/mesh-api.yaml

Lines changed: 93 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -293,42 +293,60 @@ info:
293293
294294
**Notes**
295295
- the API rejects the request if the `timestamp` supplied is not within 2 hours of the server time
296-
- in the example below `SHARED_KEY` has been `[REDACTED]`, this is the 'environment shared secret' which you received as part of creating your mailbox
296+
- in the example below `SHARED_KEY` has been `[REDACTED_SHARED_KEY]`, this is the 'environment shared secret' which you received as part of creating your mailbox
297+
- in the example below `MAILBOX_PASSWORD` has been `[REDACTED_PASSWORD]`, this is the 'mesh mailbox password' which you received as part of creating your mailbox
297298
298299
### Example implementation
299300
Here is an implementation of the above in `python3`.
300301
```python
301302
""" Python code to generate a valid authorization header. """
302303
import hmac
303304
import uuid
304-
import datetime from hashlib
305-
import sha256
306-
307-
AUTHSCHEMANAME = "NHSMESH " # Note: Space at the end of the schema.
308-
SHARED_KEY = "[REDACTED]" # Note: Don't hard code your passwords in a real implementation.
309-
310-
def build_auth_header(mailbox_id: str, password: str = "password", nonce: str = None, noncecount: int = 0):
311-
""" Generate MESH Authorization header for mailboxid. """
312-
#Generate a GUID if required.
313-
if not nonce:
314-
nonce = str(uuid.uuid4())
315-
#Current time formatted as yyyyMMddHHmm
316-
#for example, 4th May 2020 13:05 would be 202005041305
317-
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M")
318-
319-
#for example, NHSMESH AMP01HC001:bd0e2bd5-218e-41d0-83a9-73fdec414803:0:202005041305
320-
hmac_msg = mailbox_id + ":" + nonce + ":" + str(nonce_count) + ":" + password + ":" + timestamp
321-
322-
#HMAC is a standard crypto hash method built in the python standard library.
323-
hash_code = hmac.HMAC(SHARED_KEY.encode(), hmac_msg.encode(), sha256).hexdigest()
324-
return (
325-
AUTH_SCHEMA_NAME # Note: No colon between 1st and 2nd elements.
326-
+ mailbox_id + ":"
327-
+ nonce + ":"
328-
+ str(nonce_count) + ":"
329-
+ timestamp+ ":"
330-
+ hash_code
331-
)
305+
import datetime
306+
from hashlib import sha256
307+
308+
AUTH_SCHEMA_NAME = "NHSMESH " # Note: Space at the end of the schema.
309+
SHARED_KEY = "[REDACTED_SHARED_KEY]" # Note: Don't hard code your passwords in a real implementation.
310+
311+
312+
def build_auth_header(mailbox_id: str, password: str = "password", nonce: str = None, nonce_count: int = 0):
313+
""" Generate MESH Authorization header for mailboxid. """
314+
# Generate a GUID if required.
315+
if not nonce:
316+
nonce = str(uuid.uuid4())
317+
# Current time formatted as yyyyMMddHHmm
318+
# for example, 4th May 2020 13:05 would be 202005041305
319+
timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M")
320+
321+
# for example, NHSMESH AMP01HC001:bd0e2bd5-218e-41d0-83a9-73fdec414803:0:202005041305
322+
hmac_msg = mailbox_id + ":" + nonce + ":" + str(nonce_count) + ":" + password + ":" + timestamp
323+
324+
# HMAC is a standard crypto hash method built in the python standard library.
325+
hash_code = hmac.HMAC(SHARED_KEY.encode(), hmac_msg.encode(), sha256).hexdigest()
326+
return (
327+
AUTH_SCHEMA_NAME # Note: No colon between 1st and 2nd elements.
328+
+ mailbox_id + ":"
329+
+ nonce + ":"
330+
+ str(nonce_count) + ":"
331+
+ timestamp+ ":"
332+
+ hash_code
333+
)
334+
335+
336+
# example usage
337+
MAILBOX_ID = "X26AB1234" # Note: Don't hard code your mailbox id in a real implementation.
338+
MAILBOX_PASSWORD = "[REDACTED_PASSWORD]" # Note: Don't hard code your passwords in a real implementation.
339+
340+
# send a new nonce each time
341+
print(build_auth_header(MAILBOX_ID, MAILBOX_PASSWORD))
342+
343+
# or reuse the nonce and increment the nonce_count
344+
my_nonce = str(uuid.uuid4())
345+
346+
print(build_auth_header(MAILBOX_ID, MAILBOX_PASSWORD, my_nonce, nonce_count=1))
347+
print(build_auth_header(MAILBOX_ID, MAILBOX_PASSWORD, my_nonce, nonce_count=2))
348+
349+
332350
```
333351
334352
## MESH API pseudocode
@@ -862,12 +880,18 @@ paths:
862880
responses:
863881
'200':
864882
description: OK, full message retrieved
865-
content: {}
883+
content:
884+
application/octet-stream:
885+
schema:
886+
format: binary
866887
'403':
867888
description: Authentication failed
868889
'206':
869890
description: Partial Content - Indicates that chunk has been downloaded successfully and that there are further chunks.
870-
content: {}
891+
content:
892+
application/octet-stream:
893+
schema:
894+
format: binary
871895
'404':
872896
description: Not Found, message does not exist
873897
'410':
@@ -1240,12 +1264,18 @@ paths:
12401264
responses:
12411265
'200':
12421266
description: OK - chunk downloaded and no further chunks exist
1243-
content: {}
1267+
content:
1268+
application/octet-stream:
1269+
schema:
1270+
format: binary
12441271
'403':
12451272
description: Authentication failed
12461273
'206':
12471274
description: Partial Content - Indicates that chunk has been downloaded successfully and that there are further chunks.
1248-
content: {}
1275+
content:
1276+
application/octet-stream:
1277+
schema:
1278+
format: binary
12491279
'404':
12501280
description: Not Found, message does not exist
12511281
'410':
@@ -1396,7 +1426,7 @@ paths:
13961426
```json
13971427
{"messageID": "20200529155357895317_3573F8"}
13981428
```
1399-
operationId: send_message_messageexchange__mailbox_id__outbox_post
1429+
operationId: send_message
14001430
parameters:
14011431
- description: mailbox identifier
14021432
required: true
@@ -1618,6 +1648,20 @@ paths:
16181648
title: HTTPValidationError
16191649
type: object
16201650
properties: *id001
1651+
requestBody:
1652+
description: message payload or chunk, optionally encoded with content-encoding
1653+
required: true
1654+
content:
1655+
application/octet-stream:
1656+
schema:
1657+
format: binary
1658+
example: '... message payload bytes...'
1659+
'*/*':
1660+
schema:
1661+
format: any
1662+
example: |-
1663+
message content....
1664+
any content type is acceptable but use application/octet-stream if you want a single default
16211665
/messageexchange/{mailbox_id}/outbox/{message_id}/{chunk_number}:
16221666
post:
16231667
tags:
@@ -1708,7 +1752,7 @@ paths:
17081752
--data-binary '@./message.txt_ab.gz' \
17091753
https://mesh-sync.spineservices.nhs.uk/messageexchange/X26HC006/outbox/20200601122152994285_D59900/2
17101754
```
1711-
operationId: send_chunk_messageexchange__mailbox_id__outbox__message_id___chunk_number__post
1755+
operationId: send_chunk
17121756
parameters:
17131757
- description: The index number of the chunk
17141758
required: true
@@ -1881,6 +1925,20 @@ paths:
18811925
title: HTTPValidationError
18821926
type: object
18831927
properties: *id001
1928+
requestBody:
1929+
description: message payload or chunk, optionally encoded with content-encoding
1930+
required: true
1931+
content:
1932+
application/octet-stream:
1933+
schema:
1934+
format: binary
1935+
example: '... message payload bytes...'
1936+
'*/*':
1937+
schema:
1938+
format: any
1939+
example: |-
1940+
message content....
1941+
any content type is acceptable but use application/octet-stream if you want a single default
18841942
/messageexchange/{mailbox_id}/outbox/tracking:
18851943
get:
18861944
tags:

0 commit comments

Comments
 (0)