-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: sends modal event data to modal wrapper for use in hooks #1170
base: feature/DTCRCMERC-3611-modal-lander-v6
Are you sure you want to change the base?
Changes from all commits
f40050f
abfb667
58abf9c
3283443
e91a56d
71b7c29
4551ab3
5593c7b
f0a7ea8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
import { uniqueID } from '@krakenjs/belter/src'; | ||
|
||
// these constants are defined in PostMessenger | ||
const POSTMESSENGER_EVENT_TYPES = { | ||
ACK: 'ack', | ||
MESSAGE: 'message' | ||
}; | ||
const POSTMESSENGER_ACK_PAYLOAD = { | ||
ok: 'true' | ||
}; | ||
|
||
export const POSTMESSENGER_EVENT_NAMES = { | ||
CALCULATE: 'paypal-messages-modal-calculate', | ||
CLOSE: 'paypal-messages-modal-close', | ||
SHOW: 'paypal-messages-modal-show' | ||
}; | ||
|
||
export function sendEvent(payload, trustedOrigin) { | ||
if (!trustedOrigin && !document.referrer) { | ||
return; | ||
} | ||
|
||
const isTest = process.env.NODE_ENV === 'test'; | ||
const targetWindow = !isTest && window.parent === window ? window.opener : window.parent; | ||
|
||
// referrer origin is used by integrations not passing in props.origin manually | ||
// eslint-disable-next-line compat/compat | ||
const referrerOrigin = !isTest ? new window.URL(document.referrer)?.origin : undefined; | ||
|
||
targetWindow.postMessage(payload, trustedOrigin || referrerOrigin); | ||
} | ||
|
||
// This function provides data security by preventing accidentally exposing sensitive data; we are adding | ||
// an extra layer of validation here by only allowing explicitly approved fields to be included | ||
function createSafePayload(unscreenedPayload) { | ||
const allowedFields = [ | ||
'linkName' // close event | ||
]; | ||
|
||
const safePayload = {}; | ||
const entries = Object.entries(unscreenedPayload); | ||
entries.forEach(entry => { | ||
const [key, value] = entry; | ||
if (allowedFields.includes(key)) { | ||
safePayload[key] = value; | ||
} | ||
}); | ||
|
||
return safePayload; | ||
} | ||
|
||
export function createPostMessengerEvent(typeArg, eventName, eventPayloadArg) { | ||
let type; | ||
let eventPayload; | ||
|
||
if (typeArg === 'ack') { | ||
type = POSTMESSENGER_EVENT_TYPES.ACK; | ||
eventPayload = POSTMESSENGER_ACK_PAYLOAD; | ||
} else if (typeArg === 'message') { | ||
type = POSTMESSENGER_EVENT_TYPES.MESSAGE; | ||
// createSafePayload | ||
eventPayload = createSafePayload(eventPayloadArg); | ||
} | ||
|
||
return { | ||
eventName, | ||
id: uniqueID(), | ||
type, | ||
eventPayload | ||
}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,12 @@ | ||
/* global Android */ | ||
import { isAndroidWebview, isIosWebview, getPerformance } from '@krakenjs/belter/src'; | ||
import { getOrCreateDeviceID, logger } from '../../../../utils'; | ||
import { isIframe, validateProps, sendEventAck } from './utils'; | ||
import { validateProps } from './utils'; | ||
import { sendEvent, createPostMessengerEvent, POSTMESSENGER_EVENT_NAMES } from './postMessage'; | ||
|
||
const IOS_INTERFACE_NAME = 'paypalMessageModalCallbackHandler'; | ||
const ANDROID_INTERFACE_NAME = 'paypalMessageModalCallbackHandler'; | ||
// these constants should maintain parity with MESSAGE_MODAL_EVENT_NAMES in core-web-sdk | ||
|
||
function updateProps(newProps, propListeners) { | ||
Array.from(propListeners.values()).forEach(listener => { | ||
|
@@ -13,16 +15,15 @@ function updateProps(newProps, propListeners) { | |
Object.assign(window.xprops, newProps); | ||
} | ||
|
||
export function handleBrowserEvents(initialProps, propListeners, updatedPropsEvent) { | ||
export function handleBrowserEvents(clientOrigin, propListeners, updatedPropsEvent) { | ||
const { | ||
origin: eventOrigin, | ||
data: { eventName, id, eventPayload: newProps } | ||
} = updatedPropsEvent; | ||
const clientOrigin = decodeURIComponent(initialProps.origin); | ||
|
||
if (eventOrigin === clientOrigin && eventName === 'PROPS_UPDATE' && newProps && typeof newProps === 'object') { | ||
// send event ack so PostMessenger will stop reposting event | ||
sendEventAck(id, clientOrigin); | ||
// send event ack with original event id so PostMessenger will stop reposting event | ||
sendEvent(createPostMessengerEvent('ack', id), clientOrigin); | ||
const validProps = validateProps(newProps); | ||
updateProps(validProps, propListeners); | ||
} | ||
|
@@ -43,11 +44,12 @@ const getAccount = (merchantId, clientId, payerId) => { | |
|
||
const setupBrowser = props => { | ||
const propListeners = new Set(); | ||
const clientOrigin = decodeURIComponent(props.origin); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we able to test if |
||
|
||
window.addEventListener( | ||
'message', | ||
event => { | ||
handleBrowserEvents(props, propListeners, event); | ||
handleBrowserEvents(clientOrigin, propListeners, event); | ||
}, | ||
false | ||
); | ||
|
@@ -110,6 +112,13 @@ const setupBrowser = props => { | |
}); | ||
}, | ||
onCalculate: ({ value }) => { | ||
const eventPayload = { | ||
// for data security, also add new params to createSafePayload in ./postMessage.js | ||
}; | ||
Comment on lines
+115
to
+117
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we just make the |
||
sendEvent( | ||
createPostMessengerEvent('message', POSTMESSENGER_EVENT_NAMES.CALCULATE, eventPayload), | ||
clientOrigin | ||
); | ||
logger.track({ | ||
index: '1', | ||
et: 'CLICK', | ||
|
@@ -120,6 +129,10 @@ const setupBrowser = props => { | |
}); | ||
}, | ||
onShow: () => { | ||
const eventPayload = { | ||
// for data security, also add new params to createSafePayload in ./postMessage.js | ||
}; | ||
sendEvent(createPostMessengerEvent('message', POSTMESSENGER_EVENT_NAMES.SHOW, eventPayload), clientOrigin); | ||
logger.track({ | ||
index: '1', | ||
et: 'CLIENT_IMPRESSION', | ||
|
@@ -128,10 +141,11 @@ const setupBrowser = props => { | |
}); | ||
}, | ||
onClose: ({ linkName }) => { | ||
if (isIframe && document.referrer) { | ||
const targetOrigin = new window.URL(document.referrer).origin; | ||
Seavenly marked this conversation as resolved.
Show resolved
Hide resolved
|
||
window.parent.postMessage('paypal-messages-modal-close', targetOrigin); | ||
} | ||
const eventPayload = { | ||
linkName | ||
// for data security, also add new params to createSafePayload in ./postMessage.js | ||
}; | ||
sendEvent(createPostMessengerEvent('message', POSTMESSENGER_EVENT_NAMES.CLOSE, eventPayload), clientOrigin); | ||
logger.track({ | ||
index: '1', | ||
et: 'CLICK', | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In order to help us debug this in the future when we inevitably forget this filter exists, should we add an
else
that includes a simple console warn or something to help point this out?