UNPKG

guardz-event

Version:

Type-safe event handling with runtime validation using guardz for unsafe data from 3rd parties

156 lines 5.62 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.safePostMessageListener = safePostMessageListener; const guardz_1 = require("guardz"); const Status_1 = require("../../domain/event/Status"); /** * Safe PostMessage event listener with callback-based API * Usage: window.addEventListener('message', safePostMessageListener(isUserMessage, { tolerance: true, onTypeMismatch: console.warn })); */ function safePostMessageListener(guard, config) { return (event) => { // Handle null/undefined events if (!event) { if (config.onError) { config.onError('Invalid event: Event is null or undefined', { type: 'unknown', eventType: 'message' }); } return; } // Check for security violations first if (config.allowedOrigins && !config.allowedOrigins.includes(event.origin)) { const errorMessage = `PostMessage origin not allowed: ${event.origin}`; if (config.onSecurityViolation) { config.onSecurityViolation(event.origin, errorMessage); } else if (config.onError) { config.onError(errorMessage, { type: 'security', eventType: 'message', origin: event.origin }); } return; } const result = executePostMessageValidation(event, { guard, tolerance: config.tolerance, allowedOrigins: config.allowedOrigins, allowedSources: config.allowedSources, onError: (error, context) => { // In tolerance mode, call onTypeMismatch for validation errors if (config.tolerance && context.type === 'validation' && config.onTypeMismatch) { config.onTypeMismatch(error); } else if (config.onError) { config.onError(error, context); } } }); if (result.status === Status_1.Status.SUCCESS) { config.onSuccess(result.data); } else { if (result.code === 500 && config.onTypeMismatch) { config.onTypeMismatch(result.message); } else if (config.onError) { config.onError(result); } } }; } /** * Execute PostMessage validation with the given configuration */ function executePostMessageValidation(event, config) { try { // Security validation if (config.allowedOrigins && !config.allowedOrigins.includes(event.origin)) { const error = { code: 'SECURITY_ERROR', message: `PostMessage origin not allowed: ${event.origin}`, origin: event.origin }; if (config.onError) { config.onError(error.message, { type: 'security', eventType: 'message', origin: event.origin }); } return { status: Status_1.Status.ERROR, code: 403, message: error.message }; } // Extract data from PostMessage const data = event.data; // Validate event structure if (config.validateEvent && (typeof data === 'undefined' || data === null)) { const errorMessage = 'PostMessage event has no data'; if (config.onError) { config.onError(errorMessage, { type: 'validation', eventType: 'message' }); } return { status: Status_1.Status.ERROR, code: 400, message: errorMessage }; } // Type validation const validationResult = config.tolerance ? (0, guardz_1.guardWithTolerance)(data, config.guard, { identifier: config.identifier || 'PostMessage data', callbackOnError: (error) => { if (config.onError) { config.onError(error, { type: 'validation', eventType: 'message' }); } } }) : config.guard(data); if (!validationResult) { const errorMessage = `PostMessage data validation failed: ${config.identifier || 'PostMessage data'}`; if (config.onError) { config.onError(errorMessage, { type: 'validation', eventType: 'message' }); } return { status: Status_1.Status.ERROR, code: 500, message: errorMessage }; } return { status: Status_1.Status.SUCCESS, data: data }; } catch (error) { const errorMessage = `PostMessage validation error: ${error instanceof Error ? error.message : 'Unknown error'}`; if (config.onError) { config.onError(errorMessage, { type: 'unknown', eventType: 'message', originalError: error }); } return { status: Status_1.Status.ERROR, code: 500, message: errorMessage }; } } //# sourceMappingURL=PostMessageListener.js.map