connect-sdk-nodejs
Version:
SDK to communicate with the Ingenico ePayments platform using the Ingenico Connect Server API
129 lines • 4.42 kB
JavaScript
;
/* 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