From f85c7a89b354a79ba67aec49ee9c98b411183277 Mon Sep 17 00:00:00 2001 From: Shane Logsdon Date: Fri, 8 Aug 2025 12:09:49 -0400 Subject: [PATCH 1/2] bring back optional origin check; also allow multiple origins --- packages/globalpayments-3ds/src/interfaces.ts | 4 ++-- packages/globalpayments-3ds/src/lib/post-to-iframe.ts | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/globalpayments-3ds/src/interfaces.ts b/packages/globalpayments-3ds/src/interfaces.ts index e510a99..81e6e8f 100644 --- a/packages/globalpayments-3ds/src/interfaces.ts +++ b/packages/globalpayments-3ds/src/interfaces.ts @@ -56,7 +56,7 @@ export interface IChallengeWindowOptions { displayMode?: DisplayModeType; encodedChallengeRequest?: string; hide?: boolean; - origin?: string; + origin?: string | string[]; requestUrl?: string; response?: IMessageEventData; target?: string | Element; @@ -76,7 +76,7 @@ export interface ICreditCardData { export interface IIframeData { iframe?: Element; - origin?: string; + origin?: string | string[]; timeout?: number; } diff --git a/packages/globalpayments-3ds/src/lib/post-to-iframe.ts b/packages/globalpayments-3ds/src/lib/post-to-iframe.ts index 294c852..1426ed1 100644 --- a/packages/globalpayments-3ds/src/lib/post-to-iframe.ts +++ b/packages/globalpayments-3ds/src/lib/post-to-iframe.ts @@ -113,6 +113,15 @@ function getWindowMessageEventHandler( return; } + if (data.origin) { + const allowedOrigins = Array.isArray(data.origin) ? data.origin : [data.origin]; + // include some defaults from Global Payments' sandbox + allowedOrigins.push(...['https://api.sandbox.globalpay-ecommerce.com']); + if (!allowedOrigins.includes(e.origin)) { + return; + } + } + ensureIframeClosed(data.timeout || 0); resolve(e.data); }; From d798adaede4c3475d75d802cba39df03332c50f3 Mon Sep 17 00:00:00 2001 From: Shane Logsdon Date: Fri, 8 Aug 2025 12:10:10 -0400 Subject: [PATCH 2/2] ensure ACS url is correctly formed --- packages/globalpayments-3ds/src/index.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/globalpayments-3ds/src/index.ts b/packages/globalpayments-3ds/src/index.ts index d0bcb8b..8900c4b 100644 --- a/packages/globalpayments-3ds/src/index.ts +++ b/packages/globalpayments-3ds/src/index.ts @@ -180,8 +180,17 @@ export async function handleInitiateAuthentication( throw new Error("Invalid challenge state. Missing challenge URL"); } + // Browsers can sometimes malform the URL's query string parameters, + // turning `&` into `&` which messes up the query string parameter + // and causes the challenge page to load incorrectly. + // + // We use the textarea element as a way to decode the HTML entities + // and grab the expected text/URL. + var url = document.createElement("textarea"); + url.innerHTML = data.challenge.requestUrl; + const response = await postToIframe( - data.challenge.requestUrl, + url.value, [ { name: "creq", value: data.challenge.encodedChallengeRequest }, // TODO: support session data