Skip to content

Instantly share code, notes, and snippets.

@gjesse
Created October 25, 2018 19:38
Show Gist options
  • Save gjesse/3ee37b2031e8e29ea96a3c4677f480d2 to your computer and use it in GitHub Desktop.
Save gjesse/3ee37b2031e8e29ea96a3c4677f480d2 to your computer and use it in GitHub Desktop.
lithium hmac example
// get the crypto-js lib for hashing
var crypto = require('crypto-js');
// get and check the validity of the api key
var apiKey = req.headers['x-auth-apikey'];
if (apiKey !== "<your expected api key>") {
console.log("invalid api key provided")
res.status(401).end();
return;
}
// regex for removing the port section from the host header
var portTrim = /:\d+$/;
// get the host from headers without the port
var host = req.headers['host'].replace(portTrim, "")
// get the provided timestamp header
var ts = req.headers['x-auth-timestamp'];
// get the expected signature
var sig = req.headers['x-auth-signature-v2'];
// calculate header portion of the fingerprint
var headerFingerprint = getHeaderFingerprint(req.headers);
// construct the fingerprint
var fingerprint = [ts, req.method, host + req.url, req.rawBody, headerSig].join('|');
// hash our fingerprint with our secret
var hahs = crypto.HmacSHA256(fingerprint, secret);
// convert to a base64 encoded string
var calculatedSig = crypto.enc.Base64.stringify(hash);
// make sure our signatures match
if (sig !== calculatedSig) {
console.log("provided sig: %s. calculated sig: %s", sig, calculatedSig);
console.log("signatures do not match!")
res.status(401).end();
return;
}
// finally check the timestamp
var now = Date.now()
if (Math.abs(now - ts) > 60000) {
console.log("time drift is too much - rejecting")
res.status(401).end();
return;
}
// extract relevant headers and construct a fingerprint header string
function getHeaderFingerprint(headers) {
// holder array for matching headers
var smmHeaders = [];
// loop through all the provided headers
for (var key in headers) {
var element = headers[key];
// filter in only x-smm-* keys
if (key.startsWith("x-smm-")) {
// your framework may represent multiple header values as a list - if so this will be a little different
// loop over each element for the header
element.split(",").forEach(part => {
// push any found elements on to the array
smmHeaders.push(":" + key + ":" + part.trim());
})
}
}
// sort all headers alphabetically
smmHeaders.sort();
// return a : separated string
return smmHeaders.join("")
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment