guardz-event
Version:
Type-safe event handling with runtime validation using guardz for unsafe data from 3rd parties
156 lines • 5.62 kB
JavaScript
;
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