• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Adyen / adyen-node-api-library / 5786763605

pending completion
5786763605

Pull #1159

github

web-flow
Merge 78b6393cf into cb8de0b32
Pull Request #1159: Release v14.0.0

97 of 149 branches covered (65.1%)

Branch coverage included in aggregate %.

1519 of 1519 new or added lines in 79 files covered. (100.0%)

1834 of 2388 relevant lines covered (76.8%)

30.72 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.94
/src/utils/hmacValidator.ts
1
/*
2
 *                       ######
3
 *                       ######
4
 * ############    ####( ######  #####. ######  ############   ############
5
 * #############  #####( ######  #####. ######  #############  #############
6
 *        ######  #####( ######  #####. ######  #####  ######  #####  ######
7
 * ###### ######  #####( ######  #####. ######  #####  #####   #####  ######
8
 * ###### ######  #####( ######  #####. ######  #####          #####  ######
9
 * #############  #############  #############  #############  #####  ######
10
 *  ############   ############  #############   ############  #####  ######
11
 *                                      ######
12
 *                               #############
13
 *                               ############
14
 * Adyen NodeJS API Library
15
 * Copyright (c) 2020 Adyen B.V.
16
 * This file is open source and available under the MIT license.
17
 * See the LICENSE file for more info.
18
 */
19

20
import { createHmac, timingSafeEqual } from "crypto";
6✔
21
import { NotificationRequestItem } from "../typings/notification/models";
22
import { ApiConstants } from "../constants/apiConstants";
6✔
23

24
type DataToSign = NotificationRequestItem | { [key: string]: string };
25

26
class HmacValidator {
27
    public static HMAC_SHA256_ALGORITHM = "sha256";
6✔
28
    public static DATA_SEPARATOR = ":";
6✔
29

30
    public calculateHmac(data: string | NotificationRequestItem, key: string): string {
31
        const dataString = typeof data !== "string" ? this.getDataToSign(data) : data;
18✔
32
        const rawKey = Buffer.from(key, "hex");
18✔
33
        return createHmac(HmacValidator.HMAC_SHA256_ALGORITHM, rawKey).update(dataString, "utf8").digest("base64");
18✔
34
    }
35

36
    public validateBankingHMAC(hmacKey: string, hmacSign: string, notification: string): boolean {
37
        const expectedSign = createHmac(HmacValidator.HMAC_SHA256_ALGORITHM, Buffer.from(hmacSign, "hex")).update(notification, "utf8").digest("base64");
2✔
38
        if(hmacKey?.length === expectedSign.length) {
2!
39
            return timingSafeEqual(
2✔
40
                Buffer.from(expectedSign, "base64"),
41
                Buffer.from(hmacKey, "base64")
42
            );
43
        }
44
        return false;
×
45
    }
46

47
    public validateHMAC(notificationRequestItem: NotificationRequestItem, key: string): boolean {
48
        if (notificationRequestItem.additionalData?.[ApiConstants.HMAC_SIGNATURE]) {
12!
49
            const expectedSign = this.calculateHmac(notificationRequestItem, key);
10✔
50
            const merchantSign = notificationRequestItem.additionalData?.[ApiConstants.HMAC_SIGNATURE];
10!
51
            if(merchantSign?.length === expectedSign.length) {
10!
52
                return timingSafeEqual(
6✔
53
                    Buffer.from(expectedSign, "base64"),
54
                    Buffer.from(merchantSign, "base64")
55
                );
56
            }
57
            return false;
4✔
58

59
        }
60
        throw Error(`Missing ${ApiConstants.HMAC_SIGNATURE}`);
2✔
61
    }
62

63
    private isNotificationRequestItem(item: DataToSign): item is NotificationRequestItem {
64
        return !Object.values(item).every((value): boolean => typeof value === "string");
28✔
65
    }
66

67
    public getDataToSign(notificationRequestItem: DataToSign): string {
68
        if (this.isNotificationRequestItem(notificationRequestItem)) {
22✔
69
            const signedDataList = [];
18✔
70
            signedDataList.push(notificationRequestItem.pspReference);
18✔
71
            signedDataList.push(notificationRequestItem.originalReference);
18✔
72
            signedDataList.push(notificationRequestItem.merchantAccountCode);
18✔
73
            signedDataList.push(notificationRequestItem.merchantReference);
18✔
74
            signedDataList.push(notificationRequestItem.amount.value);
18✔
75
            signedDataList.push(notificationRequestItem.amount.currency);
18✔
76
            signedDataList.push(notificationRequestItem.eventCode);
18✔
77
            signedDataList.push(notificationRequestItem.success);
18✔
78
            return signedDataList.join(HmacValidator.DATA_SEPARATOR);
18✔
79
        } else {
80
            const keys: string[] = [];
4✔
81
            const values: string[] = [];
4✔
82
            const replacer = (str: string): string =>
4✔
83
                str.replace(/\\/g, "\\\\").replace(/:/g, "\\:");
20✔
84
            Object.entries(notificationRequestItem).sort().forEach(([key, value]): void => {
4✔
85
                keys.push(replacer(key));
10✔
86
                values.push(replacer(value));
10✔
87
            });
88

89
            return [...keys, ...values].join(HmacValidator.DATA_SEPARATOR);
4✔
90
        }
91
    }
92
}
93

94
export default HmacValidator;
6✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc