@shopify/shopify-api
Version:
Shopify API Library for Node - accelerate development with support for authentication, graphql proxy, webhooks
71 lines (68 loc) • 2.7 kB
JavaScript
import { logger } from '../logger/index.mjs';
import { validateHmacFromRequestFactory } from '../utils/hmac-validator.mjs';
import { HmacValidationType, ValidationErrorReason } from '../utils/types.mjs';
import { abstractConvertRequest } from '../../runtime/http/index.mjs';
import { ShopifyHeader } from '../types.mjs';
import { WebhookValidationErrorReason } from './types.mjs';
import { topicForStorage } from './registry.mjs';
import { getHeader } from '../../runtime/http/headers.mjs';
const OPTIONAL_HANDLER_PROPERTIES = {
subTopic: ShopifyHeader.SubTopic,
};
const HANDLER_PROPERTIES = {
apiVersion: ShopifyHeader.ApiVersion,
domain: ShopifyHeader.Domain,
hmac: ShopifyHeader.Hmac,
topic: ShopifyHeader.Topic,
webhookId: ShopifyHeader.WebhookId,
...OPTIONAL_HANDLER_PROPERTIES,
};
function validateFactory(config) {
return async function validate({ rawBody, ...adapterArgs }) {
const request = await abstractConvertRequest(adapterArgs);
const validHmacResult = await validateHmacFromRequestFactory(config)({
type: HmacValidationType.Webhook,
rawBody,
...adapterArgs,
});
if (!validHmacResult.valid) {
if (validHmacResult.reason === ValidationErrorReason.InvalidHmac) {
const log = logger(config);
await log.debug("Webhook HMAC validation failed. Please note that events manually triggered from a store's Notifications settings will fail this validation. To test this, please use the CLI or trigger the actual event in a development store.");
}
return validHmacResult;
}
return checkWebhookHeaders(request.headers);
};
}
function checkWebhookHeaders(headers) {
const missingHeaders = [];
const entries = Object.entries(HANDLER_PROPERTIES);
const headerValues = entries.reduce((acc, [property, headerName]) => {
const headerValue = getHeader(headers, headerName);
if (headerValue) {
acc[property] = headerValue;
}
else if (!(property in OPTIONAL_HANDLER_PROPERTIES)) {
missingHeaders.push(headerName);
}
return acc;
}, {});
if (missingHeaders.length) {
return {
valid: false,
reason: WebhookValidationErrorReason.MissingHeaders,
missingHeaders,
};
}
else {
return {
valid: true,
...headerValues,
...(headerValues.subTopic ? { subTopic: headerValues.subTopic } : {}),
topic: topicForStorage(headerValues.topic),
};
}
}
export { validateFactory };
//# sourceMappingURL=validate.mjs.map