Skip to content

Commit d124574

Browse files
committed
Add tools/hmac
1 parent 7cc1838 commit d124574

File tree

4 files changed

+144
-0
lines changed

4 files changed

+144
-0
lines changed

tools/hmac/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
## HMAC Tools
2+
3+
This folder contains PHP scripts to calculate the HMAC signature of the webhook payload.
4+
They can be used to troubleshoot the HMAC signature calculation.
5+
6+
Note: make sure you are using the HMAC key used to generate the signature associated with the payload in the JSON file
7+
8+
### Payments webhooks
9+
10+
Copy the content of the webhook in the payload.json (or provide a different file), then run with:
11+
`node hmacValidatorPayments.js {hmacKey} {path to JSON file}`
12+
```
13+
cd tools/hmac
14+
node hmacValidatorPayments.js 11223344D785FBAE710E7F943F307971BB61B21281C98C9129B3D4018A57B2EB tools/hmac/payload.json
15+
```
16+

tools/hmac/hmacValidatorPayments.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// script to calculate the HMAC signature of Payments webhooks (where the signature is calculated considering
2+
// a subset of the fields in the payload - i.e. NotificationRequestItem object)
3+
//
4+
// Run with: `node hmacValidatorPayments.js {hmacKey} {path to JSON file}
5+
//
6+
// cd tools/hmac
7+
// node hmacValidatorPayments.js 11223344D785FBAE710E7F943F307971BB61B21281C98C9129B3D4018A57B2EB payload.json
8+
9+
const fs = require('fs');
10+
const { hmacValidator } = require('@adyen/api-library');
11+
12+
// Ensure correct arguments
13+
if (process.argv.length !== 4) {
14+
console.error("Usage: node HMACValidatorPayments.js <hmacKey> <payloadFile>");
15+
process.exit(1);
16+
}
17+
18+
const hmacKey = process.argv[2];
19+
const payloadFile = process.argv[3];
20+
21+
// Check if file exists
22+
if (!fs.existsSync(payloadFile)) {
23+
console.error(`Error: File '${payloadFile}' not found.`);
24+
process.exit(1);
25+
}
26+
27+
console.log(`Calculating HMAC signature with payload from '${payloadFile}'`);
28+
29+
// Load and parse JSON file
30+
let jsonData;
31+
try {
32+
const fileContent = fs.readFileSync(payloadFile, 'utf8');
33+
jsonData = JSON.parse(fileContent);
34+
} catch (error) {
35+
console.error("Error: Invalid JSON in payload file.");
36+
process.exit(1);
37+
}
38+
39+
// Validate JSON structure
40+
if (!jsonData.notificationItems || !Array.isArray(jsonData.notificationItems)) {
41+
console.error("Error: 'notificationItems' key is missing or not an array.");
42+
process.exit(1);
43+
}
44+
45+
// Extract the first (and only) NotificationRequestItem
46+
const notificationRequestItem = jsonData.notificationItems[0]?.NotificationRequestItem;
47+
48+
if (!notificationRequestItem) {
49+
console.error("Error: 'NotificationRequestItem' is not found.");
50+
process.exit(1);
51+
}
52+
53+
//console.log(notificationRequestItem)
54+
55+
const validator = new hmacValidator()
56+
const hmacSignature = validator.calculateHmac(notificationRequestItem, hmacKey);
57+
58+
console.log(`HMAC Validation Result: ${hmacSignature}`);
59+
process.exit(0);

tools/hmac/package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "hmac-troubleshooting",
3+
"version": "1.0.0",
4+
"main": "index.js",
5+
"scripts": {
6+
"test": "echo \"Error: no test specified\" && exit 1"
7+
},
8+
"keywords": [],
9+
"author": "",
10+
"license": "ISC",
11+
"description": "Scripts to troubleshooting HMAC signature calculation",
12+
"dependencies": {
13+
"@adyen/api-library": "^25.0.0"
14+
}
15+
}

tools/hmac/payload.json

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"live": "false",
3+
"notificationItems": [
4+
{
5+
"NotificationRequestItem": {
6+
"additionalData": {
7+
"cardSummary": "0010",
8+
"hmacSignature": "e7qQumH1fdt5NHb6e62jq6hIGUCpfhAAFXhUXqXcJAQ=",
9+
"expiryDate": "03\/2030",
10+
"recurring.contractTypes": "ONECLICK,RECURRING",
11+
"cardBin": "222241",
12+
"recurring.recurringDetailReference": "DQWW2BQ9FX2R7475",
13+
"recurringProcessingModel": "Subscription",
14+
"metadata.orderTransactionId": "63",
15+
"alias": "F758505419855455",
16+
"paymentMethodVariant": "m1",
17+
"acquirerReference": "JQBMF3P3FJM",
18+
"issuerBin": "22224107",
19+
"cardIssuingCountry": "NL",
20+
"authCode": "060494",
21+
"cardHolderName": "Checkout Test",
22+
"PaymentAccountReference": "Jj3gVfMpPcpKzmHrHmpxqgfsvGaVa",
23+
"checkout.cardAddedBrand": "mc",
24+
"store": "None",
25+
"tokenization.shopperReference": "4d74f0727a318b13f85aee28ae556a08d7d9cf9e6d67b70a62e60e334aa7090d",
26+
"recurring.firstPspReference": "P9M9CTGJKKKKP275",
27+
"tokenization.storedPaymentMethodId": "DQWW2BQ9FX2R7475",
28+
"issuerCountry": "NL",
29+
"aliasType": "Default",
30+
"paymentMethod": "mc",
31+
"recurring.shopperReference": "4d74f0727a318b13f85aee28ae556a08d7d9cf9e6d67b70a62e60e334aa7090d",
32+
"cardPaymentMethod": "mc2"
33+
},
34+
"amount": {
35+
"currency": "EUR",
36+
"value": 32500
37+
},
38+
"eventCode": "AUTHORISATION",
39+
"eventDate": "2025-02-24T15:20:56+01:00",
40+
"merchantAccountCode": "Merchant 1",
41+
"merchantReference": "1143-R2",
42+
"operations": [
43+
"CANCEL",
44+
"CAPTURE",
45+
"REFUND"
46+
],
47+
"paymentMethod": "mc",
48+
"pspReference": "AB1234567890",
49+
"reason": "060494:0010:03\/2030",
50+
"success": "true"
51+
}
52+
}
53+
]
54+
}

0 commit comments

Comments
 (0)