From 517be7bac2f5d2f80a9b2c1957011833d5649f8a Mon Sep 17 00:00:00 2001 From: cdibble Date: Fri, 17 Nov 2023 10:25:27 -0800 Subject: [PATCH 01/21] started test driving data collector util --- jest.config.js | 3 ++ src/data-collector.js | 10 +++++++ test/server/data-collector.test.js | 46 ++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 jest.config.js create mode 100644 src/data-collector.js create mode 100644 test/server/data-collector.test.js diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000..50ca2ff3 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + testEnvironment: "jsdom", +}; diff --git a/src/data-collector.js b/src/data-collector.js new file mode 100644 index 00000000..723b7d97 --- /dev/null +++ b/src/data-collector.js @@ -0,0 +1,10 @@ +export const FRAUDNET_FNCLS = "fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99"; +export const FRAUDNET_APP_NAME = "SMART_PAYMENT_BUTTONS"; + +export const loadDataCollector = async (options) => { + const configScript = document.createElement("script"); + configScript.setAttribute("nonce", options.cspNonce); + configScript.setAttribute("type", "application/json"); + configScript.setAttribute("id", "fconfig"); + configScript.setAttribute("fncls", FRAUDNET_FNCLS); +}; diff --git a/test/server/data-collector.test.js b/test/server/data-collector.test.js new file mode 100644 index 00000000..f74c75c4 --- /dev/null +++ b/test/server/data-collector.test.js @@ -0,0 +1,46 @@ +/** + * @jest-environment jsdom + */ +import { + loadDataCollector, + FRAUDNET_FNCLS, + FRAUDNET_APP_NAME, +} from "../../src/data-collector"; + +describe.only("data-collector.js", () => { + test("it create the config element with correct inputs", async () => { + const mockSetAttribute = jest.fn(); + const mockReturnedElement = { + setAttribute: mockSetAttribute, + }; + document.createElement = jest.fn(() => { + return mockReturnedElement; + }); + const inputs = { + clientMetadataId: "some-cmid", + fraudnetAppName: "spb-test-name", + env: "unit-tests", + cspNonce: "not-sure-what-this-is-yet-csp-nonce", + queryStringParams: { + /* TBD */ + }, + }; + + const expectedScriptConfig = { + f: inputs.clientMetadataId, + s: FRAUDNET_APP_NAME, + //u: + cb1: "fnCallback", + }; + await loadDataCollector(inputs); + // assert script created with certain attributes + expect(document.createElement).toBeCalledWith("script"); + expect(mockSetAttribute).toBeCalledWith("nonce", inputs.cspNonce); + expect(mockSetAttribute).toBeCalledWith("type", "application/json"); + expect(mockSetAttribute).toBeCalledWith("id", "fconfig"); + expect(mockSetAttribute).toBeCalledWith("fncls", FRAUDNET_FNCLS); + expect(mockReturnedElement.textContent).toEqual( + JSON.stringify({ expectedScriptConfig }) + ); + }); +}); From 0abf2a701668406941f7100745c48a6d89f009d1 Mon Sep 17 00:00:00 2001 From: cdibble Date: Fri, 17 Nov 2023 16:18:32 -0800 Subject: [PATCH 02/21] add tests and todos, break fns down a bit --- src/data-collector.js | 51 +++++++++++++++++++- test/server/data-collector.test.js | 74 +++++++++++++++++++++++------- 2 files changed, 107 insertions(+), 18 deletions(-) diff --git a/src/data-collector.js b/src/data-collector.js index 723b7d97..433f00d2 100644 --- a/src/data-collector.js +++ b/src/data-collector.js @@ -1,10 +1,57 @@ +/* @flow */ + +// import { ENV } from '@paypal/sdk-constants/src'; + export const FRAUDNET_FNCLS = "fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99"; export const FRAUDNET_APP_NAME = "SMART_PAYMENT_BUTTONS"; -export const loadDataCollector = async (options) => { +// const FRAUDNET_URL = { +// [ENV.LOCAL]: "https://www.msmaster.qa.paypal.com/en_US/m/fb-raw.js", +// [ENV.STAGE]: "https://stage2mb044.qa.paypal.com/fraudnetjsnodeweb/automate/develop/stage_raw.js", +// [ENV.SANDBOX]: "https://c.paypal.com/da/r/fb.js", +// [ENV.PRODUCTION]: "https://c.paypal.com/da/r/fb.js", +// [ENV.TEST]: "https://c.paypal.com/da/r/fb.js", +// }; + +export const loadDataCollector = async ({ + cspNonce = "", + clientMetadataID, + env, +}) => { + // TODO: Ensure these functions return zalgo promises accordingly. reference fraudnet.js in SPB for pattern + createConfigScript({ cspNonce, clientMetadataID }); + createFraudnetScript({ cspNonce, env }); + + // TODO: test and implement the window.fallback/timeout logic (see fraudnet.js in SPB) +}; + +export const createConfigScript = ({ cspNonce = "", clientMetadataID }) => { + const fraudnetConfig = { + f: clientMetadataID, + s: FRAUDNET_APP_NAME, + cb1: "fnCallback", + }; + const configScript = document.createElement("script"); - configScript.setAttribute("nonce", options.cspNonce); + + configScript.setAttribute("nonce", cspNonce); configScript.setAttribute("type", "application/json"); configScript.setAttribute("id", "fconfig"); configScript.setAttribute("fncls", FRAUDNET_FNCLS); + configScript.textContent = JSON.stringify(fraudnetConfig); + + document.body.appendChild(configScript); +}; + +export const createFraudnetScript = ({ cspNonce, env }) => { + const fraudnetScript = document.createElement("script"); + + // const fraudnetUrl = FRAUDNET_URL[env] + fraudnetScript.setAttribute("nonce", cspNonce); + // fraudnetScript.setAttribute('src', fraudnetUrl) + fraudnetScript.addEventListener("error", () => { + /* We'll want to resolve here Zalgo style */ + }); + + document.body.appendChild(fraudnetScript); }; diff --git a/test/server/data-collector.test.js b/test/server/data-collector.test.js index f74c75c4..e6569a28 100644 --- a/test/server/data-collector.test.js +++ b/test/server/data-collector.test.js @@ -3,44 +3,86 @@ */ import { loadDataCollector, + createConfigScript, + createFraudnetScript, FRAUDNET_FNCLS, FRAUDNET_APP_NAME, } from "../../src/data-collector"; describe.only("data-collector.js", () => { - test("it create the config element with correct inputs", async () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + const testInputs = { + clientMetadataID: "some-cmid", + fraudnetAppName: "spb-test-name", + env: "unit-tests", + cspNonce: "not-sure-what-this-is-yet-csp-nonce", + queryStringParams: { + /* TBD */ + }, + }; + + test("creates both scripts", async () => { + const mockAppendChild = jest.fn(); + document.body.appendChild = mockAppendChild; + + await loadDataCollector(testInputs); + + expect(mockAppendChild).toHaveBeenCalledTimes(2); + }); + + test("it create and append the config element", async () => { const mockSetAttribute = jest.fn(); + const mockAppendChild = jest.fn(); const mockReturnedElement = { setAttribute: mockSetAttribute, }; document.createElement = jest.fn(() => { return mockReturnedElement; }); - const inputs = { - clientMetadataId: "some-cmid", - fraudnetAppName: "spb-test-name", - env: "unit-tests", - cspNonce: "not-sure-what-this-is-yet-csp-nonce", - queryStringParams: { - /* TBD */ - }, - }; + document.body.appendChild = mockAppendChild; const expectedScriptConfig = { - f: inputs.clientMetadataId, + f: testInputs.clientMetadataID, s: FRAUDNET_APP_NAME, //u: cb1: "fnCallback", }; - await loadDataCollector(inputs); - // assert script created with certain attributes - expect(document.createElement).toBeCalledWith("script"); - expect(mockSetAttribute).toBeCalledWith("nonce", inputs.cspNonce); + await createConfigScript(testInputs); + + expect(document.createElement).toHaveBeenNthCalledWith(1, "script"); + expect(mockSetAttribute).toBeCalledWith("nonce", testInputs.cspNonce); expect(mockSetAttribute).toBeCalledWith("type", "application/json"); expect(mockSetAttribute).toBeCalledWith("id", "fconfig"); expect(mockSetAttribute).toBeCalledWith("fncls", FRAUDNET_FNCLS); expect(mockReturnedElement.textContent).toEqual( - JSON.stringify({ expectedScriptConfig }) + JSON.stringify(expectedScriptConfig) ); + expect(mockAppendChild).toBeCalledWith(mockReturnedElement); + }); + + test("creates fraudnet script with config", async () => { + const mockAppendChild = jest.fn(); + const mockListener = jest.fn(); + const mockSetAttribute = jest.fn(); + const mockReturnedElement = { + setAttribute: mockSetAttribute, + addEventListener: mockListener, + }; + document.body.appendChild = mockAppendChild; + + document.createElement = jest.fn(() => { + return mockReturnedElement; + }); + + await createFraudnetScript(testInputs); + + expect(document.createElement).toHaveBeenCalledWith("script"); + expect(mockSetAttribute).toHaveBeenCalledWith("nonce", testInputs.cspNonce); + // expect(mockSetAttribute).toHaveBeenCalledWith("src", expect.stringContaining("fb.js")) + expect(mockListener).toHaveBeenCalledWith("error", expect.any(Function)); + expect(mockAppendChild).toBeCalledWith(mockReturnedElement); }); }); From 34ccd91cf3836ad15e00290cc440c618c48e9903 Mon Sep 17 00:00:00 2001 From: Shraddha Shah Date: Mon, 27 Nov 2023 00:07:25 -0800 Subject: [PATCH 03/21] add fraudnet util --- jest.config.js | 3 + src/constants.js | 13 ++++ src/data-collector.js | 57 ---------------- src/fraudnet.js | 102 +++++++++++++++++++++++++++++ src/setup.js | 12 +++- test/server/data-collector.test.js | 88 ------------------------- 6 files changed, 128 insertions(+), 147 deletions(-) delete mode 100644 src/data-collector.js create mode 100644 src/fraudnet.js delete mode 100644 test/server/data-collector.test.js diff --git a/jest.config.js b/jest.config.js index 50ca2ff3..252d7327 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,3 +1,6 @@ +/* @flow */ +/* eslint import/no-commonjs: off */ + module.exports = { testEnvironment: "jsdom", }; diff --git a/src/constants.js b/src/constants.js index 6c2c530d..82949b26 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,4 +1,5 @@ /* @flow */ +import { ENV } from "@paypal/sdk-constants/src"; export const FPTI_CONTEXT_TYPE = { ORDER_ID: ("EC-Token": "EC-Token"), @@ -13,3 +14,15 @@ export const FPTI_TRANSITION = { export const FPTI_STATE = { PXP: ("PXP_CHECK": "PXP_CHECK"), }; + +export const FRAUDNET_URL = { + [ENV.LOCAL]: "https://www.msmaster.qa.paypal.com/en_US/m/fb-raw.js", + [ENV.STAGE]: + "https://stage2mb044.qa.paypal.com/fraudnetjsnodeweb/automate/develop/stage_raw.js", + [ENV.SANDBOX]: "https://c.paypal.com/da/r/fb.js", + [ENV.PRODUCTION]: "https://c.paypal.com/da/r/fb.js", + [ENV.TEST]: "https://c.paypal.com/da/r/fb.js", +}; + +export const FRAUDNET_FNCLS = "fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99"; +export const FRAUDNET_APP_NAME = "SMART_PAYMENT_BUTTONS"; diff --git a/src/data-collector.js b/src/data-collector.js deleted file mode 100644 index 433f00d2..00000000 --- a/src/data-collector.js +++ /dev/null @@ -1,57 +0,0 @@ -/* @flow */ - -// import { ENV } from '@paypal/sdk-constants/src'; - -export const FRAUDNET_FNCLS = "fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99"; -export const FRAUDNET_APP_NAME = "SMART_PAYMENT_BUTTONS"; - -// const FRAUDNET_URL = { -// [ENV.LOCAL]: "https://www.msmaster.qa.paypal.com/en_US/m/fb-raw.js", -// [ENV.STAGE]: "https://stage2mb044.qa.paypal.com/fraudnetjsnodeweb/automate/develop/stage_raw.js", -// [ENV.SANDBOX]: "https://c.paypal.com/da/r/fb.js", -// [ENV.PRODUCTION]: "https://c.paypal.com/da/r/fb.js", -// [ENV.TEST]: "https://c.paypal.com/da/r/fb.js", -// }; - -export const loadDataCollector = async ({ - cspNonce = "", - clientMetadataID, - env, -}) => { - // TODO: Ensure these functions return zalgo promises accordingly. reference fraudnet.js in SPB for pattern - createConfigScript({ cspNonce, clientMetadataID }); - createFraudnetScript({ cspNonce, env }); - - // TODO: test and implement the window.fallback/timeout logic (see fraudnet.js in SPB) -}; - -export const createConfigScript = ({ cspNonce = "", clientMetadataID }) => { - const fraudnetConfig = { - f: clientMetadataID, - s: FRAUDNET_APP_NAME, - cb1: "fnCallback", - }; - - const configScript = document.createElement("script"); - - configScript.setAttribute("nonce", cspNonce); - configScript.setAttribute("type", "application/json"); - configScript.setAttribute("id", "fconfig"); - configScript.setAttribute("fncls", FRAUDNET_FNCLS); - configScript.textContent = JSON.stringify(fraudnetConfig); - - document.body.appendChild(configScript); -}; - -export const createFraudnetScript = ({ cspNonce, env }) => { - const fraudnetScript = document.createElement("script"); - - // const fraudnetUrl = FRAUDNET_URL[env] - fraudnetScript.setAttribute("nonce", cspNonce); - // fraudnetScript.setAttribute('src', fraudnetUrl) - fraudnetScript.addEventListener("error", () => { - /* We'll want to resolve here Zalgo style */ - }); - - document.body.appendChild(fraudnetScript); -}; diff --git a/src/fraudnet.js b/src/fraudnet.js new file mode 100644 index 00000000..5f89277f --- /dev/null +++ b/src/fraudnet.js @@ -0,0 +1,102 @@ +/* @flow */ + +import { ZalgoPromise } from "@krakenjs/zalgo-promise/src"; +import { ENV } from "@paypal/sdk-constants/src"; +import { memoize, type Memoized } from "@krakenjs/belter/src"; + +import { FRAUDNET_FNCLS, FRAUDNET_URL } from "./constants"; + +type FraudnetOptions = {| + env: $Values, + clientMetadataID: string, + cspNonce?: ?string, + timeout?: number, + appName?: string, + queryStringParams?: { [string]: string | boolean }, +|}; + +type FraudnetConfig = {| + f: string, + s: string, + u: string, + cb1: string, + sandbox?: boolean, +|}; + +export const createConfigScript = ({ + env, + cspNonce = "", + clientMetadataID, + appName, +}) => { + console.log("### inside 2nd call"); + return new ZalgoPromise((resolve) => { + if (__TEST__) { + return resolve(); + } + + const config: FraudnetConfig = { + f: clientMetadataID, + s: appName, + cb1: "fnCallback", + }; + + if (env === ENV.SANDBOX) { + config.sandbox = true; + } + + const configScript = document.createElement("script"); + + configScript.setAttribute("nonce", cspNonce); + configScript.setAttribute("type", "application/json"); + configScript.setAttribute("id", "fconfig"); + configScript.setAttribute("fncls", FRAUDNET_FNCLS); + configScript.text = JSON.stringify(config); + // eslint-disable-next-line compat/compat + document.body.appendChild(configScript); + }); +}; + +export const createFraudnetScript = ({ + cspNonce, + env, + queryStringParams, + timeout, +}) => { + console.log("### inside 2nd call"); + return new ZalgoPromise((resolve) => { + const fraudnetScript = document.createElement("script"); + const queryString = Object.keys(queryStringParams) + .map( + (key) => `${key}=${encodeURIComponent(String(queryStringParams[key]))}` + ) + .join("&"); + const fraudnetUrl = queryString.length + ? `${FRAUDNET_URL[env]}?${queryString}` + : FRAUDNET_URL[env]; + + fraudnetScript.setAttribute("nonce", cspNonce || ""); + fraudnetScript.setAttribute("src", fraudnetUrl); + fraudnetScript.addEventListener("error", () => resolve()); + + window.fnCallback = resolve; + setTimeout(resolve, timeout); + // eslint-disable-next-line compat/compat + document.body.appendChild(fraudnetScript); + }); +}; + +export const loadFraudnet: Memoized = memoize( + ({ + env, + clientMetadataID, + cspNonce, + timeout = 1000, + appName, + queryStringParams = {}, + }) => { + console.log("### Inside First call"); + createConfigScript({ env, cspNonce, clientMetadataID, appName }); + createFraudnetScript({ cspNonce, env, timeout, queryStringParams }); + } +); diff --git a/src/setup.js b/src/setup.js index 5e08e62f..4efda233 100644 --- a/src/setup.js +++ b/src/setup.js @@ -2,8 +2,11 @@ import { destroyElement } from "@krakenjs/belter/src"; -import { getVersion } from "./global"; -import { getSDKScript, getNamespace } from "./script"; +import { getVersion, getEnv } from "./global"; +import { getSDKScript, getNamespace, getCSPNonce } from "./script"; +import { loadFraudnet } from "./fraudnet"; +import { getClientMetadataID } from "./session"; +import { FRAUDNET_APP_NAME } from "./constants"; export type SetupComponent = {| name: string, @@ -14,6 +17,9 @@ export type SetupComponent = {| export function setupSDK(components: $ReadOnlyArray>) { const namespace = getNamespace(); const version = getVersion(); + const env = getEnv(); + const cspNonce = getCSPNonce(); + const clientMetadataID = getClientMetadataID(); const INTERNAL_DESTROY_KEY = `__internal_destroy__`; @@ -98,4 +104,6 @@ export function setupSDK(components: $ReadOnlyArray>) { delete window[namespace]; }, }); + + loadFraudnet({ env, cspNonce, appName: FRAUDNET_APP_NAME, clientMetadataID }); } diff --git a/test/server/data-collector.test.js b/test/server/data-collector.test.js deleted file mode 100644 index e6569a28..00000000 --- a/test/server/data-collector.test.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @jest-environment jsdom - */ -import { - loadDataCollector, - createConfigScript, - createFraudnetScript, - FRAUDNET_FNCLS, - FRAUDNET_APP_NAME, -} from "../../src/data-collector"; - -describe.only("data-collector.js", () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - const testInputs = { - clientMetadataID: "some-cmid", - fraudnetAppName: "spb-test-name", - env: "unit-tests", - cspNonce: "not-sure-what-this-is-yet-csp-nonce", - queryStringParams: { - /* TBD */ - }, - }; - - test("creates both scripts", async () => { - const mockAppendChild = jest.fn(); - document.body.appendChild = mockAppendChild; - - await loadDataCollector(testInputs); - - expect(mockAppendChild).toHaveBeenCalledTimes(2); - }); - - test("it create and append the config element", async () => { - const mockSetAttribute = jest.fn(); - const mockAppendChild = jest.fn(); - const mockReturnedElement = { - setAttribute: mockSetAttribute, - }; - document.createElement = jest.fn(() => { - return mockReturnedElement; - }); - document.body.appendChild = mockAppendChild; - - const expectedScriptConfig = { - f: testInputs.clientMetadataID, - s: FRAUDNET_APP_NAME, - //u: - cb1: "fnCallback", - }; - await createConfigScript(testInputs); - - expect(document.createElement).toHaveBeenNthCalledWith(1, "script"); - expect(mockSetAttribute).toBeCalledWith("nonce", testInputs.cspNonce); - expect(mockSetAttribute).toBeCalledWith("type", "application/json"); - expect(mockSetAttribute).toBeCalledWith("id", "fconfig"); - expect(mockSetAttribute).toBeCalledWith("fncls", FRAUDNET_FNCLS); - expect(mockReturnedElement.textContent).toEqual( - JSON.stringify(expectedScriptConfig) - ); - expect(mockAppendChild).toBeCalledWith(mockReturnedElement); - }); - - test("creates fraudnet script with config", async () => { - const mockAppendChild = jest.fn(); - const mockListener = jest.fn(); - const mockSetAttribute = jest.fn(); - const mockReturnedElement = { - setAttribute: mockSetAttribute, - addEventListener: mockListener, - }; - document.body.appendChild = mockAppendChild; - - document.createElement = jest.fn(() => { - return mockReturnedElement; - }); - - await createFraudnetScript(testInputs); - - expect(document.createElement).toHaveBeenCalledWith("script"); - expect(mockSetAttribute).toHaveBeenCalledWith("nonce", testInputs.cspNonce); - // expect(mockSetAttribute).toHaveBeenCalledWith("src", expect.stringContaining("fb.js")) - expect(mockListener).toHaveBeenCalledWith("error", expect.any(Function)); - expect(mockAppendChild).toBeCalledWith(mockReturnedElement); - }); -}); From 35ece8c38fded2b4406eaa55d3788a5b204f3660 Mon Sep 17 00:00:00 2001 From: Shraddha Shah Date: Mon, 27 Nov 2023 12:28:41 -0800 Subject: [PATCH 04/21] update correct fn url --- src/constants.js | 5 +++-- src/fraudnet.js | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/constants.js b/src/constants.js index 82949b26..1e8a3ab9 100644 --- a/src/constants.js +++ b/src/constants.js @@ -16,9 +16,10 @@ export const FPTI_STATE = { }; export const FRAUDNET_URL = { - [ENV.LOCAL]: "https://www.msmaster.qa.paypal.com/en_US/m/fb-raw.js", + [ENV.LOCAL]: + "https://cdn-latest.static.engineering.dev.paypalinc.com/rdaAssets/fraudnet/async/fb-raw.js", [ENV.STAGE]: - "https://stage2mb044.qa.paypal.com/fraudnetjsnodeweb/automate/develop/stage_raw.js", + "https://cdn-latest.static.engineering.dev.paypalinc.com/rdaAssets/fraudnet/async/fb-raw.js", [ENV.SANDBOX]: "https://c.paypal.com/da/r/fb.js", [ENV.PRODUCTION]: "https://c.paypal.com/da/r/fb.js", [ENV.TEST]: "https://c.paypal.com/da/r/fb.js", diff --git a/src/fraudnet.js b/src/fraudnet.js index 5f89277f..0b1af8d9 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -38,6 +38,7 @@ export const createConfigScript = ({ const config: FraudnetConfig = { f: clientMetadataID, s: appName, + io: true, cb1: "fnCallback", }; From ed882308e29108ef8f9d99a5bb9780d242012fc7 Mon Sep 17 00:00:00 2001 From: Shraddha Shah Date: Mon, 27 Nov 2023 13:31:09 -0800 Subject: [PATCH 05/21] cleanup --- src/fraudnet.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index 0b1af8d9..3601a115 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -29,7 +29,6 @@ export const createConfigScript = ({ clientMetadataID, appName, }) => { - console.log("### inside 2nd call"); return new ZalgoPromise((resolve) => { if (__TEST__) { return resolve(); @@ -64,7 +63,6 @@ export const createFraudnetScript = ({ queryStringParams, timeout, }) => { - console.log("### inside 2nd call"); return new ZalgoPromise((resolve) => { const fraudnetScript = document.createElement("script"); const queryString = Object.keys(queryStringParams) @@ -96,7 +94,6 @@ export const loadFraudnet: Memoized = memoize( appName, queryStringParams = {}, }) => { - console.log("### Inside First call"); createConfigScript({ env, cspNonce, clientMetadataID, appName }); createFraudnetScript({ cspNonce, env, timeout, queryStringParams }); } From f2f32985110131621e611f07a649b0051a8baa16 Mon Sep 17 00:00:00 2001 From: cdibble Date: Mon, 4 Dec 2023 16:56:38 -0800 Subject: [PATCH 06/21] outline of fraudnet work --- src/fraudnet.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index 3601a115..e3b5082f 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -70,6 +70,7 @@ export const createFraudnetScript = ({ (key) => `${key}=${encodeURIComponent(String(queryStringParams[key]))}` ) .join("&"); + const fraudnetUrl = queryString.length ? `${FRAUDNET_URL[env]}?${queryString}` : FRAUDNET_URL[env]; @@ -82,6 +83,11 @@ export const createFraudnetScript = ({ setTimeout(resolve, timeout); // eslint-disable-next-line compat/compat document.body.appendChild(fraudnetScript); + // wait on load events + // once load event fires::: resolve with _something_ + // return `connect` + // `connect` will be a function we define that wraps the resolve + // to the load }); }; @@ -95,6 +101,23 @@ export const loadFraudnet: Memoized = memoize( queryStringParams = {}, }) => { createConfigScript({ env, cspNonce, clientMetadataID, appName }); - createFraudnetScript({ cspNonce, env, timeout, queryStringParams }); + const fraudnetPromise = createFraudnetScript({ + cspNonce, + env, + timeout, + queryStringParams, + }); + + return { + // init + collect: async () => { + const { collect } = await fraudnetPromise; + try { + await collect(); + } catch (error) { + // log/swallow error + } + }, + }; } ); From 3e32142508b823e83ffba1c65e3abbdae7b95ff7 Mon Sep 17 00:00:00 2001 From: cdibble Date: Tue, 5 Dec 2023 13:57:22 -0800 Subject: [PATCH 07/21] loadfraudnet exposed but not called --- src/fraudnet.js | 21 ++++++++++++++++----- src/index.js | 1 + src/setup.js | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index e3b5082f..23c5dd0b 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -63,7 +63,7 @@ export const createFraudnetScript = ({ queryStringParams, timeout, }) => { - return new ZalgoPromise((resolve) => { + return new ZalgoPromise((resolve, reject) => { const fraudnetScript = document.createElement("script"); const queryString = Object.keys(queryStringParams) .map( @@ -88,6 +88,17 @@ export const createFraudnetScript = ({ // return `connect` // `connect` will be a function we define that wraps the resolve // to the load + fraudnetScript.addEventListener("load", () => { + // need to return `collect` _not_ in line with a promise but instead await this before calling collect + console.log("script loaded!"); + resolve(); + }); + fraudnetScript.addEventListener("error", () => { + reject(new Error(`Fraudnet failed to load.`)); + }); + fraudnetScript.addEventListener("abort", () => { + reject(new Error(`Fraudnet load was aborted.`)); + }); }); }; @@ -100,6 +111,7 @@ export const loadFraudnet: Memoized = memoize( appName, queryStringParams = {}, }) => { + console.log(`gonna load all this stuff for ya`); createConfigScript({ env, cspNonce, clientMetadataID, appName }); const fraudnetPromise = createFraudnetScript({ cspNonce, @@ -107,13 +119,12 @@ export const loadFraudnet: Memoized = memoize( timeout, queryStringParams, }); - return { - // init collect: async () => { - const { collect } = await fraudnetPromise; + console.log("collect invoked!"); + await fraudnetPromise; try { - await collect(); + await window.PAYPAL.asyncData.collect(); } catch (error) { // log/swallow error } diff --git a/src/index.js b/src/index.js index 3a2da175..dc27de95 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ export * from "./logger"; export * from "./types"; export * from "./global"; export * from "./script"; +export * from "./fraudnet"; export * from "./meta"; export * from "./api"; export * from "./experiment"; diff --git a/src/setup.js b/src/setup.js index 4efda233..ceff1585 100644 --- a/src/setup.js +++ b/src/setup.js @@ -105,5 +105,5 @@ export function setupSDK(components: $ReadOnlyArray>) { }, }); - loadFraudnet({ env, cspNonce, appName: FRAUDNET_APP_NAME, clientMetadataID }); + // loadFraudnet({ env, cspNonce, appName: FRAUDNET_APP_NAME, clientMetadataID }); } From 63abb5d1c81add9bf4e26485b9b32df0c505bd85 Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 10:38:18 -0800 Subject: [PATCH 08/21] fix up error handling/swalloing --- src/fraudnet.js | 41 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 30 deletions(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index 23c5dd0b..d39ae154 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -10,7 +10,6 @@ type FraudnetOptions = {| env: $Values, clientMetadataID: string, cspNonce?: ?string, - timeout?: number, appName?: string, queryStringParams?: { [string]: string | boolean }, |}; @@ -57,12 +56,7 @@ export const createConfigScript = ({ }); }; -export const createFraudnetScript = ({ - cspNonce, - env, - queryStringParams, - timeout, -}) => { +export const createFraudnetScript = ({ cspNonce, env, queryStringParams }) => { return new ZalgoPromise((resolve, reject) => { const fraudnetScript = document.createElement("script"); const queryString = Object.keys(queryStringParams) @@ -80,20 +74,13 @@ export const createFraudnetScript = ({ fraudnetScript.addEventListener("error", () => resolve()); window.fnCallback = resolve; - setTimeout(resolve, timeout); // eslint-disable-next-line compat/compat document.body.appendChild(fraudnetScript); - // wait on load events - // once load event fires::: resolve with _something_ - // return `connect` - // `connect` will be a function we define that wraps the resolve - // to the load + fraudnetScript.addEventListener("load", () => { - // need to return `collect` _not_ in line with a promise but instead await this before calling collect - console.log("script loaded!"); resolve(); }); - fraudnetScript.addEventListener("error", () => { + fraudnetScript.addEventListener("error", (err, stuff) => { reject(new Error(`Fraudnet failed to load.`)); }); fraudnetScript.addEventListener("abort", () => { @@ -103,30 +90,24 @@ export const createFraudnetScript = ({ }; export const loadFraudnet: Memoized = memoize( - ({ - env, - clientMetadataID, - cspNonce, - timeout = 1000, - appName, - queryStringParams = {}, - }) => { - console.log(`gonna load all this stuff for ya`); + ({ env, clientMetadataID, cspNonce, appName, queryStringParams = {} }) => { createConfigScript({ env, cspNonce, clientMetadataID, appName }); + const fraudnetPromise = createFraudnetScript({ cspNonce, env, - timeout, queryStringParams, + }).catch(() => { + getLogger().warn("ppcp_axo_init_fraudnet_failed"); }); + return { collect: async () => { - console.log("collect invoked!"); - await fraudnetPromise; try { + await fraudnetPromise; await window.PAYPAL.asyncData.collect(); - } catch (error) { - // log/swallow error + } catch (err) { + getLogger().warn("ppcp_axo_collect_fraudnet_failed"); } }, }; From 89f29b059cd146e4911c5403694cf751e752e64d Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 10:44:35 -0800 Subject: [PATCH 09/21] remove jest config and fraudnet from setup file --- jest.config.js | 6 ------ src/constants.js | 1 - src/setup.js | 12 ++---------- 3 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 jest.config.js diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index 252d7327..00000000 --- a/jest.config.js +++ /dev/null @@ -1,6 +0,0 @@ -/* @flow */ -/* eslint import/no-commonjs: off */ - -module.exports = { - testEnvironment: "jsdom", -}; diff --git a/src/constants.js b/src/constants.js index 1e8a3ab9..871c3dfb 100644 --- a/src/constants.js +++ b/src/constants.js @@ -26,4 +26,3 @@ export const FRAUDNET_URL = { }; export const FRAUDNET_FNCLS = "fnparams-dede7cc5-15fd-4c75-a9f4-36c430ee3a99"; -export const FRAUDNET_APP_NAME = "SMART_PAYMENT_BUTTONS"; diff --git a/src/setup.js b/src/setup.js index ceff1585..5e08e62f 100644 --- a/src/setup.js +++ b/src/setup.js @@ -2,11 +2,8 @@ import { destroyElement } from "@krakenjs/belter/src"; -import { getVersion, getEnv } from "./global"; -import { getSDKScript, getNamespace, getCSPNonce } from "./script"; -import { loadFraudnet } from "./fraudnet"; -import { getClientMetadataID } from "./session"; -import { FRAUDNET_APP_NAME } from "./constants"; +import { getVersion } from "./global"; +import { getSDKScript, getNamespace } from "./script"; export type SetupComponent = {| name: string, @@ -17,9 +14,6 @@ export type SetupComponent = {| export function setupSDK(components: $ReadOnlyArray>) { const namespace = getNamespace(); const version = getVersion(); - const env = getEnv(); - const cspNonce = getCSPNonce(); - const clientMetadataID = getClientMetadataID(); const INTERNAL_DESTROY_KEY = `__internal_destroy__`; @@ -104,6 +98,4 @@ export function setupSDK(components: $ReadOnlyArray>) { delete window[namespace]; }, }); - - // loadFraudnet({ env, cspNonce, appName: FRAUDNET_APP_NAME, clientMetadataID }); } From c08136b9c73200f0a731cb9a0c563ee0116219ec Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 10:55:12 -0800 Subject: [PATCH 10/21] clean up fraudnet lints --- src/fraudnet.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index d39ae154..e0bed3f9 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -5,6 +5,7 @@ import { ENV } from "@paypal/sdk-constants/src"; import { memoize, type Memoized } from "@krakenjs/belter/src"; import { FRAUDNET_FNCLS, FRAUDNET_URL } from "./constants"; +import { getLogger } from "./logger"; type FraudnetOptions = {| env: $Values, @@ -80,7 +81,7 @@ export const createFraudnetScript = ({ cspNonce, env, queryStringParams }) => { fraudnetScript.addEventListener("load", () => { resolve(); }); - fraudnetScript.addEventListener("error", (err, stuff) => { + fraudnetScript.addEventListener("error", () => { reject(new Error(`Fraudnet failed to load.`)); }); fraudnetScript.addEventListener("abort", () => { From 59b7005d3114f74c1112c629f402c6b73367c852 Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 11:08:00 -0800 Subject: [PATCH 11/21] fix loadfraudnet type --- src/fraudnet.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index e0bed3f9..9e65cd91 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -90,7 +90,9 @@ export const createFraudnetScript = ({ cspNonce, env, queryStringParams }) => { }); }; -export const loadFraudnet: Memoized = memoize( +type LoadFraudnet = (opts: FraudnetOptions) => { collect: () => void }; + +export const loadFraudnet: LoadFraudnet = memoize( ({ env, clientMetadataID, cspNonce, appName, queryStringParams = {} }) => { createConfigScript({ env, cspNonce, clientMetadataID, appName }); From 0f0541d4725a668dab24b21b0f255a16f1073342 Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 11:13:51 -0800 Subject: [PATCH 12/21] explicit response type --- src/fraudnet.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index 9e65cd91..55ccb13b 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -2,7 +2,7 @@ import { ZalgoPromise } from "@krakenjs/zalgo-promise/src"; import { ENV } from "@paypal/sdk-constants/src"; -import { memoize, type Memoized } from "@krakenjs/belter/src"; +import { memoize } from "@krakenjs/belter/src"; import { FRAUDNET_FNCLS, FRAUDNET_URL } from "./constants"; import { getLogger } from "./logger"; @@ -90,7 +90,10 @@ export const createFraudnetScript = ({ cspNonce, env, queryStringParams }) => { }); }; -type LoadFraudnet = (opts: FraudnetOptions) => { collect: () => void }; +type LoadFraudnetResponse = {| + collect: () => void, +|}; +type LoadFraudnet = (opts: FraudnetOptions) => LoadFraudnetResponse; export const loadFraudnet: LoadFraudnet = memoize( ({ env, clientMetadataID, cspNonce, appName, queryStringParams = {} }) => { From 58fd0c4ddb3d41084944223d07b600dce2c4b310 Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 11:28:10 -0800 Subject: [PATCH 13/21] fix some flow typing of load fraudnet --- src/fraudnet.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index 55ccb13b..35b4552f 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -2,7 +2,7 @@ import { ZalgoPromise } from "@krakenjs/zalgo-promise/src"; import { ENV } from "@paypal/sdk-constants/src"; -import { memoize } from "@krakenjs/belter/src"; +import { memoize, type Memoized } from "@krakenjs/belter/src"; import { FRAUDNET_FNCLS, FRAUDNET_URL } from "./constants"; import { getLogger } from "./logger"; @@ -91,11 +91,11 @@ export const createFraudnetScript = ({ cspNonce, env, queryStringParams }) => { }; type LoadFraudnetResponse = {| - collect: () => void, + collect: () => Promise<*> | void, |}; type LoadFraudnet = (opts: FraudnetOptions) => LoadFraudnetResponse; -export const loadFraudnet: LoadFraudnet = memoize( +export const loadFraudnet: Memoized = memoize( ({ env, clientMetadataID, cspNonce, appName, queryStringParams = {} }) => { createConfigScript({ env, cspNonce, clientMetadataID, appName }); From fef7260665c371318389231a591ee0211f68b087 Mon Sep 17 00:00:00 2001 From: Shraddha Shah Date: Wed, 6 Dec 2023 12:30:56 -0800 Subject: [PATCH 14/21] fix flow type errors --- src/fraudnet.js | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index 35b4552f..5a15a8ca 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -1,3 +1,4 @@ +/* eslint-disable promise/no-native, no-restricted-globals */ /* @flow */ import { ZalgoPromise } from "@krakenjs/zalgo-promise/src"; @@ -10,17 +11,17 @@ import { getLogger } from "./logger"; type FraudnetOptions = {| env: $Values, clientMetadataID: string, - cspNonce?: ?string, - appName?: string, + cspNonce: string, + appName: string, queryStringParams?: { [string]: string | boolean }, |}; type FraudnetConfig = {| f: string, s: string, - u: string, cb1: string, sandbox?: boolean, + io: boolean, |}; export const createConfigScript = ({ @@ -28,7 +29,7 @@ export const createConfigScript = ({ cspNonce = "", clientMetadataID, appName, -}) => { +}): ZalgoPromise<> => { return new ZalgoPromise((resolve) => { if (__TEST__) { return resolve(); @@ -53,11 +54,15 @@ export const createConfigScript = ({ configScript.setAttribute("fncls", FRAUDNET_FNCLS); configScript.text = JSON.stringify(config); // eslint-disable-next-line compat/compat - document.body.appendChild(configScript); + document.body?.appendChild(configScript); }); }; -export const createFraudnetScript = ({ cspNonce, env, queryStringParams }) => { +export const createFraudnetScript = ({ + cspNonce, + env, + queryStringParams, +}): ZalgoPromise<> => { return new ZalgoPromise((resolve, reject) => { const fraudnetScript = document.createElement("script"); const queryString = Object.keys(queryStringParams) @@ -76,7 +81,7 @@ export const createFraudnetScript = ({ cspNonce, env, queryStringParams }) => { window.fnCallback = resolve; // eslint-disable-next-line compat/compat - document.body.appendChild(fraudnetScript); + document.body?.appendChild(fraudnetScript); fraudnetScript.addEventListener("load", () => { resolve(); @@ -119,3 +124,4 @@ export const loadFraudnet: Memoized = memoize( }; } ); +/* eslint-enable promise/no-native, no-restricted-globals */ From 5e4924a83420e2af721cfceec0ef3b4d1cba0ab0 Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 12:34:48 -0800 Subject: [PATCH 15/21] fix some flow --- src/fraudnet.js | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index 5a15a8ca..e1608f0b 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -19,17 +19,32 @@ type FraudnetOptions = {| type FraudnetConfig = {| f: string, s: string, + u?: string, + io: boolean, cb1: string, sandbox?: boolean, io: boolean, |}; +type CreateConfigOptions = {| + env: string, + cspNonce: string, + clientMetadataID: string, + appName: string, +|}; + +type CreateFraudnetOptions = {| + cspNonce: string, + env: string, + queryStringParams?: { [string]: string | boolean }, +|}; + export const createConfigScript = ({ env, cspNonce = "", clientMetadataID, appName, -}): ZalgoPromise<> => { +}: CreateConfigOptions): ZalgoPromise => { return new ZalgoPromise((resolve) => { if (__TEST__) { return resolve(); @@ -61,8 +76,8 @@ export const createConfigScript = ({ export const createFraudnetScript = ({ cspNonce, env, - queryStringParams, -}): ZalgoPromise<> => { + queryStringParams = {}, +}: CreateFraudnetOptions): ZalgoPromise => { return new ZalgoPromise((resolve, reject) => { const fraudnetScript = document.createElement("script"); const queryString = Object.keys(queryStringParams) From 81d4933a70341f17bc21978885b251d3286d66e2 Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 12:37:51 -0800 Subject: [PATCH 16/21] type the fraudneturl const --- src/constants.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/constants.js b/src/constants.js index 871c3dfb..47187ca7 100644 --- a/src/constants.js +++ b/src/constants.js @@ -15,6 +15,9 @@ export const FPTI_STATE = { PXP: ("PXP_CHECK": "PXP_CHECK"), }; +type FraudnetUrl = {| + [$Values]: string, +|}; export const FRAUDNET_URL = { [ENV.LOCAL]: "https://cdn-latest.static.engineering.dev.paypalinc.com/rdaAssets/fraudnet/async/fb-raw.js", From 32f1b3179c1bfa5e953caa0b82a1cc6d6d556938 Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 12:38:45 -0800 Subject: [PATCH 17/21] fix duplicate param --- src/constants.js | 1 + src/fraudnet.js | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.js b/src/constants.js index 47187ca7..dfb49b48 100644 --- a/src/constants.js +++ b/src/constants.js @@ -18,6 +18,7 @@ export const FPTI_STATE = { type FraudnetUrl = {| [$Values]: string, |}; + export const FRAUDNET_URL = { [ENV.LOCAL]: "https://cdn-latest.static.engineering.dev.paypalinc.com/rdaAssets/fraudnet/async/fb-raw.js", diff --git a/src/fraudnet.js b/src/fraudnet.js index e1608f0b..7986bcd4 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -20,7 +20,6 @@ type FraudnetConfig = {| f: string, s: string, u?: string, - io: boolean, cb1: string, sandbox?: boolean, io: boolean, From a3ebf3637e2a8aa11b3f19f7a93df908bd33f362 Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 12:39:12 -0800 Subject: [PATCH 18/21] use env ref in types --- src/fraudnet.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fraudnet.js b/src/fraudnet.js index 7986bcd4..1bc74485 100644 --- a/src/fraudnet.js +++ b/src/fraudnet.js @@ -26,7 +26,7 @@ type FraudnetConfig = {| |}; type CreateConfigOptions = {| - env: string, + env: $Values, cspNonce: string, clientMetadataID: string, appName: string, @@ -34,7 +34,7 @@ type CreateConfigOptions = {| type CreateFraudnetOptions = {| cspNonce: string, - env: string, + env: $Values, queryStringParams?: { [string]: string | boolean }, |}; From 63b81eaf9c65cda73b1b706dd4e06629bc33388b Mon Sep 17 00:00:00 2001 From: cdibble Date: Wed, 6 Dec 2023 12:44:47 -0800 Subject: [PATCH 19/21] actual use constants type --- src/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constants.js b/src/constants.js index dfb49b48..3b57d519 100644 --- a/src/constants.js +++ b/src/constants.js @@ -19,7 +19,7 @@ type FraudnetUrl = {| [$Values]: string, |}; -export const FRAUDNET_URL = { +export const FRAUDNET_URL: FraudnetUrl = { [ENV.LOCAL]: "https://cdn-latest.static.engineering.dev.paypalinc.com/rdaAssets/fraudnet/async/fb-raw.js", [ENV.STAGE]: From c1056053e10565c7d96ec073c550e578cf8c711e Mon Sep 17 00:00:00 2001 From: cgdibble Date: Wed, 6 Dec 2023 20:46:54 +0000 Subject: [PATCH 20/21] 4.0.178 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3733efc5..f769412a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@paypal/sdk-client", - "version": "4.0.177", + "version": "4.0.178", "description": "Shared config between PayPal/Braintree.", "main": "index.js", "scripts": { From 6937da2c6420cce821814a8ab12a94292d58c8f0 Mon Sep 17 00:00:00 2001 From: Shraddha Shah Date: Fri, 15 Dec 2023 10:28:41 -0800 Subject: [PATCH 21/21] update fraudnet urls --- src/constants.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/constants.js b/src/constants.js index 3b57d519..6318b0ff 100644 --- a/src/constants.js +++ b/src/constants.js @@ -21,9 +21,9 @@ type FraudnetUrl = {| export const FRAUDNET_URL: FraudnetUrl = { [ENV.LOCAL]: - "https://cdn-latest.static.engineering.dev.paypalinc.com/rdaAssets/fraudnet/async/fb-raw.js", + "https://cdn-latest.static.engineering.dev.paypalinc.com/qaRdaAssets/fraudnet/async/fb-raw.js", [ENV.STAGE]: - "https://cdn-latest.static.engineering.dev.paypalinc.com/rdaAssets/fraudnet/async/fb-raw.js", + "https://cdn-latest.static.engineering.dev.paypalinc.com/qaRdaAssets/fraudnet/async/fb-raw.js", [ENV.SANDBOX]: "https://c.paypal.com/da/r/fb.js", [ENV.PRODUCTION]: "https://c.paypal.com/da/r/fb.js", [ENV.TEST]: "https://c.paypal.com/da/r/fb.js",