All files / src/encryption hmacSha256.ts

100% Statements 15/15
100% Branches 2/2
100% Functions 5/5
100% Lines 15/15

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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 541x               1x       43x       43x     43x       1x       1x       1x       1x         1x       1x 44x 44x 1x   43x        
import { getCryptoLib } from './cryptoUtils'
 
export interface Hmac {
  digest(key: Buffer, data: Buffer): Promise<Buffer>;
}
 
type NodeCryptoCreateHmac = typeof import('crypto').createHmac
 
export class NodeCryptoHmacSha256 implements Hmac {
  createHmac: NodeCryptoCreateHmac
 
  constructor(createHmac: NodeCryptoCreateHmac) {
    this.createHmac = createHmac
  }
 
  async digest(key: Buffer, data: Buffer): Promise<Buffer> {
    const result = this.createHmac('sha256', key)
      .update(data)
      .digest()
    return Promise.resolve(result)
  }
}
 
export class WebCryptoHmacSha256 implements Hmac {
  subtleCrypto: SubtleCrypto
 
  constructor(subtleCrypto: SubtleCrypto) {
    this.subtleCrypto = subtleCrypto
  }
 
  async digest(key: Buffer, data: Buffer): Promise<Buffer> {
    const cryptoKey = await this.subtleCrypto.importKey(
      'raw', key, { name: 'HMAC', hash: 'SHA-256' },
      true, ['sign']
    )
    const sig = await this.subtleCrypto.sign(
      // The `hash` is only specified for non-compliant browsers like Edge. 
      { name: 'HMAC', hash: 'SHA-256' }, 
      cryptoKey, data
    )
    return Buffer.from(sig)
  }
}
 
export async function createHmacSha256(): Promise<Hmac> {
  const cryptoLib = await getCryptoLib()
  if (cryptoLib.name === 'subtleCrypto') {
    return new WebCryptoHmacSha256(cryptoLib.lib)
  } else {
    return new NodeCryptoHmacSha256(cryptoLib.lib.createHmac)
  }
}