All files / src/utils webhookSecret.ts

44.11% Statements 15/34
42.85% Branches 6/14
75% Functions 3/4
40.62% Lines 13/32

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 54 55 56 57 58 59 60 61 62 63 64 65              1x       7x 7x 11x   7x 3x     4x 4x   4x     4x     4x 1x     3x                                                                
import crypto from "crypto"
 
import { NextFunction, Request, Response } from "express"
import pino from "pino"
 
import { env } from "../config"
 
const logger = pino()
 
export function verifyWebhookSignature(signatureHeader: string, rawBody: string, secret: string): boolean {
  // Parse la signature : t=...,v1=...
  const parts = signatureHeader.split(",")
  const timestampPart = parts.find((p) => p.startsWith("t="))
  const signaturePart = parts.find((p) => p.startsWith("v1="))
 
  if (!timestampPart || !signaturePart) {
    return false
  }
 
  const timestamp = timestampPart.slice(2)
  const receivedSignature = signaturePart.slice(3)
 
  const signedPayload = `${timestamp}.${rawBody}`
 
  // Calcul du HMAC SHA3-256
  const expectedSignature = crypto.createHmac("sha3-256", secret).update(signedPayload, "utf8").digest("hex")
 
  // Comparaison en temps constant
  if (expectedSignature.length !== receivedSignature.length) {
    return false
  }
 
  return crypto.timingSafeEqual(Buffer.from(expectedSignature, "hex"), Buffer.from(receivedSignature, "hex"))
}
 
export function verifyWebhookMiddleware(req: Request & { rawBody?: string }, res: Response, next: NextFunction) {
  logger.debug("Verifying webhook signature")
 
  if (!req.headers["signature"]) {
    logger.error("No signature header found")
    res.status(400).send("No signature header found")
    return
  }
 
  if (!req.rawBody) {
    logger.error("No raw body found on request")
    res.status(400).send("No raw body found")
    return
  }
 
  if (!env.fireflyWebhookSecret) {
    logger.error("No webhook secret configured")
    res.status(500).send("No webhook secret configured")
    return
  }
 
  const isValid = verifyWebhookSignature(req.headers["signature"] as string, req.rawBody, env.fireflyWebhookSecret)
  if (isValid) {
    logger.debug("Webhook signature verified")
    return next()
  }
  logger.error("Invalid webhook signature")
  res.status(401).send("Invalid webhook signature")
}