Skip to content

Commit 068e59f

Browse files
committed
Add validateHMACSignature
1 parent 082578b commit 068e59f

File tree

1 file changed

+43
-1
lines changed

1 file changed

+43
-1
lines changed

src/utils/hmacValidator.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,26 @@ class HmacValidator {
2727
public static HMAC_SHA256_ALGORITHM = "sha256";
2828
public static DATA_SEPARATOR = ":";
2929

30+
/**
31+
* Calculate HMAC signature of the payload data
32+
* @param data payload as String or as NotificationRequestItem
33+
* @param key HMAC key
34+
* @returns HMAC signature
35+
*/
3036
public calculateHmac(data: string | NotificationRequestItem, key: string): string {
3137
const dataString = typeof data !== "string" ? this.getDataToSign(data) : data;
3238
const rawKey = Buffer.from(key, "hex");
3339
return createHmac(HmacValidator.HMAC_SHA256_ALGORITHM, rawKey).update(dataString, "utf8").digest("base64");
3440
}
3541

42+
/**
43+
* @deprecated use Use validateHMACSignature with correct parameter order instead
44+
* Validate HMAC signature for Banking webhooks
45+
* @param hmacKey
46+
* @param hmacSign
47+
* @param notification
48+
* @returns
49+
*/
3650
public validateBankingHMAC(hmacKey: string, hmacSign: string, notification: string): boolean {
3751
const expectedSign = createHmac(HmacValidator.HMAC_SHA256_ALGORITHM, Buffer.from(hmacSign, "hex")).update(notification, "utf8").digest("base64");
3852
if(hmacKey?.length === expectedSign.length) {
@@ -44,6 +58,30 @@ class HmacValidator {
4458
return false;
4559
}
4660

61+
/**
62+
* Validate HMAC signature for Banking/Management webhooks
63+
* @param hmacKey HMAC key
64+
* @param hmacSignature HMAC signature to validate
65+
* @param data webhook payload (as string)
66+
* @returns true when HMAC signature is valid
67+
*/
68+
public validateHMACSignature(hmacKey: string, hmacSignature: string, data: string): boolean {
69+
const expectedSign = createHmac(HmacValidator.HMAC_SHA256_ALGORITHM, Buffer.from(hmacKey, "hex")).update(data, "utf8").digest("base64");
70+
if(hmacSignature?.length === expectedSign.length) {
71+
return timingSafeEqual(
72+
Buffer.from(expectedSign, "base64"),
73+
Buffer.from(hmacSignature, "base64")
74+
);
75+
}
76+
return false;
77+
}
78+
79+
/**
80+
* Validate HMAC signature for Payment webhooks
81+
* @param notificationRequestItem webhook payload (as NotificationRequestItem object)
82+
* @param key HMAC key
83+
* @returns true when HMAC signature is valid
84+
*/
4785
public validateHMAC(notificationRequestItem: NotificationRequestItem, key: string): boolean {
4886
if (notificationRequestItem.additionalData?.[ApiConstants.HMAC_SIGNATURE]) {
4987
const expectedSign = this.calculateHmac(notificationRequestItem, key);
@@ -55,7 +93,6 @@ class HmacValidator {
5593
);
5694
}
5795
return false;
58-
5996
}
6097
throw Error(`Missing ${ApiConstants.HMAC_SIGNATURE}`);
6198
}
@@ -64,6 +101,11 @@ class HmacValidator {
64101
return !Object.values(item).every((value): boolean => typeof value === "string");
65102
}
66103

104+
/**
105+
* extract fields to be used to calculate the HMAC signature
106+
* @param notificationRequestItem webhook payload
107+
* @returns data to sign (as string)
108+
*/
67109
public getDataToSign(notificationRequestItem: DataToSign): string {
68110
if (this.isNotificationRequestItem(notificationRequestItem)) {
69111
const signedDataList = [];

0 commit comments

Comments
 (0)