Good morning
Hope you can help - looking at trying to set up an interface in Mirth that could generate the necessary auth header to connect to a mailbox via the API using HMAC SHA256 as per your Python3 example. Are there any additional resources showing how to do it outside of Python i.e. using Java or Javascript?
Thanks
Hi Matthew,
For javascript, I can point you at Javascript-mesh-client/src/headers/generate_headers.js at main · NHSDigital/Javascript-mesh-client · GitHub - this was developed by a product team external to MESH, but is now owned by the MESH team, although we haven’t developed it since it was handed over. We are more than happy to accept pull requests to that repo if you wish to use and contribute to its development for the rest of the community.
Is there a particular language you are developing in / considering developing in?
Hope that helps - but please get back in touch if there is anything further we can help with.
Best regards,
Dave
1 Like
Thank you sir, having a look at that now. In the past we have used Mirth which is a Java application and makes use of JavaScript interfaces which can interact with JS libraries or load Java classes. In an earlier project which resulted in a hash similar to the MESH API, we used libraries such as CryptoJS to create the auth header for us. However what you have sent over - may do the job also.
Doesnt look like we can use that method as it is Node only. We need the JavaScript to run inside a Mirth channel. Sadly the Crypto module of Node is not available externally.
Would there be any further examples that can be sent over?
Hi Matthew,
Unfortunately I don’t have any further examples of javascript code that interfaces to MESH. I guess the key challenge is generating the HMAC. I’m not familiar with Mirth and what its constraints and limitations are, but a quick google suggests that it uses Rhino (a javascript implementation in Java) and a quick chatgpt on how to generate a HMAC in Rhino brings up code like this which runs fine in Online Compiler and Editor/IDE for Java, C, C++, PHP, Python, Ruby, Perl - Code and Run Online. NB: I’ve not verified this against MESH, but hopefully the APIs used here give you inspiration to develop your solution.
var secret = "my-secret-key";
var message = "Hello, world!";
// Convert JS strings to Java Strings before calling getBytes
var secretKey = new java.lang.String(secret).getBytes("UTF-8");
var messageBytes = new java.lang.String(message).getBytes("UTF-8");
var keySpec = new javax.crypto.spec.SecretKeySpec(secretKey, "HmacSHA256");
var mac = javax.crypto.Mac.getInstance("HmacSHA256");
mac.init(keySpec);
var hmacBytes = mac.doFinal(messageBytes);
// Convert bytes to hex
var hex = '';
for (var i = 0; i < hmacBytes.length; i++) {
var byteHex = (hmacBytes[i] & 0xFF).toString(16);
if (byteHex.length === 1) hex += '0';
hex += byteHex;
}
print("HMAC: " + hex);
Good luck - I hope this helps you - let me know how you get on.
Best regards,
Dave
We’re using java based Apache Camel + Spring Boot, so using kotlin.
package virtually.healthcare.orchestration.configuration
import org.apache.commons.codec.binary.Hex
import org.slf4j.LoggerFactory
import org.springframework.context.annotation.Configuration
import java.io.IOException
import java.security.KeyStore
import java.text.SimpleDateFormat
import java.util.*
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManagerFactory
@Configuration
class SSLFactory(val messageProperties: MessageProperties) {
public var sslSocketFactory: SSLSocketFactory? = null
init {
buildSSLFactory()
}
companion object {
private val log = LoggerFactory.getLogger(SSLFactory::class.java)
}
fun getToken( mailbox: String, mailboxPwd: String): String {
val df = SimpleDateFormat("yyyyMMddHHmm")
val date = Date()
val timestamp = df.format(date)
val nonce = UUID.randomUUID()
val hmac_msg = "$mailbox:$nonce:001:$mailboxPwd:$timestamp"
log.info("hash content: $hmac_msg")
val hash = getHash(hmac_msg, "BackBone")
val token = ("NHSMESH " + mailbox + ":" + nonce + ":"
+ "001:"
+ timestamp + ":"
+ hash)
log.debug("token: $token")
return token
}
fun getHash(data: String, key: String): String? {
val algorithm = "HmacSHA256"
return try {
val secretKeySpec = SecretKeySpec(key.toByteArray(), algorithm)
val mac = Mac.getInstance(algorithm)
mac.init(secretKeySpec)
val result = mac.doFinal(data.toByteArray())
Hex.encodeHexString(result)
} catch (ex: java.lang.Exception) {
ex.message
}
}
@Throws(java.lang.Exception::class)
private fun buildSSLFactory() {
try {
// Key Store
val ksp: KeyStore
val classLoader = javaClass.classLoader
var file = classLoader.getResourceAsStream(messageProperties.getSSLKeyStore())
ksp = KeyStore.getInstance("JKS")
val ksppassphrase: CharArray = messageProperties.getSSLKeyStorePwd().toCharArray()
ksp.load(file, ksppassphrase)
val tks: KeyStore
tks = KeyStore.getInstance("JKS")
file = classLoader.getResourceAsStream(messageProperties.getSSLTrustStore())
val tsppassphrase: CharArray = messageProperties.getSSLTrustStorePwd().toCharArray()
tks.load(file, tsppassphrase)
// Key Factories
val kmf: KeyManagerFactory
val tmf: TrustManagerFactory
kmf = KeyManagerFactory.getInstance("SunX509")
kmf.init(ksp, ksppassphrase)
tmf = TrustManagerFactory.getInstance("SunX509")
tmf.init(tks)
// SSL Context
val ctx: SSLContext
ctx = SSLContext.getInstance("TLS")
ctx.init(kmf.keyManagers, tmf.trustManagers, null)
sslSocketFactory = ctx.socketFactory
} catch (e: java.lang.Exception) {
throw IOException(e.message)
}
}
}