UNPKG

connect-sdk-nodejs

Version:

SDK to communicate with the Ingenico ePayments platform using the Ingenico Connect Server API

129 lines 4.42 kB
"use strict"; /* eslint-disable @typescript-eslint/no-non-null-assertion */ const crypto = require("crypto"); const compare = require("secure-compare"); const versions_1 = require("../utils/versions"); const webhooks_1 = require("../model/webhooks"); const webhooksContext = { // eslint-disable-next-line @typescript-eslint/no-unused-vars getSecretKey(_keyId, _cb) { throw new Error("getSecretKey not initialized yet"); } }; const secretKeyStore = {}; function getHeaderValue(requestHeaders, headerName) { const lowerCaseHeaderName = headerName.toLowerCase(); for (const name in requestHeaders) { if (name != null && lowerCaseHeaderName === name.toLowerCase()) { const value = requestHeaders[name]; if (typeof value === "string") { return value; } if (typeof value === "undefined") { throw new Error("could not find header '" + headerName + "'"); } throw new Error("found multiple values for header '" + headerName + "'"); } } throw new Error("could not find header '" + headerName + "'"); } function validateBody(body, requestHeaders, cb) { try { const signature = getHeaderValue(requestHeaders, "X-GCS-Signature"); const keyId = getHeaderValue(requestHeaders, "X-GCS-KeyId"); webhooksContext.getSecretKey(keyId, (error, secretKey) => { if (error) { cb(error); } else { const expectedSignature = crypto .createHmac("sha256", secretKey) // if error is falsy, secretKey isn't .update(body) .digest("base64"); if (compare(signature, expectedSignature)) { cb(null); } else { cb(new Error("failed to validate signature '" + signature + "'")); } } }); } catch (e) { cb(e); } } function validate(body, requestHeaders, cb) { try { validateBody(body, requestHeaders, cb); } catch (e) { cb(e); } } function validateApiVersion(event) { if (versions_1.apiVersion !== event.apiVersion) { throw new webhooks_1.ApiVersionMismatchError("event API version " + event.apiVersion + " is not compatible with SDK API version " + versions_1.apiVersion, event.apiVersion, versions_1.apiVersion); } } function unmarshal(body, requestHeaders, cb) { validate(body, requestHeaders, error => { if (error) { cb(error, null); } else { try { const event = JSON.parse(body.toString()); validateApiVersion(event); cb(null, event); } catch (e) { cb(e, null); } } }); } const webhooksHelper = { init: context => { if (!context || !context.getSecretKey || typeof context.getSecretKey !== "function") { throw new Error("no valid secret key store given"); } webhooksContext.getSecretKey = context.getSecretKey; return webhooksHelper; }, validate: validate, unmarshal: unmarshal, inMemorySecretKeyStore: { getSecretKey(keyId, cb) { const secretKey = secretKeyStore[keyId]; if (!secretKey) { cb(new webhooks_1.SecretKeyNotAvailableError("could not find secret key for key id " + keyId, keyId), null); } else { cb(null, secretKey); } }, storeSecretKey(keyId, secretKey) { if (!keyId || !keyId.trim()) { throw new Error("keyId is required"); } if (!secretKey || !secretKey.trim()) { throw new Error("secretKey is required"); } secretKeyStore[keyId] = secretKey; }, removeSecretKey(keyId) { delete secretKeyStore[keyId]; }, clear() { for (const prop in secretKeyStore) { // eslint-disable-next-line no-prototype-builtins if (secretKeyStore.hasOwnProperty(prop)) { delete secretKeyStore[prop]; } } } } }; module.exports = webhooksHelper; //# sourceMappingURL=index.js.map