Add HmacSignature to additionalData.ts and improve hmac validation tests

This commit is contained in:
Ricardo Ambrogi
2020-05-27 10:50:10 +02:00
parent 650e7dc0a5
commit ef490a5cdf
6 changed files with 82 additions and 26 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@adyen/api-library",
"version": "4.0.0",
"version": "4.0.1",
"description": "The Adyen API Library for NodeJS enables you to work with Adyen APIs.",
"main": "dist/lib/src/index.js",
"types": "dist/lib/src/index.d.ts",

View File

@@ -18,24 +18,32 @@
*/
import HmacValidator from "../utils/hmacValidator";
import {AdditionalData, NotificationRequestItem} from "../typings/notification/models";
import {AdditionalData, NotificationItem, NotificationRequestItem} from "../typings/notification/models";
import {ApiConstants} from "../constants/apiConstants";
import NotificationRequest from "../notification/notificationRequest";
const key = "DFB1EB5485895CFA84146406857104ABB4CBCABDC8AAF103A624C8F6A3EAAB00";
const expectedSign = "xhpHvYq2u2Np0rstbZ6QjLGu7JWhvf7Iwaa6EviJSX0=";
const notificationRequestItem: NotificationRequestItem = {
pspReference: "pspReference",
originalReference: "originalReference",
merchantAccountCode: "merchantAccount",
merchantReference: "reference",
amount: {currency: "EUR", value: 1000},
eventCode: NotificationRequestItem.EventCodeEnum.CAPTURE,
eventDate: new Date("01-01-1970").toISOString(),
paymentMethod: "VISA",
reason: "reason",
success: NotificationRequestItem.SuccessEnum.True,
additionalData: { [ApiConstants.HMAC_SIGNATURE as keyof AdditionalData]: expectedSign },
const expectedSign = "ZNBPtI+oDyyRrLyD1XirkKnQgIAlFc07Vj27TeHsDRE=";
const notificationRequestItem: { NotificationRequestItem: NotificationRequestItem } = {
NotificationRequestItem :{
pspReference: "pspReference",
originalReference: "originalReference",
merchantAccountCode: "merchantAccount",
merchantReference: "reference",
amount: {currency: "EUR", value: 1000},
eventCode: NotificationRequestItem.EventCodeEnum.REPORTAVAILABLE,
eventDate: "2019-09-21T11:45:24.637Z",
paymentMethod: "VISA",
reason: "reason",
success: NotificationRequestItem.SuccessEnum.True,
additionalData: { [ApiConstants.HMAC_SIGNATURE]: expectedSign },
}
};
const notification = new NotificationRequest({
live: "false",
notificationItems: [notificationRequestItem as unknown as NotificationItem]
});
describe("HMAC Validator", function (): void {
let hmacValidator: HmacValidator;
@@ -57,22 +65,59 @@ describe("HMAC Validator", function (): void {
expect(encrypted).toEqual("34oR8T1whkQWTv9P+SzKyp8zhusf9n0dpqrm9nsqSJs=");
});
it("should get correct data to sign", function (): void {
const data = hmacValidator.getDataToSign(notificationRequestItem);
expect(data).toEqual("pspReference:originalReference:merchantAccount:reference:1000:EUR:CAPTURE:true");
const data = hmacValidator.getDataToSign(notification.notificationItems![0]);
expect(data).toEqual("pspReference:originalReference:merchantAccount:reference:1000:EUR:REPORT_AVAILABLE:true");
});
it("should have valid hmac", function (): void {
const encrypted = hmacValidator.calculateHmac(notificationRequestItem, key);
const encrypted = hmacValidator.calculateHmac(notification.notificationItems![0], key);
expect(expectedSign).toEqual(encrypted);
expect(hmacValidator.validateHMAC(notificationRequestItem, key)).toBeTruthy();
expect(hmacValidator.validateHMAC(notification.notificationItems![0], key)).toBeTruthy();
});
it("should have invalid hmac", function (): void {
const invalidNotification = {
...notificationRequestItem,
additionalData: { [ApiConstants.HMAC_SIGNATURE as keyof NotificationRequestItem]: "notValidSign" }
...notification.notificationItems![0],
additionalData: { [ApiConstants.HMAC_SIGNATURE as keyof AdditionalData]: "notValidSign" }
};
const result = hmacValidator.validateHMAC(invalidNotification, key);
expect(result).toBeFalsy();
});
it("should test hmac", function () {
const data = "countryCode:currencyCode:merchantAccount:merchantReference:paymentAmount:sessionValidity:skinCode:NL:EUR:MagentoMerchantTest2:TEST-PAYMENT-2017-02-01-14\\:02\\:05:199:2017-02-02T14\\:02\\:05+01\\:00:PKz2KML1";
const key = "DFB1EB5485895CFA84146406857104ABB4CBCABDC8AAF103A624C8F6A3EAAB00";
const hmacValidator = new HmacValidator();
const encrypted = hmacValidator.calculateHmac(data, key);
expect(encrypted).toEqual("34oR8T1whkQWTv9P+SzKyp8zhusf9n0dpqrm9nsqSJs=");
});
it("should validate HMAC", function () {
expect(hmacValidator.validateHMAC(notification.notificationItems![0], key)).toBeTruthy();
});
it("should have valid notification request item HMAC", function () {
const expectedSign = "ipnxGCaUZ4l8TUW75a71/ghd2Fe5ffvX0pV4TLTntIc=";
const notificationRequestItem = { NotificationRequestItem: {
pspReference: "pspReference",
originalReference: "originalReference",
merchantAccountCode: "merchantAccount",
merchantReference: "reference",
amount: { currency: "EUR", value: 1000 },
eventCode: "EVENT",
success: "true",
additionalData: { [ApiConstants.HMAC_SIGNATURE]: expectedSign }
}} as unknown as NotificationItem;
const notification = new NotificationRequest({
live: "false",
notificationItems: [notificationRequestItem]
});
const data = hmacValidator.getDataToSign(notification.notificationItems![0]);
expect("pspReference:originalReference:merchantAccount:reference:1000:EUR:EVENT:true").toEqual(data);
const encrypted = hmacValidator.calculateHmac(notification.notificationItems![0], key);
expect(expectedSign).toEqual(encrypted);
expect(hmacValidator.validateHMAC(notification.notificationItems![0], key)).toBeTruthy();
notification.notificationItems![0].additionalData![ApiConstants.HMAC_SIGNATURE] = "notValidSign";
expect(hmacValidator.validateHMAC(notification.notificationItems![0], key)).toBeFalsy();
});
});

View File

@@ -61,6 +61,10 @@ export class AdditionalData {
* Currency of the authorised amount.
*/
'authorisedAmountCurrency'?: string;
/**
* HMAC Key from customer area
*/
'hmacSignature'?: string;
static discriminator: string | undefined = undefined;
@@ -99,6 +103,11 @@ export class AdditionalData {
"name": "authorisedAmountCurrency",
"baseName": "authorisedAmountCurrency",
"type": "string"
},
{
"name": "hmacSignature",
"baseName": "hmacSignature",
"type": "string"
} ];
static getAttributeTypeMap() {

View File

@@ -29,7 +29,6 @@
* Do not edit the class manually.
*/
/**
* A container object for the payable amount information for the transaction.For HTTP POST notifications, currency and value are returned as URL parameters.
*/

View File

@@ -165,3 +165,4 @@ export class ObjectSerializer {
}
}
}

View File

@@ -34,10 +34,12 @@ class HmacValidator {
}
public validateHMAC(notificationRequestItem: NotificationRequestItem, key: string): boolean {
const expectedSign = this.calculateHmac(notificationRequestItem, key);
const merchantSign = notificationRequestItem.additionalData?.[ApiConstants.HMAC_SIGNATURE];
return expectedSign === merchantSign;
if (notificationRequestItem.additionalData?.[ApiConstants.HMAC_SIGNATURE]) {
const expectedSign = this.calculateHmac(notificationRequestItem, key);
const merchantSign = notificationRequestItem.additionalData?.[ApiConstants.HMAC_SIGNATURE];
return expectedSign === merchantSign;
}
throw Error(`Missing ${ApiConstants.HMAC_SIGNATURE}`);
}
private isNotificationRequestItem(item: DataToSign): item is NotificationRequestItem {