UNPKG

hook-engine

Version:

Production-grade webhook engine with comprehensive adapter support, security, reliability, structured logging, and CLI tools.

334 lines (333 loc) 12.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.microservicesSecurityConfig = exports.apiGatewaySecurityConfig = exports.highSecurityConfig = exports.productionSecurityConfig = exports.developmentSecurityConfig = void 0; exports.getSecurityConfigByEnvironment = getSecurityConfigByEnvironment; exports.mergeSecurityConfigs = mergeSecurityConfigs; /** * Basic security configuration for development environments */ exports.developmentSecurityConfig = { rateLimiting: { windowMs: 60000, // 1 minute maxRequests: 1000, // High limit for development skipSuccessfulRequests: false, skipFailedRequests: false }, requestValidation: { enableSignatureValidation: false, // Disabled for easier testing enablePayloadValidation: true, enableHeaderValidation: true, enableTimestampValidation: false, timestampToleranceMs: 300000, // 5 minutes maxPayloadSize: 10 * 1024 * 1024, // 10MB requiredHeaders: ['content-type'], allowedContentTypes: ['application/json', 'application/x-www-form-urlencoded', 'text/plain'] }, ipAllowlist: { enabled: false, // Disabled for development allowedIPs: [], allowedRanges: [], denyByDefault: false, trustedProxies: ['127.0.0.1', '::1'] }, requestSizeLimit: 10 * 1024 * 1024, // 10MB timeoutMs: 30000, // 30 seconds enableCORS: true, corsOptions: { origin: true, // Allow all origins in development methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'], credentials: true, maxAge: 86400 } }; /** * Production security configuration with strict policies */ exports.productionSecurityConfig = { rateLimiting: { windowMs: 60000, // 1 minute maxRequests: 100, // Strict limit for production skipSuccessfulRequests: false, skipFailedRequests: false, keyGenerator: (req) => { // Use IP + User-Agent for more specific rate limiting const ip = req.ip || req.connection?.remoteAddress || 'unknown'; const userAgent = req.headers['user-agent'] || 'unknown'; return `${ip}:${userAgent}`; } }, requestValidation: { enableSignatureValidation: true, enablePayloadValidation: true, enableHeaderValidation: true, enableTimestampValidation: true, timestampToleranceMs: 60000, // 1 minute tolerance maxPayloadSize: 1024 * 1024, // 1MB requiredHeaders: ['content-type', 'x-signature', 'x-timestamp'], allowedContentTypes: ['application/json'] }, ipAllowlist: { enabled: true, allowedIPs: [], // Configure based on your webhook sources allowedRanges: [], // Configure CIDR ranges denyByDefault: true, trustedProxies: [], // Configure your load balancer IPs enableGeoBlocking: true, blockedCountries: ['CN', 'RU'] // Example blocked countries }, requestSizeLimit: 1024 * 1024, // 1MB timeoutMs: 10000, // 10 seconds enableCORS: false, // Disabled for webhooks enableCSRF: true, csrfOptions: { enabled: true, secret: process.env.CSRF_SECRET || 'your-csrf-secret', cookieName: '_csrf', headerName: 'x-csrf-token', ignoreMethods: ['GET', 'HEAD', 'OPTIONS'] }, enableEncryption: true, encryptionOptions: { algorithm: 'aes-256-gcm', keyDerivation: 'pbkdf2', keyLength: 32, ivLength: 16, saltLength: 32, iterations: 100000 } }; /** * High-security configuration for sensitive environments */ exports.highSecurityConfig = { rateLimiting: { windowMs: 60000, // 1 minute maxRequests: 50, // Very strict limit skipSuccessfulRequests: false, skipFailedRequests: false, keyGenerator: (req) => { // Multi-factor rate limiting key const ip = req.ip || 'unknown'; const userAgent = req.headers['user-agent'] || 'unknown'; const source = req.headers['x-webhook-source'] || 'unknown'; return `${ip}:${userAgent}:${source}`; } }, requestValidation: { enableSignatureValidation: true, enablePayloadValidation: true, enableHeaderValidation: true, enableTimestampValidation: true, timestampToleranceMs: 30000, // 30 seconds tolerance maxPayloadSize: 512 * 1024, // 512KB requiredHeaders: [ 'content-type', 'x-signature', 'x-timestamp', 'x-webhook-source', 'authorization' ], allowedContentTypes: ['application/json'], customValidators: [ { name: 'signature-strength', validate: (req) => { const signature = req.headers['x-signature']; if (!signature || signature.length < 64) { return { isValid: false, errors: ['Signature too weak'] }; } return { isValid: true, errors: [] }; }, required: true, errorMessage: 'Strong signature required' }, { name: 'source-validation', validate: (req) => { const source = req.headers['x-webhook-source']; const allowedSources = ['github', 'stripe', 'shopify']; if (!source || !allowedSources.includes(source)) { return { isValid: false, errors: ['Invalid webhook source'] }; } return { isValid: true, errors: [] }; }, required: true, errorMessage: 'Valid webhook source required' } ] }, ipAllowlist: { enabled: true, allowedIPs: [], // Strict allowlist only allowedRanges: [], // Specific CIDR ranges only denyByDefault: true, trustedProxies: [], // Only specific proxy IPs enableGeoBlocking: true, blockedCountries: ['CN', 'RU', 'KP', 'IR'] // Extended blocked list }, requestSizeLimit: 512 * 1024, // 512KB timeoutMs: 5000, // 5 seconds enableCORS: false, enableCSRF: true, csrfOptions: { enabled: true, secret: process.env.CSRF_SECRET || 'your-strong-csrf-secret', cookieName: '_csrf_token', headerName: 'x-csrf-token', ignoreMethods: [] }, enableEncryption: true, encryptionOptions: { algorithm: 'aes-256-gcm', keyDerivation: 'argon2', keyLength: 32, ivLength: 16, saltLength: 32, cost: 16, blockSize: 8, parallelization: 1 } }; /** * API Gateway security configuration */ exports.apiGatewaySecurityConfig = { rateLimiting: { windowMs: 60000, // 1 minute maxRequests: 200, skipSuccessfulRequests: true, // Don't count successful requests skipFailedRequests: false, keyGenerator: (req) => { // Use API key for rate limiting const apiKey = req.headers['x-api-key'] || req.headers['authorization']; const ip = req.ip || 'unknown'; return apiKey ? `api:${apiKey}` : `ip:${ip}`; } }, requestValidation: { enableSignatureValidation: true, enablePayloadValidation: true, enableHeaderValidation: true, enableTimestampValidation: true, timestampToleranceMs: 120000, // 2 minutes maxPayloadSize: 2 * 1024 * 1024, // 2MB requiredHeaders: ['content-type', 'x-api-key'], allowedContentTypes: ['application/json', 'application/xml'] }, ipAllowlist: { enabled: false, // Rely on API key authentication allowedIPs: [], allowedRanges: [], denyByDefault: false, trustedProxies: ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'] }, requestSizeLimit: 2 * 1024 * 1024, // 2MB timeoutMs: 15000, // 15 seconds enableCORS: true, corsOptions: { origin: ['https://api.example.com', 'https://dashboard.example.com'], methods: ['POST', 'PUT'], allowedHeaders: ['Content-Type', 'X-API-Key', 'Authorization'], credentials: false, maxAge: 3600 } }; /** * Microservices security configuration */ exports.microservicesSecurityConfig = { rateLimiting: { windowMs: 60000, // 1 minute maxRequests: 500, // Higher limit for internal services skipSuccessfulRequests: true, skipFailedRequests: false, keyGenerator: (req) => { // Use service name for rate limiting const serviceName = req.headers['x-service-name'] || 'unknown'; const ip = req.ip || 'unknown'; return `service:${serviceName}:${ip}`; } }, requestValidation: { enableSignatureValidation: true, enablePayloadValidation: true, enableHeaderValidation: true, enableTimestampValidation: false, // Relaxed for internal services timestampToleranceMs: 300000, // 5 minutes maxPayloadSize: 5 * 1024 * 1024, // 5MB requiredHeaders: ['content-type', 'x-service-name', 'x-service-token'], allowedContentTypes: ['application/json', 'application/protobuf'] }, ipAllowlist: { enabled: true, allowedIPs: [], allowedRanges: [ '10.0.0.0/8', // Private network '172.16.0.0/12', // Private network '192.168.0.0/16' // Private network ], denyByDefault: true, trustedProxies: ['10.0.0.0/8'] }, requestSizeLimit: 5 * 1024 * 1024, // 5MB timeoutMs: 20000, // 20 seconds enableCORS: false, // Not needed for internal services enableEncryption: true, encryptionOptions: { algorithm: 'aes-256-gcm', keyDerivation: 'pbkdf2', keyLength: 32, ivLength: 16, saltLength: 32, iterations: 50000 } }; /** * Get security configuration by environment */ function getSecurityConfigByEnvironment(env) { switch (env.toLowerCase()) { case 'development': case 'dev': return exports.developmentSecurityConfig; case 'production': case 'prod': return exports.productionSecurityConfig; case 'staging': case 'stage': return { ...exports.productionSecurityConfig, rateLimiting: { ...exports.productionSecurityConfig.rateLimiting, maxRequests: 200 } }; case 'high-security': case 'secure': return exports.highSecurityConfig; case 'api-gateway': case 'gateway': return exports.apiGatewaySecurityConfig; case 'microservices': case 'internal': return exports.microservicesSecurityConfig; default: return exports.developmentSecurityConfig; } } /** * Merge security configurations */ function mergeSecurityConfigs(base, override) { return { ...base, ...override, rateLimiting: { ...base.rateLimiting, ...override.rateLimiting }, requestValidation: { ...base.requestValidation, ...override.requestValidation }, ipAllowlist: { ...base.ipAllowlist, ...override.ipAllowlist }, corsOptions: base.corsOptions && override.corsOptions ? { ...base.corsOptions, ...override.corsOptions } : override.corsOptions || base.corsOptions, csrfOptions: base.csrfOptions && override.csrfOptions ? { ...base.csrfOptions, ...override.csrfOptions } : override.csrfOptions || base.csrfOptions, encryptionOptions: base.encryptionOptions && override.encryptionOptions ? { ...base.encryptionOptions, ...override.encryptionOptions } : override.encryptionOptions || base.encryptionOptions }; }