Skip to content

Commit 67b49af

Browse files
author
Krishna Rajendran
authored
Add a same site cookie option (#246)
1 parent 662a9dc commit 67b49af

File tree

8 files changed

+90
-2
lines changed

8 files changed

+90
-2
lines changed

src/amplitude-client.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ AmplitudeClient.prototype.init = function init(apiKey, opt_userId, opt_config, o
9898
expirationDays: this.options.cookieExpiration,
9999
domain: this.options.domain,
100100
secure: this.options.secureCookie,
101+
sameSite: this.options.sameSiteCookie
101102
});
102103
this.options.domain = this.cookieStorage.options().domain;
103104

@@ -786,7 +787,8 @@ AmplitudeClient.prototype.setDomain = function setDomain(domain) {
786787
this.cookieStorage.options({
787788
expirationDays: this.options.cookieExpiration,
788789
secure: this.options.secureCookie,
789-
domain: domain
790+
domain: domain,
791+
sameSite: this.options.sameSiteCookie
790792
});
791793
this.options.domain = this.cookieStorage.options().domain;
792794
_loadCookieData(this);

src/base-cookie.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ const set = (name, value, opts) => {
3939
if (opts.secure) {
4040
str += '; Secure';
4141
}
42-
str += '; SameSite=Lax';
42+
if (opts.sameSite) {
43+
str += '; SameSite=' + opts.sameSite;
44+
}
4345
document.cookie = str;
4446
};
4547

src/cookie.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ var options = function(opts) {
7070

7171
_options.expirationDays = opts.expirationDays;
7272
_options.secure = opts.secure;
73+
_options.sameSite = opts.sameSite;
7374

7475
var domain = (!utils.isEmptyString(opts.domain)) ? opts.domain : '.' + topDomain(getLocation().href);
7576
var token = Math.random();

src/options.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export default {
1616
batchEvents: false,
1717
cookieExpiration: 365 * 10,
1818
cookieName: 'amplitude_id',
19+
sameSiteCookie: 'None',
1920
deviceIdFromUrlParam: false,
2021
domain: '',
2122
eventUploadPeriodMillis: 30 * 1000, // 30s

test/amplitude-client.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import queryString from 'query-string';
99
import Identify from '../src/identify.js';
1010
import Revenue from '../src/revenue.js';
1111
import constants from '../src/constants.js';
12+
import { mockCookie, restoreCookie, getCookie } from './mock-cookie';
1213

1314
// maintain for testing backwards compatability
1415
describe('AmplitudeClient', function() {
@@ -34,6 +35,7 @@ describe('AmplitudeClient', function() {
3435
function reset() {
3536
localStorage.clear();
3637
sessionStorage.clear();
38+
restoreCookie();
3739
cookie.remove(amplitude.options.cookieName);
3840
cookie.remove(amplitude.options.cookieName + keySuffix);
3941
cookie.remove(amplitude.options.cookieName + '_new_app');
@@ -74,6 +76,24 @@ describe('AmplitudeClient', function() {
7476
assert.ok(onInitCalled);
7577
});
7678

79+
it('should set the Secure flag on cookie with the secureCookie option', () => {
80+
mockCookie();
81+
amplitude.init(apiKey, null, { secureCookie: true });
82+
assert.include(getCookie('amplitude_id_' + apiKey).options, 'Secure');
83+
});
84+
85+
it('should set the SameSite cookie option to None by default', () => {
86+
mockCookie();
87+
amplitude.init(apiKey);
88+
assert.include(getCookie('amplitude_id_' + apiKey).options, 'SameSite=None');
89+
});
90+
91+
it('should set the sameSite option on a cookie with the sameSiteCookie Option', () => {
92+
mockCookie();
93+
amplitude.init(apiKey, null, {sameSiteCookie: 'Strict'});
94+
assert.include(getCookie('amplitude_id_' + apiKey).options, 'SameSite=Strict');
95+
});
96+
7797
it('should immediately invoke onInit callbacks if already initialized', function() {
7898
let onInitCalled = false;
7999
amplitude.init(apiKey);
@@ -3352,6 +3372,7 @@ describe('setVersionName', function() {
33523372
assert.lengthOf(server.requests, 1, 'should have sent a request to Amplitude');
33533373
assert.equal(events[0].event_type, '$identify');
33543374
});
3375+
33553376
describe('prior to opting into analytics', function () {
33563377
beforeEach(function () {
33573378
reset();

test/base-cookie.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import cookie from '../src/base-cookie';
2+
import { mockCookie, restoreCookie, getCookie } from './mock-cookie';
3+
4+
describe('cookie', function() {
5+
beforeEach(() => {
6+
mockCookie();
7+
})
8+
9+
afterEach(() => {
10+
restoreCookie();
11+
});
12+
13+
describe('set', () => {
14+
it('should set the secure flag with the secure option', () => {
15+
cookie.set('key', 'val', {secure: true});
16+
assert.include(getCookie('key').options, 'Secure');
17+
})
18+
19+
it('should set the same site value with the sameSite option', () => {
20+
cookie.set('key', 'val', {sameSite: "Lax"});
21+
assert.include(getCookie('key').options, 'SameSite=Lax');
22+
})
23+
})
24+
});

test/mock-cookie.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
let rawCookieData = {};
2+
3+
let isMocked = false;
4+
5+
export const mockCookie = () => {
6+
isMocked = true;
7+
8+
document.__defineGetter__('cookie', function () {
9+
return Object.keys(rawCookieData).map(key => `${key}=${rawCookieData[key].val}`).join(";");
10+
});
11+
12+
document.__defineSetter__('cookie', function (str) {
13+
const indexEquals = str.indexOf("=");
14+
const key = str.substr(0, indexEquals);
15+
const remainingStr = str.substring(str + 1);
16+
const splitSemi = remainingStr.split(';').map((str)=> str.trim());
17+
18+
rawCookieData[key] = {
19+
val: splitSemi[0],
20+
options: splitSemi.slice(1)
21+
};
22+
return str;
23+
});
24+
};
25+
26+
export const restoreCookie = () => {
27+
if (isMocked) {
28+
delete document['cookie'];
29+
rawCookieData = {};
30+
isMocked = false;
31+
}
32+
};
33+
34+
export const getCookie = (key) => {
35+
return rawCookieData[key];
36+
};

test/tests.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ import './amplitude.js';
1111
import './amplitude-client.js';
1212
import './utils.js';
1313
import './revenue.js';
14+
import './base-cookie.js';

0 commit comments

Comments
 (0)