Skip to content

Commit edb2e61

Browse files
authored
feat: disable session cookie/localStorage when noFunctional is set (#1070)
1 parent 3a0643b commit edb2e61

File tree

4 files changed

+274
-1
lines changed

4 files changed

+274
-1
lines changed

jest.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,14 @@ module.exports = {
44
// The built mParticle.js file needs to exist for integration tests
55
setupFiles: ['./dist/mparticle.js'],
66
setupFilesAfterEnv: ['jest-expect-message'],
7+
transform: {
8+
'^.+\\.(js)$': 'ts-jest',
9+
},
10+
globals: {
11+
'ts-jest': {
12+
tsconfig: {
13+
allowJs: true,
14+
},
15+
},
16+
},
717
};

src/persistence.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export default function _Persistence(mpInstance) {
3535
mpInstance._Store.isFirstRun = false;
3636
}
3737

38+
if (mpInstance._Store.getPrivacyFlag('SDKState')) {
39+
return;
40+
}
41+
3842
// https://go.mparticle.com/work/SQDSDKS-6045
3943
if (!mpInstance._Store.isLocalStorageAvailable) {
4044
mpInstance._Store.SDKConfig.useCookieStorage = true;
@@ -142,7 +146,10 @@ export default function _Persistence(mpInstance) {
142146
};
143147

144148
this.update = function() {
145-
if (!mpInstance._Store.webviewBridgeEnabled) {
149+
if (
150+
!mpInstance._Store.webviewBridgeEnabled &&
151+
!mpInstance._Store.getPrivacyFlag('SDKState')
152+
) {
146153
if (mpInstance._Store.SDKConfig.useCookieStorage) {
147154
self.setCookie();
148155
}
@@ -962,6 +969,9 @@ export default function _Persistence(mpInstance) {
962969

963970
// https://go.mparticle.com/work/SQDSDKS-6021
964971
this.savePersistence = function(persistence) {
972+
if (mpInstance._Store.getPrivacyFlag('SDKState')) {
973+
return;
974+
}
965975
var encodedPersistence = self.encodePersistence(
966976
JSON.stringify(persistence)
967977
),
@@ -1006,6 +1016,9 @@ export default function _Persistence(mpInstance) {
10061016
};
10071017

10081018
this.getPersistence = function() {
1019+
if (mpInstance._Store.getPrivacyFlag('SDKState')) {
1020+
return null;
1021+
}
10091022
var persistence = this.useLocalStorage()
10101023
? this.getLocalStorage()
10111024
: this.getCookie();

test/jest/persistence.spec.ts

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

test/src/tests-persistence.ts

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1948,4 +1948,90 @@ describe('persistence', () => {
19481948
user2.getAllUserAttributes()['ua-list'][1].should.equal('<b>');
19491949
user2.getAllUserAttributes()['ua-1'].should.equal('a');
19501950
});
1951+
1952+
describe('noFunctional privacy flag', () => {
1953+
beforeEach(() => {
1954+
mParticle._resetForTests(MPConfig);
1955+
});
1956+
1957+
describe('set to true', () => {
1958+
beforeEach(() => {
1959+
mParticle.config.launcherOptions = { noFunctional: true };
1960+
});
1961+
1962+
it('should NOT store cookie when useCookieStorage = true', async () => {
1963+
mParticle.config.useCookieStorage = true;
1964+
1965+
mParticle.init(apiKey, mParticle.config);
1966+
await waitForCondition(hasIdentifyReturned);
1967+
1968+
mParticle.getInstance()._Persistence.update();
1969+
1970+
expect(findCookie()).to.not.be.ok;
1971+
});
1972+
1973+
it('should NOT write localStorage when useCookieStorage = false', async () => {
1974+
mParticle.config.useCookieStorage = false;
1975+
1976+
mParticle.init(apiKey, mParticle.config);
1977+
await waitForCondition(hasIdentifyReturned);
1978+
1979+
mParticle.getInstance()._Persistence.update();
1980+
1981+
expect(getLocalStorage()).to.not.be.ok;
1982+
});
1983+
});
1984+
1985+
describe('set to false', () => {
1986+
beforeEach(() => {
1987+
mParticle.config.launcherOptions = { noFunctional: false };
1988+
});
1989+
1990+
it('should store cookie when useCookieStorage = true', async () => {
1991+
mParticle.config.useCookieStorage = true;
1992+
1993+
mParticle.init(apiKey, mParticle.config);
1994+
await waitForCondition(hasIdentifyReturned);
1995+
1996+
mParticle.getInstance()._Persistence.update();
1997+
1998+
expect(findCookie()).to.be.ok;
1999+
});
2000+
2001+
it('should store localStorage when useCookieStorage = false', async () => {
2002+
mParticle.config.useCookieStorage = false;
2003+
2004+
mParticle.init(apiKey, mParticle.config);
2005+
await waitForCondition(hasIdentifyReturned);
2006+
2007+
mParticle.getInstance()._Persistence.update();
2008+
2009+
expect(getLocalStorage()).to.be.ok;
2010+
});
2011+
});
2012+
2013+
describe('is false by default', () => {
2014+
it('should store cookie when useCookieStorage = true', async () => {
2015+
mParticle.config.useCookieStorage = true;
2016+
2017+
mParticle.init(apiKey, mParticle.config);
2018+
await waitForCondition(hasIdentifyReturned);
2019+
2020+
mParticle.getInstance()._Persistence.update();
2021+
2022+
expect(findCookie()).to.be.ok;
2023+
});
2024+
2025+
it('should store localStorage when useCookieStorage = false', async () => {
2026+
mParticle.config.useCookieStorage = false;
2027+
2028+
mParticle.init(apiKey, mParticle.config);
2029+
await waitForCondition(hasIdentifyReturned);
2030+
2031+
mParticle.getInstance()._Persistence.update();
2032+
2033+
expect(getLocalStorage()).to.be.ok;
2034+
});
2035+
});
2036+
});
19512037
});

0 commit comments

Comments
 (0)