Skip to content

Commit

Permalink
DTSHOPSEOL-2021: [Muse] SDK - cookie-remediation Phase 2, Honor noCoo… (
Browse files Browse the repository at this point in the history
#185)

* DTSHOPSEOL-2021: [Muse] SDK - cookie-remediation Phase 2, Honor noCookies flag

* DTSHOPSEOL-2021: Fix flow issues

* DTSHOPSEOL-2021: remove typo

* DTSHOPSEOL-2021: Parse JSON inside local storage manager
  • Loading branch information
yehor-anisimov authored Aug 8, 2023
1 parent 4dc4c08 commit 91f020a
Show file tree
Hide file tree
Showing 23 changed files with 149 additions and 87 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ dist
coverage
flow-typed
npm-debug.log
.idea
.idea
.vscode
5 changes: 3 additions & 2 deletions src/lib/debug-console-logger.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* @flow */
import constants from './constants';
import { writeInLocalStorage, readFromLocalStorage } from './local-storage/local-storage-manager';

const { storage } = constants;
const timeOutOptions = { hour12: false };
Expand All @@ -20,7 +21,7 @@ function _initDebugTracker() {
console.log(`${ _getTimeLabel() }[debug-console-logger:init] PayPal Shopping: debug mode on. Based on URL parameter.`);
} else {
try {
debug = window.localStorage.getItem(storage.paypalSDKConsoleDebug) === 'true';
debug = readFromLocalStorage(storage.paypalSDKConsoleDebug) === true;
if (debug) {
// eslint-disable-next-line no-console
console.log(`${ _getTimeLabel() }[debug-console-logger:init] PayPal Shopping: debug mode on. Based on local storage.`);
Expand Down Expand Up @@ -53,7 +54,7 @@ export const debugLogger = {
}
},
setDebugEnabled: (enabled : boolean) => {
window.localStorage.setItem(storage.paypalSDKConsoleDebug, enabled);
writeInLocalStorage(storage.paypalSDKConsoleDebug, enabled);
if (enabled) {
// eslint-disable-next-line no-console
console.log(`${ _getTimeLabel() }[debug-console-logger:setDebugEnabled] PayPal Shopping: debug mode on. Mode ON saved to local storage.`);
Expand Down
5 changes: 3 additions & 2 deletions src/lib/get-property-id.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* @flow */
import { getMerchantID, getSDKQueryParam } from '@paypal/sdk-client/src';
import { getDisableSetCookie, getMerchantID, getSDKQueryParam } from '@paypal/sdk-client/src';

import type {
Config,
Expand Down Expand Up @@ -59,8 +59,9 @@ export const getContainerRequestUrl = (merchantId : string, clientId : string, p
const baseUrl = paramsToPropertyIdUrl ? paramsToPropertyIdUrl() : 'https://www.paypal.com/tagmanager/containers/xo';

const requestId = merchantId ? `mrid=${ merchantId }` : `client_id=${ clientId }`;
const cookieQueryParams = getDisableSetCookie() ? '&disableSetCookie=true' : '';

return `${ baseUrl }?${ requestId }&url=${ encodeURIComponent(merchantWebsite) }&jlAccessToken=true`;
return `${ baseUrl }?${ requestId }&url=${ encodeURIComponent(merchantWebsite) }&jlAccessToken=true${cookieQueryParams}`;
};

const getContainer = (paramsToPropertyIdUrl? : Function) : Promise<Container> => {
Expand Down
8 changes: 4 additions & 4 deletions src/lib/iframe-tools/identity-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getDeviceInfo } from '../get-device-info';
import { logger } from '../logger';
import { debugLogger } from '../debug-console-logger';
import constants from '../constants';
import { readFromLocalStorage, writeInLocalStorage } from '../local-storage/local-storage-manager';

import { IframeManager } from './iframe-manager';

Expand Down Expand Up @@ -90,13 +91,12 @@ export class IdentityManager extends IframeManager {
let shouldCheckCountry = true; // default to how it works currently
const localStorageKey = 'pp-sdk-shouldReallyCheckCountry';
try {
const LS = window.localStorage;
if (LS.getItem(localStorageKey) === null) {
if (readFromLocalStorage(localStorageKey) === null) {
const randomChance = Math.floor(Math.random() * 100);
shouldCheckCountry = randomChance < 50;
LS.setItem(localStorageKey, JSON.stringify(shouldCheckCountry));
writeInLocalStorage(localStorageKey, shouldCheckCountry);
} else {
shouldCheckCountry = JSON.parse(LS.getItem(localStorageKey));
shouldCheckCountry = readFromLocalStorage(localStorageKey);
}
} catch (e) {
debugLogger.log('[identity-manager:fetchIdentity] Error while accessing local storage for key :', localStorageKey);
Expand Down
12 changes: 4 additions & 8 deletions src/lib/local-storage/cart.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@
import constants from '../constants';
import generate from '../generate-id';

import { readFromLocalStorage, writeInLocalStorage } from './local-storage-manager';

const { storage, sevenDays } = constants;

/* Returns an existing cartId or null */
export const getCartId = () => {
const storedValue = window.localStorage.getItem(storage.paypalCrCart);

if (storedValue) {
return JSON.parse(storedValue);
}

return null;
return readFromLocalStorage(storage.paypalCrCart);
};

/* Sets a new cartId to expire in 7 days */
Expand All @@ -22,7 +18,7 @@ export const setCartId = (cartId : string) => {
createdAt: Date.now()
};

window.localStorage.setItem(storage.paypalCrCart, JSON.stringify(storedValue));
writeInLocalStorage(storage.paypalCrCart, storedValue);

return storedValue;
};
Expand Down
12 changes: 4 additions & 8 deletions src/lib/local-storage/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,12 @@
import constants from '../constants';
import type { ContainerSummary } from '../../types';

import { writeInLocalStorage, readFromLocalStorage } from './local-storage-manager';

const { storage, oneHour } = constants;

const getContainer = () : Object | null => {
const storedValue = window.localStorage.getItem(storage.paypalCrContainer);

if (storedValue) {
return JSON.parse(storedValue);
}

return null;
return readFromLocalStorage(storage.paypalCrContainer);
};

/* Returns an existing, non-expired container. Removes a container
Expand Down Expand Up @@ -39,7 +35,7 @@ export const setContainer = (containerSummary : ContainerSummary) => {
createdAt: Date.now()
});

window.localStorage.setItem(storage.paypalCrContainer, storedValue);
writeInLocalStorage(storage.paypalCrContainer, storedValue);
};

export const clearContainer = () => {
Expand Down
10 changes: 5 additions & 5 deletions src/lib/local-storage/identity.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
/* @flow */
import constants from '../constants';

import { writeInLocalStorage, readFromLocalStorage } from './local-storage-manager';

const { storage, oneHour } = constants;

export const clearIdentity = () => {
window.localStorage.removeItem(storage.paypalSDKIdentity);
};

export const getIdentity = () => {
let storedValue = window.localStorage.getItem(storage.paypalSDKIdentity);
const storedValue = readFromLocalStorage(storage.paypalSDKIdentity);
const now = Date.now();

try {
storedValue = JSON.parse(storedValue);
} catch (err) {
if (!storedValue) {
clearIdentity();
return null;
}
Expand All @@ -33,7 +33,7 @@ export const setIdentity = identity => {
createdAt: Date.now()
};

window.localStorage.setItem(storage.paypalSDKIdentity, JSON.stringify(storedValue));
writeInLocalStorage(storage.paypalSDKIdentity, storedValue);

return storedValue;
};
32 changes: 32 additions & 0 deletions src/lib/local-storage/local-storage-manager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* @flow */
import { getDisableSetCookie } from '@paypal/sdk-client/src';

const serializeData = (data: Object | string) => {
try {
if (typeof data === 'string') {
return data;
}

return JSON.stringify(data);
} catch (e) {
return '';
}
};

export const readFromLocalStorage = (key: string) => {
const value = window.localStorage.getItem(key);

try {
return JSON.parse(value);
} catch (e) {
return null;
}
};

export const writeInLocalStorage = (key: string, data: Object) => {
if (getDisableSetCookie()) {
return;
}

window.localStorage.setItem(key, serializeData(data));
};
18 changes: 6 additions & 12 deletions src/lib/local-storage/property-id.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
/* @flow */
import constants from '../constants';

import { writeInLocalStorage, readFromLocalStorage } from './local-storage-manager';

const { storage } = constants;

export const getPropertyId = () : Object | null => {
try {
const storedValue = window.localStorage.getItem(storage.paypalCrPropertyId);

if (storedValue) {
return JSON.parse(storedValue);
}
} catch (e) {
return null;
}

return null;
return readFromLocalStorage(storage.paypalCrPropertyId);
};

export const setPropertyId = (propertyId : string) : void => {
Expand All @@ -23,5 +15,7 @@ export const setPropertyId = (propertyId : string) : void => {
createdAt: Date.now()
};

window.localStorage.setItem(storage.paypalCrPropertyId, JSON.stringify(storedValue));
writeInLocalStorage(storage.paypalCrPropertyId, storedValue);
};

// TODO: removeFromLocal storage `window.localStorage.removeItem(key);`
28 changes: 5 additions & 23 deletions src/lib/local-storage/user.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
/* @flow */
import constants from '../constants';
import generate from '../generate-id';
import { logger } from '../logger';

import { writeInLocalStorage, readFromLocalStorage } from './local-storage-manager';

const { storage } = constants;

export const getUserStorage = () => {
let userStorage = window.localStorage.getItem(storage.paypalCrUser) || '{}';

try {
userStorage = JSON.parse(userStorage);
} catch (err) {
logger.error('getUserStorage', err);
userStorage = {};
}

return userStorage;
return readFromLocalStorage(storage.paypalCrUser) || {};
};

export const setUserStorage = (userStorage : Object) => {
window.localStorage.setItem(storage.paypalCrUser, JSON.stringify(userStorage));
writeInLocalStorage(storage.paypalCrUser, userStorage);
};

// Generates a random user ID.
Expand Down Expand Up @@ -48,17 +40,7 @@ export const setMerchantProvidedUserId = (id : string) => {

/* Returns a userId if one exists */
export const getUserId = () => {
try {
const storedValue = window.localStorage.getItem(storage.paypalCrUser);

if (storedValue) {
return JSON.parse(storedValue);
}
} catch (e) {
return null;
}

return null;
return readFromLocalStorage(storage.paypalCrUser);
};

/** Returns an existing, valid userId cached in localStorage
Expand Down
7 changes: 5 additions & 2 deletions src/lib/shopping-analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'whatwg-fetch'; // eslint-disable-line import/no-unassigned-import

import type { Config } from '../types/config';
import type { ContainerSummary } from '../types';
import type { VisitorInfo } from '../types/user';

import { setupTrackers } from './shopping-trackers';
import { setupUserDetails } from './user-configuration';
Expand All @@ -18,6 +19,7 @@ export const shoppingAnalyticsSetup = (config : Config = {}) => {
let identityFetchCompleted : boolean = false;
let containerFetchCompleted : boolean = false;
let eventQueue = [];
let inMemoryIdentity: VisitorInfo = null;
const queue_limit = 100;

function isReadyToPublish() : boolean {
Expand All @@ -27,13 +29,14 @@ export const shoppingAnalyticsSetup = (config : Config = {}) => {
function flushEventQueueIfReady () {
if (isReadyToPublish()) {
for (const params of eventQueue) {
shoppingTracker.send(...params);
shoppingTracker.send(...params, inMemoryIdentity);
}
eventQueue = [];
}
}

function onUserIdentityFetch() {
function onUserIdentityFetch(identity: VisitorInfo) {
inMemoryIdentity = identity;
debugLogger.log('[shopping-analytics:onUserIdentityFetch] Received identity fetch notification.');
identityFetchCompleted = true;
flushEventQueueIfReady();
Expand Down
6 changes: 4 additions & 2 deletions src/lib/shopping-fpti/shopping-event-conversions.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
import type { FptiInput, Config } from '../../types';
import { getDeviceInfo } from '../get-device-info';
import { getIdentity, getUserId } from '../local-storage';
import type { VisitorInfo } from '../../types/user';

import { eventToFptiMapperInit } from './event-handlers';

Expand All @@ -29,12 +30,13 @@ export const eventToFptiConverters = (config : Config) => {

function constructFptiInput(
eventType : EventType,
event : Object
event : Object,
inMemoryIdentity: ?VisitorInfo
) : Object {
const containerSummary = config.containerSummary || {};
const applicationContext = containerSummary.applicationContext || {};
const deviceInfo : any = getDeviceInfo() || {};
const identity : any = getIdentity() || {};
const identity : any = inMemoryIdentity || getIdentity() || {};

const storedUserIds = getStoredUserIds();
const eventFptiAttributes = eventToFptiMapper.eventToFptiAttributes(eventType, event);
Expand Down
5 changes: 3 additions & 2 deletions src/lib/shopping-trackers.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* @flow */
import type { FptiInput, Config } from '../types';
import type { EventType } from '../types/shopping-events';
import type { VisitorInfo } from '../types/user';

import { debugLogger } from './debug-console-logger';
import { trackFpti } from './shopping-fpti/shopping-fpti';
Expand All @@ -12,8 +13,8 @@ import { shoppingAttributes } from './shopping-attributes';
function initGenericEventPublisher(config : Config) : Object {
const convertEvent = eventToFptiConverters(config).eventToFpti;
return {
publishEvent: (event : EventType, payload : Object) => {
const fptiInput : FptiInput = convertEvent(event, payload);
publishEvent: (event : EventType, payload : Object, inMemoryIdentity: VisitorInfo) => {
const fptiInput : FptiInput = convertEvent(event, payload, inMemoryIdentity);
debugLogger.log('[shopping-tracker:publishEvent] Publishing FPTI event:', fptiInput);
trackFpti(fptiInput);
}
Expand Down
3 changes: 2 additions & 1 deletion src/messaging-component.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Tracker } from './tracker-component';
import { checkIfMobile } from './lib/mobile-check';
import { loadJavascript } from './lib/load-js';
import { getCookie, setCookie } from './lib/cookie-utils';
import { readFromLocalStorage } from './lib/local-storage/local-storage-manager';

const museSdkUrl = 'https://www.paypalobjects.com/muse/cart-recovery-0.3/sdk.js';
let userId = '';
Expand All @@ -31,7 +32,7 @@ const showExitModal = ({ cartRecovery }) => {
}
// don't show modal if user has no cart items
// Prefer localStorage first, fallback to cookie (backwards compatibility -- this check can be removed a couple weeks after deploy).
const cart = JSON.parse(window.localStorage.getItem('paypal-cr-cart') || getCookie('paypal-cr-cart') || '{}');
const cart = readFromLocalStorage('paypal-cr-cart') || JSON.parse(getCookie('paypal-cr-cart') || '{}');
if (!cart.items) {
return false;
}
Expand Down
7 changes: 7 additions & 0 deletions src/types/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,10 @@ export type IdentityData = {|
onIdentification : Function,
onError? : Function
|};

export type VisitorInfo= {|
confidenceScore: number,
encryptedAccountNumber: string,
identificationType: string,
country: string
|} | null
3 changes: 2 additions & 1 deletion test/get-property-id.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ global.fetch = jest.fn().mockImplementation(async () => {
jest.mock('@paypal/sdk-client/src', () => {
return {
getMerchantID: jest.fn().mockImplementation(() => [ mockContainer1.owner_id ]),
getSDKQueryParam: jest.fn()
getSDKQueryParam: jest.fn(),
getDisableSetCookie: () => false
};
});

Expand Down
Loading

0 comments on commit 91f020a

Please sign in to comment.