All files / src/auth-strategies hmac.validation.ts

31.25% Statements 5/16
0% Branches 0/5
0% Functions 0/4
31.25% Lines 5/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 301x 1x 1x   1x                                     1x            
import crypto from 'crypto';
import { CONTENT_TYPE } from '@logchain/configs';
import { AuthError, HmacPrincipal } from './hmac.auth.strategy';
 
const ALGORITHM = 'sha256';
 
function createHash(data: object, hashAlg = 'md5') {
  return crypto.createHash('md5').update(JSON.stringify(data)).digest('hex');
}
 
function computeHmac(hmacPrincipal: HmacPrincipal, body: object): crypto.Hmac {
  const { created, options, keyId, nonce, method, url } = hmacPrincipal;
  const hashBody = createHash(body);
  const stringToSign = `${keyId}\n${nonce}\n${created}\n${method}\n${hashBody}\n${CONTENT_TYPE.JSON}\n${url}`;
  return crypto.createHmac(ALGORITHM, options.secretAccessKey).update(stringToSign);
}
 
function isValidSignature(hmac: crypto.Hmac, signature: string) {
  const sourceDigest = Buffer.from(signature, 'utf8');
  const hmacBuffer = Buffer.from(hmac.digest('base64'), 'utf8');
  return hmacBuffer.length === sourceDigest.length && crypto.timingSafeEqual(hmacBuffer, sourceDigest);
}
 
export function verifySignature(hmacPrincipal: HmacPrincipal, body: object) {
  const hmac = computeHmac(hmacPrincipal, body);
  if (!isValidSignature(hmac, hmacPrincipal.signature)) {
    throw new AuthError(`Invalid signature.`);
  }
}