UNPKG

@hookflo/tern

Version:

A robust, scalable webhook verification framework supporting multiple platforms and signature algorithms

148 lines (147 loc) 7.26 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createCustomVerifier = exports.createAlgorithmVerifier = exports.validateSignatureConfig = exports.getPlatformsUsingAlgorithm = exports.platformUsesAlgorithm = exports.getPlatformAlgorithmConfig = exports.WebhookVerificationService = void 0; const algorithms_1 = require("./verifiers/algorithms"); const custom_algorithms_1 = require("./verifiers/custom-algorithms"); const algorithms_2 = require("./platforms/algorithms"); class WebhookVerificationService { static async verify(request, config) { const verifier = this.getVerifier(config); const result = await verifier.verify(request); // Ensure the platform is set correctly in the result if (result.isValid) { result.platform = config.platform; } return result; } static getVerifier(config) { const platform = config.platform.toLowerCase(); // If a custom signature config is provided, use the new algorithm-based framework if (config.signatureConfig) { return this.createAlgorithmBasedVerifier(config); } // Fallback to platform-specific verifiers for backward compatibility return this.getLegacyVerifier(config); } static createAlgorithmBasedVerifier(config) { const { signatureConfig, secret, toleranceInSeconds = 300 } = config; if (!signatureConfig) { throw new Error('Signature config is required for algorithm-based verification'); } // Use custom verifiers for special cases (token-based, etc.) if (signatureConfig.algorithm === 'custom') { return (0, custom_algorithms_1.createCustomVerifier)(secret, signatureConfig, toleranceInSeconds); } // Use algorithm-based verifiers for standard algorithms return (0, algorithms_1.createAlgorithmVerifier)(secret, signatureConfig, config.platform, toleranceInSeconds); } static getLegacyVerifier(config) { const platform = config.platform.toLowerCase(); // For legacy support, we'll use the algorithm-based approach const platformConfig = (0, algorithms_2.getPlatformAlgorithmConfig)(platform); const configWithSignature = { ...config, signatureConfig: platformConfig.signatureConfig, }; return this.createAlgorithmBasedVerifier(configWithSignature); } // New method to create verifier using platform algorithm config static async verifyWithPlatformConfig(request, platform, secret, toleranceInSeconds = 300) { const platformConfig = (0, algorithms_2.getPlatformAlgorithmConfig)(platform); const config = { platform, secret, toleranceInSeconds, signatureConfig: platformConfig.signatureConfig, }; return await this.verify(request, config); } // Helper method to get all platforms using a specific algorithm static getPlatformsUsingAlgorithm(algorithm) { const { getPlatformsUsingAlgorithm } = require('./platforms/algorithms'); return getPlatformsUsingAlgorithm(algorithm); } // Helper method to check if a platform uses a specific algorithm static platformUsesAlgorithm(platform, algorithm) { const { platformUsesAlgorithm } = require('./platforms/algorithms'); return platformUsesAlgorithm(platform, algorithm); } // Helper method to validate signature config static validateSignatureConfig(config) { const { validateSignatureConfig } = require('./platforms/algorithms'); return validateSignatureConfig(config); } // Simple token-based verification for platforms like Supabase static async verifyTokenBased(request, webhookId, webhookToken) { try { const idHeader = request.headers.get('x-webhook-id'); const tokenHeader = request.headers.get('x-webhook-token'); if (!idHeader || !tokenHeader) { return { isValid: false, error: 'Missing required headers: x-webhook-id and x-webhook-token', platform: 'custom', }; } // Simple comparison - we don't actually verify, just check if tokens match const isValid = idHeader === webhookId && tokenHeader === webhookToken; if (!isValid) { return { isValid: false, error: 'Invalid webhook ID or token', platform: 'custom', }; } const rawBody = await request.text(); let payload; try { payload = JSON.parse(rawBody); } catch (e) { payload = rawBody; } return { isValid: true, platform: 'custom', payload, metadata: { id: idHeader, algorithm: 'token-based', }, }; } catch (error) { return { isValid: false, error: `Token-based verification error: ${error.message}`, platform: 'custom', }; } } } exports.WebhookVerificationService = WebhookVerificationService; __exportStar(require("./types"), exports); var algorithms_3 = require("./platforms/algorithms"); Object.defineProperty(exports, "getPlatformAlgorithmConfig", { enumerable: true, get: function () { return algorithms_3.getPlatformAlgorithmConfig; } }); Object.defineProperty(exports, "platformUsesAlgorithm", { enumerable: true, get: function () { return algorithms_3.platformUsesAlgorithm; } }); Object.defineProperty(exports, "getPlatformsUsingAlgorithm", { enumerable: true, get: function () { return algorithms_3.getPlatformsUsingAlgorithm; } }); Object.defineProperty(exports, "validateSignatureConfig", { enumerable: true, get: function () { return algorithms_3.validateSignatureConfig; } }); var algorithms_4 = require("./verifiers/algorithms"); Object.defineProperty(exports, "createAlgorithmVerifier", { enumerable: true, get: function () { return algorithms_4.createAlgorithmVerifier; } }); var custom_algorithms_2 = require("./verifiers/custom-algorithms"); Object.defineProperty(exports, "createCustomVerifier", { enumerable: true, get: function () { return custom_algorithms_2.createCustomVerifier; } }); exports.default = WebhookVerificationService;