Skip to content

Commit bfbb1de

Browse files
committed
feat: disable session cookie/localStorage when noFunctional is set
1 parent 9235483 commit bfbb1de

4 files changed

Lines changed: 340 additions & 51 deletions

File tree

src/persistence.interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export interface IPersistence {
105105
getUserProductsFromLS(mpid: MPID): Product[];
106106
getAllUserProductsFromLS(): Product[];
107107
setLocalStorage(): void;
108+
setProductStorage(): void;
108109
getLocalStorage(): IPersistenceMinified | null;
109110
expireCookies(cookieName: string): void;
110111
getCookie(): IPersistenceMinified | null;

src/persistence.js

Lines changed: 76 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -39,51 +39,52 @@ export default function _Persistence(mpInstance) {
3939
if (!mpInstance._Store.isLocalStorageAvailable) {
4040
mpInstance._Store.SDKConfig.useCookieStorage = true;
4141
}
42-
43-
// https://go.mparticle.com/work/SQDSDKS-6046
44-
if (mpInstance._Store.isLocalStorageAvailable) {
45-
storage = window.localStorage;
46-
if (mpInstance._Store.SDKConfig.useCookieStorage) {
47-
// For migrating from localStorage to cookies -- If an instance switches from localStorage to cookies, then
48-
// no mParticle cookie exists yet and there is localStorage. Get the localStorage, set them to cookies, then delete the localStorage item.
49-
if (localStorageData) {
50-
if (cookies) {
51-
// https://go.mparticle.com/work/SQDSDKS-6047
52-
allData = mpInstance._Helpers.extend(
53-
false,
54-
localStorageData,
55-
cookies
56-
);
57-
} else {
58-
allData = localStorageData;
59-
}
60-
storage.removeItem(mpInstance._Store.storageName);
61-
} else if (cookies) {
62-
allData = cookies;
63-
}
64-
self.storeDataInMemory(allData);
65-
} else {
66-
// For migrating from cookie to localStorage -- If an instance is newly switching from cookies to localStorage, then
67-
// no mParticle localStorage exists yet and there are cookies. Get the cookies, set them to localStorage, then delete the cookies.
68-
if (cookies) {
42+
if (!mpInstance._Store.getNoFunctional()) {
43+
// https://go.mparticle.com/work/SQDSDKS-6046
44+
if (mpInstance._Store.isLocalStorageAvailable) {
45+
storage = window.localStorage;
46+
if (mpInstance._Store.SDKConfig.useCookieStorage) {
47+
// For migrating from localStorage to cookies -- If an instance switches from localStorage to cookies, then
48+
// no mParticle cookie exists yet and there is localStorage. Get the localStorage, set them to cookies, then delete the localStorage item.
6949
if (localStorageData) {
70-
// https://go.mparticle.com/work/SQDSDKS-6047
71-
allData = mpInstance._Helpers.extend(
72-
false,
73-
localStorageData,
74-
cookies
75-
);
76-
} else {
50+
if (cookies) {
51+
// https://go.mparticle.com/work/SQDSDKS-6047
52+
allData = mpInstance._Helpers.extend(
53+
false,
54+
localStorageData,
55+
cookies
56+
);
57+
} else {
58+
allData = localStorageData;
59+
}
60+
storage.removeItem(mpInstance._Store.storageName);
61+
} else if (cookies) {
7762
allData = cookies;
7863
}
7964
self.storeDataInMemory(allData);
80-
self.expireCookies(mpInstance._Store.storageName);
8165
} else {
82-
self.storeDataInMemory(localStorageData);
66+
// For migrating from cookie to localStorage -- If an instance is newly switching from cookies to localStorage, then
67+
// no mParticle localStorage exists yet and there are cookies. Get the cookies, set them to localStorage, then delete the cookies.
68+
if (cookies) {
69+
if (localStorageData) {
70+
// https://go.mparticle.com/work/SQDSDKS-6047
71+
allData = mpInstance._Helpers.extend(
72+
false,
73+
localStorageData,
74+
cookies
75+
);
76+
} else {
77+
allData = cookies;
78+
}
79+
self.storeDataInMemory(allData);
80+
self.expireCookies(mpInstance._Store.storageName);
81+
} else {
82+
self.storeDataInMemory(localStorageData);
83+
}
8384
}
85+
} else {
86+
self.storeDataInMemory(cookies);
8487
}
85-
} else {
86-
self.storeDataInMemory(cookies);
8788
}
8889

8990
// https://go.mparticle.com/work/SQDSDKS-6048
@@ -114,14 +115,15 @@ export default function _Persistence(mpInstance) {
114115
'Error loading products in initialization: ' + e
115116
);
116117
}
117-
118-
// https://go.mparticle.com/work/SQDSDKS-6046
119-
// Stores all non-current user MPID information into the store
120-
for (var key in allData) {
121-
if (allData.hasOwnProperty(key)) {
122-
if (!SDKv2NonMPIDCookieKeys[key]) {
123-
mpInstance._Store.nonCurrentUserMPIDs[key] =
124-
allData[key];
118+
if (!mpInstance._Store.getNoFunctional()) {
119+
// https://go.mparticle.com/work/SQDSDKS-6046
120+
// Stores all non-current user MPID information into the store
121+
for (var key in allData) {
122+
if (allData.hasOwnProperty(key)) {
123+
if (!SDKv2NonMPIDCookieKeys[key]) {
124+
mpInstance._Store.nonCurrentUserMPIDs[key] =
125+
allData[key];
126+
}
125127
}
126128
}
127129
}
@@ -143,6 +145,10 @@ export default function _Persistence(mpInstance) {
143145

144146
this.update = function() {
145147
if (!mpInstance._Store.webviewBridgeEnabled) {
148+
if (mpInstance._Store.getNoFunctional()) {
149+
self.setProductStorage();
150+
return;
151+
}
146152
if (mpInstance._Store.SDKConfig.useCookieStorage) {
147153
self.setCookie();
148154
}
@@ -326,15 +332,13 @@ export default function _Persistence(mpInstance) {
326332
return parsedDecodedProducts;
327333
};
328334

329-
// https://go.mparticle.com/work/SQDSDKS-6021
330-
this.setLocalStorage = function() {
335+
// Update only the product storage, independent from main persistence writes
336+
this.setProductStorage = function() {
331337
if (!mpInstance._Store.isLocalStorageAvailable) {
332338
return;
333339
}
334340

335-
var key = mpInstance._Store.storageName,
336-
allLocalStorageProducts = self.getAllUserProductsFromLS(),
337-
localStorageData = self.getLocalStorage() || {},
341+
var allLocalStorageProducts = self.getAllUserProductsFromLS(),
338342
currentUser = mpInstance.Identity.getCurrentUser(),
339343
mpid = currentUser ? currentUser.getMPID() : null,
340344
currentUserProducts = {
@@ -356,6 +360,21 @@ export default function _Persistence(mpInstance) {
356360
);
357361
}
358362
}
363+
};
364+
365+
// https://go.mparticle.com/work/SQDSDKS-6021
366+
this.setLocalStorage = function() {
367+
if (!mpInstance._Store.isLocalStorageAvailable) {
368+
return;
369+
}
370+
371+
var key = mpInstance._Store.storageName,
372+
localStorageData = self.getLocalStorage() || {},
373+
currentUser = mpInstance.Identity.getCurrentUser(),
374+
mpid = currentUser ? currentUser.getMPID() : null;
375+
376+
// Always update product storage when setLocalStorage is invoked
377+
self.setProductStorage();
359378

360379
if (!mpInstance._Store.SDKConfig.useCookieStorage) {
361380
localStorageData.gs = localStorageData.gs || {};
@@ -962,6 +981,9 @@ export default function _Persistence(mpInstance) {
962981

963982
// https://go.mparticle.com/work/SQDSDKS-6021
964983
this.savePersistence = function(persistence) {
984+
if (mpInstance._Store.getNoFunctional()) {
985+
return;
986+
}
965987
var encodedPersistence = self.encodePersistence(
966988
JSON.stringify(persistence)
967989
),
@@ -1006,6 +1028,9 @@ export default function _Persistence(mpInstance) {
10061028
};
10071029

10081030
this.getPersistence = function() {
1031+
if (mpInstance._Store.getNoFunctional()) {
1032+
return null;
1033+
}
10091034
var persistence = this.useLocalStorage()
10101035
? this.getLocalStorage()
10111036
: this.getCookie();

test/jest/persistence.spec.ts

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import Store, { IStore } from '../../src/store';
2+
import { IMParticleWebSDKInstance } from '../../src/mp-instance';
3+
import { SDKInitConfig } from '../../src/sdkRuntimeModels';
4+
5+
describe('Persistence writers', () => {
6+
let store: IStore;
7+
let mockMPInstance: IMParticleWebSDKInstance;
8+
9+
beforeEach(() => {
10+
mockMPInstance = {
11+
_Helpers: {
12+
createMainStorageName: () => 'mprtcl-v4_ws',
13+
createProductStorageName: () => 'mprtcl-prodv4_ws',
14+
Validators: { isFunction: () => true },
15+
extend: Object.assign,
16+
},
17+
_NativeSdkHelpers: {
18+
isWebviewEnabled: () => false,
19+
},
20+
_Persistence: {
21+
setCookie: jest.fn(),
22+
setLocalStorage: jest.fn(),
23+
setProductStorage: jest.fn(),
24+
update: function () {
25+
if (store.webviewBridgeEnabled) {
26+
return;
27+
}
28+
if (store.getNoFunctional()) {
29+
mockMPInstance._Persistence.setProductStorage();
30+
return;
31+
}
32+
if (store.SDKConfig.useCookieStorage) {
33+
mockMPInstance._Persistence.setCookie();
34+
}
35+
mockMPInstance._Persistence.setLocalStorage();
36+
},
37+
},
38+
Logger: {
39+
verbose: () => {},
40+
warning: () => {},
41+
error: () => {},
42+
},
43+
Identity: {
44+
getCurrentUser: () => ({ getMPID: () => 'mpid' }),
45+
},
46+
} as unknown as IMParticleWebSDKInstance;
47+
48+
store = {} as IStore;
49+
Store.call(store, {} as SDKInitConfig, mockMPInstance, 'apikey');
50+
});
51+
52+
describe('#noFunctional', () => {
53+
describe('true', () => {
54+
beforeEach(() => {
55+
store.setNoFunctional(true);
56+
store.webviewBridgeEnabled = false;
57+
});
58+
59+
it('should NOT write to cookie when useCookieStorage = true', () => {
60+
store.SDKConfig.useCookieStorage = true;
61+
jest.clearAllMocks();
62+
63+
mockMPInstance._Persistence.update();
64+
65+
expect(mockMPInstance._Persistence.setCookie).not.toHaveBeenCalled();
66+
expect(mockMPInstance._Persistence.setLocalStorage).not.toHaveBeenCalled();
67+
expect(mockMPInstance._Persistence.setProductStorage).toHaveBeenCalled();
68+
});
69+
70+
it('should NOT write to localStorage when useCookieStorage = false', () => {
71+
store.SDKConfig.useCookieStorage = false;
72+
jest.clearAllMocks();
73+
74+
mockMPInstance._Persistence.update();
75+
76+
expect(mockMPInstance._Persistence.setCookie).not.toHaveBeenCalled();
77+
expect(mockMPInstance._Persistence.setLocalStorage).not.toHaveBeenCalled();
78+
expect(mockMPInstance._Persistence.setProductStorage).toHaveBeenCalled();
79+
});
80+
});
81+
82+
describe('false', () => {
83+
beforeEach(() => {
84+
store.setNoFunctional(false);
85+
store.webviewBridgeEnabled = false;
86+
});
87+
88+
it('should write to cookie when useCookieStorage = true', () => {
89+
store.SDKConfig.useCookieStorage = true;
90+
jest.clearAllMocks();
91+
92+
mockMPInstance._Persistence.update();
93+
94+
expect(mockMPInstance._Persistence.setCookie).toHaveBeenCalled();
95+
expect(mockMPInstance._Persistence.setLocalStorage).toHaveBeenCalled();
96+
expect(mockMPInstance._Persistence.setProductStorage).not.toHaveBeenCalled();
97+
});
98+
99+
it('should write to localStorage when useCookieStorage = false', () => {
100+
store.SDKConfig.useCookieStorage = false;
101+
jest.clearAllMocks();
102+
103+
mockMPInstance._Persistence.update();
104+
105+
expect(mockMPInstance._Persistence.setCookie).not.toHaveBeenCalled();
106+
expect(mockMPInstance._Persistence.setLocalStorage).toHaveBeenCalled();
107+
expect(mockMPInstance._Persistence.setProductStorage).not.toHaveBeenCalled();
108+
});
109+
});
110+
111+
describe('default (false)', () => {
112+
beforeEach(() => {
113+
// default is false
114+
store.webviewBridgeEnabled = false;
115+
});
116+
117+
it('should write to cookie by default when useCookieStorage = true', () => {
118+
store.SDKConfig.useCookieStorage = true;
119+
jest.clearAllMocks();
120+
121+
mockMPInstance._Persistence.update();
122+
123+
expect(store.getNoFunctional()).toBe(false);
124+
expect(mockMPInstance._Persistence.setCookie).toHaveBeenCalled();
125+
expect(mockMPInstance._Persistence.setLocalStorage).toHaveBeenCalled();
126+
expect(mockMPInstance._Persistence.setProductStorage).not.toHaveBeenCalled();
127+
});
128+
129+
it('should write to localStorage by default when useCookieStorage = false', () => {
130+
store.SDKConfig.useCookieStorage = false;
131+
jest.clearAllMocks();
132+
133+
mockMPInstance._Persistence.update();
134+
135+
expect(store.getNoFunctional()).toBe(false);
136+
expect(mockMPInstance._Persistence.setCookie).not.toHaveBeenCalled();
137+
expect(mockMPInstance._Persistence.setLocalStorage).toHaveBeenCalled();
138+
expect(mockMPInstance._Persistence.setProductStorage).not.toHaveBeenCalled();
139+
});
140+
});
141+
142+
it('should NOT write to storage when webviewBridgeEnabled = true', () => {
143+
store.setNoFunctional(false);
144+
store.webviewBridgeEnabled = true;
145+
store.SDKConfig.useCookieStorage = true;
146+
jest.clearAllMocks();
147+
148+
mockMPInstance._Persistence.update();
149+
150+
expect(mockMPInstance._Persistence.setCookie).not.toHaveBeenCalled();
151+
expect(mockMPInstance._Persistence.setLocalStorage).not.toHaveBeenCalled();
152+
expect(mockMPInstance._Persistence.setProductStorage).not.toHaveBeenCalled();
153+
});
154+
});
155+
});

0 commit comments

Comments
 (0)