UNPKG

@adyen/api-library

Version:

The Adyen API Library for NodeJS enables you to work with Adyen APIs.

116 lines 5.89 kB
"use strict"; /* * ###### * ###### * ############ ####( ###### #####. ###### ############ ############ * ############# #####( ###### #####. ###### ############# ############# * ###### #####( ###### #####. ###### ##### ###### ##### ###### * ###### ###### #####( ###### #####. ###### ##### ##### ##### ###### * ###### ###### #####( ###### #####. ###### ##### ##### ###### * ############# ############# ############# ############# ##### ###### * ############ ############ ############# ############ ##### ###### * ###### * ############# * ############ * Adyen NodeJS API Library * Copyright (c) 2026 Adyen B.V. * This file is open source and available under the MIT license. * See the LICENSE file for more info. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.NexoSecurityManager = void 0; const nexoSecurityException_1 = require("./nexoSecurityException"); const nexoDerivedKeyGenerator_1 = require("./nexoDerivedKeyGenerator"); const nexoCryptoPrimitives_1 = require("./nexoCryptoPrimitives"); /** * Handles encryption, decryption, and integrity validation for Cloud Device API * SaleToPOI messages using AES-256-CBC and HMAC-SHA256. */ class NexoSecurityManager { constructor(credentials) { this.derivedKey = null; validateCredentials(credentials); this.credentials = credentials; } /** * Encrypts the SaleToPOI message using the provided message header and credential details. */ encrypt(saleToPoiMessageJson, messageHeader) { try { const dk = this.getDerivedKey(); const messageBytes = Buffer.from(saleToPoiMessageJson, "utf-8"); const ivNonce = (0, nexoCryptoPrimitives_1.generateRandomIvNonce)(); const encryptedBytes = (0, nexoCryptoPrimitives_1.crypt)(messageBytes, dk, ivNonce, "encrypt"); const hmacBytes = (0, nexoCryptoPrimitives_1.hmac)(messageBytes, dk); return { MessageHeader: messageHeader, NexoBlob: encryptedBytes.toString("base64"), SecurityTrailer: { AdyenCryptoVersion: this.credentials.adyenCryptoVersion, KeyIdentifier: this.credentials.keyIdentifier, KeyVersion: this.credentials.keyVersion, Nonce: ivNonce.toString("base64"), Hmac: hmacBytes.toString("base64"), }, }; } catch (e) { if (e instanceof nexoSecurityException_1.NexoSecurityException) throw e; throw new nexoSecurityException_1.NexoSecurityException("Cannot encrypt the SaleToPOISecuredMessage", e); } } /** * Decrypts a SaleToPOI secured message and returns the plaintext JSON string. */ decrypt(secured) { let decryptedBytes; try { const dk = this.getDerivedKey(); const encryptedBytes = Buffer.from(secured.NexoBlob, "base64"); const ivNonce = Buffer.from(secured.SecurityTrailer.Nonce, "base64"); decryptedBytes = (0, nexoCryptoPrimitives_1.crypt)(encryptedBytes, dk, ivNonce, "decrypt"); const receivedHmac = Buffer.from(secured.SecurityTrailer.Hmac, "base64"); (0, nexoCryptoPrimitives_1.validateHmac)(receivedHmac, decryptedBytes, dk); } catch (_a) { // Emit a single, generic error for every failure mode (padding, HMAC, nonce, decoding). // Distinguishable errors would reintroduce a CBC padding-oracle side channel. throw new nexoSecurityException_1.NexoSecurityException("Decryption of the SaleToPOISecuredMessage failed"); } // Only reachable once the message is cryptographically verified, so a distinct diagnostic // here is safe: a tampered message fails the HMAC check above and never reaches this point. this.validateKeyMetadata(secured); return decryptedBytes.toString("utf-8"); } validateKeyMetadata(secured) { const trailer = secured.SecurityTrailer; if (trailer.KeyIdentifier !== this.credentials.keyIdentifier || trailer.KeyVersion !== this.credentials.keyVersion || trailer.AdyenCryptoVersion !== this.credentials.adyenCryptoVersion) { // Do not include the KeyIdentifier value: it is credential material and this message // is likely to end up in logs. Only report the non-sensitive version numbers. throw new nexoSecurityException_1.NexoSecurityException("SecurityTrailer key metadata does not match the configured credentials: " + `expected KeyVersion=${this.credentials.keyVersion}, AdyenCryptoVersion=${this.credentials.adyenCryptoVersion} ` + `but received KeyVersion=${trailer.KeyVersion}, AdyenCryptoVersion=${trailer.AdyenCryptoVersion} ` + `(KeyIdentifier ${trailer.KeyIdentifier === this.credentials.keyIdentifier ? "matches" : "differs"})`); } } getDerivedKey() { if (!this.derivedKey) { this.derivedKey = (0, nexoDerivedKeyGenerator_1.deriveKeyMaterial)(this.credentials.passphrase); } return this.derivedKey; } } exports.NexoSecurityManager = NexoSecurityManager; function validateCredentials(credentials) { if (!credentials || !credentials.passphrase || !credentials.keyIdentifier || !Number.isFinite(credentials.keyVersion) || !Number.isFinite(credentials.adyenCryptoVersion)) { throw new nexoSecurityException_1.NexoSecurityException("Invalid Security Key"); } } //# sourceMappingURL=nexoSecurityManager.js.map