From 762b9bad5563a925f0c9d738dce690cf8efac5b7 Mon Sep 17 00:00:00 2001 From: Antariksh Mahajan Date: Mon, 23 Sep 2024 16:19:57 +0800 Subject: [PATCH 1/2] feat: update iframe parent on form submission --- .../public-form/PublicFormProvider.tsx | 7 ++++++ .../public-form/utils/iframeMessaging.ts | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 frontend/src/features/public-form/utils/iframeMessaging.ts diff --git a/frontend/src/features/public-form/PublicFormProvider.tsx b/frontend/src/features/public-form/PublicFormProvider.tsx index d920c9447e..ecbbb21866 100644 --- a/frontend/src/features/public-form/PublicFormProvider.tsx +++ b/frontend/src/features/public-form/PublicFormProvider.tsx @@ -67,6 +67,7 @@ import { import { FormNotFound } from './components/FormNotFound' import { decryptAttachment, decryptSubmission } from './utils/decryptSubmission' +import { postIFrameMessage } from './utils/iframeMessaging' import { usePublicAuthMutations, usePublicFormMutations } from './mutations' import { PublicFormContext, SubmissionData } from './PublicFormContext' import { useEncryptedSubmission, usePublicFormView } from './queries' @@ -584,6 +585,8 @@ export const PublicFormProvider = ({ } } + postIFrameMessage({ state: 'submitting' }) + switch (form.responseMode) { case FormResponseMode.Email: { // Using mutateAsync so react-hook-form goes into loading state. @@ -717,6 +720,7 @@ export const PublicFormProvider = ({ paymentData, }) => { trackSubmitForm(form) + postIFrameMessage({ state: 'submitted', submissionId }) if (paymentData) { navigate(getPaymentPageUrl(formId, paymentData.paymentId)) @@ -739,6 +743,7 @@ export const PublicFormProvider = ({ }, ) .catch(async (error) => { + postIFrameMessage({ state: 'submitError' }) datadogLogs.logger.warn(`handleSubmitForm: ${error.message}`, { meta: { ...logMeta, @@ -781,6 +786,7 @@ export const PublicFormProvider = ({ paymentData, }) => { trackSubmitForm(form) + postIFrameMessage({ state: 'submitted', submissionId }) if (paymentData) { navigate(getPaymentPageUrl(formId, paymentData.paymentId)) storePaymentMemory(paymentData.paymentId) @@ -802,6 +808,7 @@ export const PublicFormProvider = ({ }, ) .catch(async (error) => { + postIFrameMessage({ state: 'submitError' }) // TODO(#5826): Remove when we have resolved the Network Error datadogLogs.logger.warn( `handleSubmitForm: submit with virus scan`, diff --git a/frontend/src/features/public-form/utils/iframeMessaging.ts b/frontend/src/features/public-form/utils/iframeMessaging.ts new file mode 100644 index 0000000000..1b4e9c7ef1 --- /dev/null +++ b/frontend/src/features/public-form/utils/iframeMessaging.ts @@ -0,0 +1,23 @@ +export type PublicFormIFrameMessage = + | { state: 'submitting' | 'submitError' } + | { state: 'submitted'; submissionId: string } + +const TRUSTED_TARGET_ORIGINS = [ + 'https://pay.gov.sg', + 'https://exp.pay.gov.sg', + 'https://staging.pay.gov.sg', +].concat( + process.env.NODE_ENV === 'development' ? ['http://localhost:3000'] : [], +) + +export const postIFrameMessage = (message: PublicFormIFrameMessage): void => { + // De-risk by wrapping in try-catch even though this is synchronous. This should + // never block form submission. + try { + TRUSTED_TARGET_ORIGINS.forEach((origin) => { + window.parent.postMessage(message, origin) + }) + } catch (error) { + console.warn('Error while posting form state to iframe parent', error) + } +} From 31c7eb51f167102d155056e5181e59510a550f66 Mon Sep 17 00:00:00 2001 From: Antariksh Mahajan Date: Sat, 12 Oct 2024 16:08:23 +0800 Subject: [PATCH 2/2] fix: remove localhost from trusted origins --- frontend/src/features/public-form/utils/iframeMessaging.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/features/public-form/utils/iframeMessaging.ts b/frontend/src/features/public-form/utils/iframeMessaging.ts index 1b4e9c7ef1..199ccf8f19 100644 --- a/frontend/src/features/public-form/utils/iframeMessaging.ts +++ b/frontend/src/features/public-form/utils/iframeMessaging.ts @@ -6,9 +6,7 @@ const TRUSTED_TARGET_ORIGINS = [ 'https://pay.gov.sg', 'https://exp.pay.gov.sg', 'https://staging.pay.gov.sg', -].concat( - process.env.NODE_ENV === 'development' ? ['http://localhost:3000'] : [], -) +] export const postIFrameMessage = (message: PublicFormIFrameMessage): void => { // De-risk by wrapping in try-catch even though this is synchronous. This should