The following Node.js example shows how to read the raw request body, calculate the expected HMAC signature, and compare it with the signature received in the request headers.
const http = require('http');
const crypto = require('crypto');
const secret = process.env.EHI_HMAC_SECRET;
const port = Number(process.env.PORT || 8085);
function sha256Hex(buffer) {
return crypto.createHash('sha256').update(buffer).digest('hex');
}
http
.createServer((req, res) => {
const chunks = [];
const receivedAt = new Date().toISOString();
req.on('data', (chunk) => chunks.push(chunk));
req.on('end', () => {
const rawBodyBuffer = Buffer.concat(chunks);
const rawBody = rawBodyBuffer.toString('utf8');
const signatureTimestamp = req.headers['x-ehi-signature-timestamp'];
const receivedSignature = req.headers['x-ehi-signature'];
const algorithm = req.headers['x-ehi-signature-algorithm'];
const payloadToSignBuffer = Buffer.concat([
Buffer.from(`${signatureTimestamp}.`, 'utf8'),
rawBodyBuffer,
]);
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payloadToSignBuffer)
.digest('hex');
const report = {
receivedAt,
request: {
method: req.method,
url: req.url,
httpVersion: req.httpVersion,
remoteAddress: req.socket.remoteAddress,
remotePort: req.socket.remotePort,
headers: req.headers,
rawHeaders: req.rawHeaders,
},
body: {
rawBody,
byteLength: rawBodyBuffer.length,
sha256: sha256Hex(rawBodyBuffer),
base64: rawBodyBuffer.toString('base64'),
},
hmac: {
algorithm,
timestamp: signatureTimestamp,
receivedSignature,
expectedSignature,
matches: receivedSignature === expectedSignature,
payloadToSignByteLength: payloadToSignBuffer.length,
payloadToSignSha256: sha256Hex(payloadToSignBuffer),
secretByteLength: Buffer.byteLength(secret || '', 'utf8'),
secretFingerprintSha256: sha256Hex(
Buffer.from(secret || '', 'utf8'),
).slice(0, 16),
},
};
console.log('\n================ EHI REQUEST ================');
console.dir(report, { depth: null, colors: true });
console.log('=============================================\n');
res.writeHead(report.hmac.matches ? 200 : 401, {
'content-type': 'application/json',
});
res.end(
JSON.stringify({
Acknowledgement: '1',
Responsestatus: '00',
}),
);
});
})
.listen(port, '127.0.0.1', () => {
console.log(`Mock sponsor on http://127.0.0.1:${port}/ehi`);
});