Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 30x 30x 30x 30x 30x 30x 30x 30x 30x 30x 30x 30x 30x 21x 21x 2x 2x 2x 19x 19x 19x 19x 21x 1x 1x 1x 18x 18x 18x 18x 18x 17x 16x 21x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 11x 11x 11x 11x 11x 10x 9x 21x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 21x 30x 30x 30x 30x 30x 30x 5x 5x 1x 1x 1x 1x 4x 4x 5x 5x 30x 30x 30x 30x 1x 1x 1x 1x 1x 59x 24x 24x 24x 59x 23x 23x 23x 59x | /**
* Modal iframe monitoring utilities
*/
import type { ThreeDSAuthResult } from '../types';
import { SDKError } from '../types';
import { CF_3DS_AUTH_COMPLETE, CF_AUTH_ERROR } from '../constants';
export interface MonitoringCallbacks {
onComplete?: (result: ThreeDSAuthResult) => void;
onError?: (error: Error) => void;
onClose?: (result: ThreeDSAuthResult) => void;
isStillActive: () => boolean;
log?: (message: string, ...args: unknown[]) => void;
}
export interface MonitoringHandlers {
messageHandler: ((event: MessageEvent) => void) | null;
timeoutId: NodeJS.Timeout | null;
}
/**
* Sets up postMessage listener for iframe communication
*/
export function setupIframeMonitoring(
iframeElement: HTMLIFrameElement,
timeout: number,
callbacks: MonitoringCallbacks
): MonitoringHandlers {
const handlers: MonitoringHandlers = {
messageHandler: null,
timeoutId: null,
};
callbacks.log?.('Setting up postMessage listener for iframe communication');
// Set up postMessage listener
handlers.messageHandler = (event: MessageEvent): void => {
// Check if this modal is still active before processing messages
if (!callbacks.isStillActive()) {
callbacks.log?.('Received message but modal is no longer active, ignoring');
return;
}
// Verify message is from our iframe (security check)
// For cross-origin 3DS providers, we can't always verify the source
// In production, you might want to add origin validation
if (event.source !== iframeElement.contentWindow) {
callbacks.log?.('Received message from unknown source, ignoring');
return;
}
// Check if message is an error message
if (
event.data &&
typeof event.data === 'object' &&
'type' in event.data &&
(event.data as { type: string }).type === CF_AUTH_ERROR
) {
const errorData = event.data as {
type: string;
respMsg?: string;
description?: string;
data?: unknown;
};
callbacks.log?.('Received auth error message from iframe', errorData);
// Double-check we're still active before processing
if (!callbacks.isStillActive()) {
callbacks.log?.('Modal no longer active, ignoring error message');
return;
}
// Clean up
cleanupMonitoring(handlers);
// Create error and call onError callback
const errorMessage =
errorData.respMsg || errorData.description || 'Authentication error occurred';
const error = new SDKError(errorMessage, 'AUTH_ERROR', errorData.data);
callbacks.onError?.(error);
// Close modal with error result
callbacks.onClose?.({
success: false,
error: errorMessage,
data: errorData as Record<string, unknown>,
});
return;
}
// Check if message is a 3DS completion message
if (
event.data &&
typeof event.data === 'object' &&
'type' in event.data &&
(event.data as { type: string }).type === CF_3DS_AUTH_COMPLETE
) {
const completionData = event.data as {
type: string;
statusCode?: number;
[key: string]: unknown;
};
callbacks.log?.('Received 3DS completion message from iframe', completionData);
// Double-check we're still active before processing
if (!callbacks.isStillActive()) {
callbacks.log?.('Modal no longer active, ignoring completion message');
return;
}
// Remove type property for data
const { type: _, ...resultData } = completionData;
// Clean up
cleanupMonitoring(handlers);
// Close modal with result
const success = completionData.statusCode == 200 || completionData.statusCode == 201;
callbacks.onClose?.({
success: success,
data: resultData as Record<string, unknown>,
});
}
};
// Add event listener
window.addEventListener('message', handlers.messageHandler);
// Set up timeout fallback
handlers.timeoutId = setTimeout(() => {
// Check if this modal is still active before processing timeout
if (!callbacks.isStillActive()) {
callbacks.log?.('Timeout reached but modal is no longer active, ignoring');
cleanupMonitoring(handlers);
return;
}
callbacks.log?.('Timeout reached, closing modal');
cleanupMonitoring(handlers);
callbacks.onClose?.({ success: false, error: 'Authentication timeout' });
}, timeout);
return handlers;
}
/**
* Cleans up monitoring resources
*/
export function cleanupMonitoring(handlers: MonitoringHandlers): void {
if (handlers.messageHandler) {
window.removeEventListener('message', handlers.messageHandler);
handlers.messageHandler = null;
}
if (handlers.timeoutId) {
clearTimeout(handlers.timeoutId);
handlers.timeoutId = null;
}
}
|