Skip to content

Commit

Permalink
Merge pull request #270 from auth0/cookie-fallback
Browse files Browse the repository at this point in the history
Cookie fallback for storage
  • Loading branch information
hzalaz authored Dec 16, 2016
2 parents 48cc54a + 6962ff2 commit 4193686
Show file tree
Hide file tree
Showing 9 changed files with 447 additions and 11 deletions.
58 changes: 58 additions & 0 deletions src/helper/cookies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
var windowHandler = require('./window');
var base64Url = require('./base64_url');

function create(name, value, days) {
var date;
var expires;

if (windowHandler.getDocument().cookie === undefined
|| windowHandler.getDocument().cookie === null) {
throw new Error('cookie storage not available');
}

if (days) {
date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = '; expires=' + date.toGMTString();
} else {
expires = '';
}

windowHandler.getDocument().cookie = name + '=' + base64Url.encode(value) + expires + '; path=/';
}

function read(name) {
var i;
var cookie;
var cookies;
var nameEQ = name + '=';

if (windowHandler.getDocument().cookie === undefined
|| windowHandler.getDocument().cookie === null) {
throw new Error('cookie storage not available');
}

cookies = windowHandler.getDocument().cookie.split(';');

for (i = 0; i < cookies.length; i++) {
cookie = cookies[i];
while (cookie.charAt(0) === ' ') {
cookie = cookie.substring(1, cookie.length);
}
if (cookie.indexOf(nameEQ) === 0) {
return base64Url.decode(cookie.substring(nameEQ.length, cookie.length));
}
}

return null;
}

function erase(name) {
create(name, '', -1);
}

module.exports = {
create: create,
read: read,
erase: erase
};
20 changes: 11 additions & 9 deletions src/helper/storage.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
var windowHandler = require('./window');
var StorageHandler = require('./storage/handler');
var storage;

function DummyStorage() {}
DummyStorage.prototype.getItem = function (key) { return null; };
DummyStorage.prototype.removeItem = function (key) {};
DummyStorage.prototype.setItem = function (key, value) {};

function getStorage() {
return windowHandler.getWindow().localStorage || new DummyStorage();
function getStorage(force) {
if (!storage || force) {
storage = new StorageHandler();
}
return storage;
}

module.exports = {
getItem: function (key) {
var value = getStorage().getItem(key);
return JSON.parse(value);
return value ? JSON.parse(value) : value;
},
removeItem: function (key) {
return getStorage().removeItem(key);
},
setItem: function (key, value) {
var json = JSON.stringify(value);
return getStorage().setItem(key, json);
},
reload: function() {
getStorage(true);
}
};
18 changes: 18 additions & 0 deletions src/helper/storage/cookie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
var windowHandler = require('../window');
var cookies = require('../cookies');

function CookieStorage() {}

CookieStorage.prototype.getItem = function (key) {
return cookies.read(key);
};

CookieStorage.prototype.removeItem = function (key) {
cookies.erase(key);
};

CookieStorage.prototype.setItem = function (key, value) {
cookies.create(key, value, 1);
};

module.exports = CookieStorage;
9 changes: 9 additions & 0 deletions src/helper/storage/dummy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function DummyStorage() {}

DummyStorage.prototype.getItem = function (key) { return null; };

DummyStorage.prototype.removeItem = function (key) {};

DummyStorage.prototype.setItem = function (key, value) {};

module.exports = DummyStorage;
54 changes: 54 additions & 0 deletions src/helper/storage/handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
var windowHandler = require('../window');
var DummyStorage = require('./dummy');
var CookieStorage = require('./cookie');
var Warn = require('../warn');

function StorageHandler() {
this.warn = new Warn({});
this.storage = windowHandler.getWindow().localStorage || new CookieStorage();
}

StorageHandler.prototype.failover = function () {
if (this.storage instanceof DummyStorage) {
this.warn.warning('DummyStorage: ignore failover');
return;
} else if (this.storage instanceof CookieStorage) {
this.warn.warning('CookieStorage: failing over DummyStorage');
this.storage = new DummyStorage();
} else {
this.warn.warning('LocalStorage: failing over CookieStorage');
this.storage = new CookieStorage();
}
};

StorageHandler.prototype.getItem = function (key) {
try {
return this.storage.getItem(key);
} catch (e) {
this.warn.warning(e);
this.failover();
return this.getItem(key);
}
};

StorageHandler.prototype.removeItem = function (key) {
try {
return this.storage.removeItem(key);
} catch (e) {
this.warn.warning(e);
this.failover();
return this.removeItem(key);
}
};

StorageHandler.prototype.setItem = function (key, value) {
try {
return this.storage.setItem(key, value);
} catch (e) {
this.warn.warning(e);
this.failover();
return this.setItem(key, value);
}
};

module.exports = StorageHandler;
108 changes: 108 additions & 0 deletions test/helper/cookies.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
var expect = require('expect.js');
var stub = require('sinon').stub;

var windowHandler = require('../../src/helper/window');
var cookies = require('../../src/helper/cookies');

describe('helpers cookies', function () {

beforeEach(function(){
var document = {
cookie: ''
}

stub(windowHandler, 'getDocument', function (message) {
return document;
});
stub(Date.prototype, 'getTime', function (message) {
return 0;
});
})

afterEach(function(){
windowHandler.getDocument.restore();
Date.prototype.getTime.restore();
})

it('create a cookie with exp', function () {

cookies.create('cookie_name', 'cookie value', 1);
expect(windowHandler.getDocument().cookie).to.be.eql('cookie_name=Y29va2llIHZhbHVl; expires=Fri, 02 Jan 1970 00:00:00 GMT; path=/')

});

it('create a cookie without exp', function () {

cookies.create('cookie_name', 'cookie value');
expect(windowHandler.getDocument().cookie).to.be.eql('cookie_name=Y29va2llIHZhbHVl; path=/')

});

it('returns null if the cookie does not exist', function () {

var value = cookies.read('cookie_name');
expect(value).to.be.eql(null);

});

it('returns the cookie value', function () {

cookies.create('cookie_name', 'cookie value');
expect(windowHandler.getDocument().cookie).to.be.eql('cookie_name=Y29va2llIHZhbHVl; path=/')

var value = cookies.read('cookie_name');
expect(value).to.be.eql('cookie value')

});


it('should handle multiple cookies', function () {

windowHandler.getDocument.restore();
stub(windowHandler, 'getDocument', function (message) {
return {
cookie: 'cookie_name=Y29va2llIHZhbHVl; path=/; cookie_name2=Y29va2llIHZhbHVlMg; path=/'
};
});

var value = cookies.read('cookie_name2');
expect(value).to.be.eql('cookie value2')
});

it('returns the cookie value (with ;)', function () {

cookies.create('cookie_name', 'cookie; value');
expect(windowHandler.getDocument().cookie).to.be.eql('cookie_name=Y29va2llOyB2YWx1ZQ; path=/')

var value = cookies.read('cookie_name');
expect(value).to.be.eql('cookie; value')

});

it('should reset the expiration', function () {

cookies.create('cookie_name', 'cookie; value');
expect(windowHandler.getDocument().cookie).to.be.eql('cookie_name=Y29va2llOyB2YWx1ZQ; path=/')

cookies.erase('cookie_name');

expect(windowHandler.getDocument().cookie).to.be.eql('cookie_name=; expires=Wed, 31 Dec 1969 00:00:00 GMT; path=/')
});

it('handle cookie not available', function () {

windowHandler.getDocument.restore();
stub(windowHandler, 'getDocument', function (message) {
return {};
});
expect(function () {
cookies.create('cookie_name', 'cookie; value');
}).to.throwError();

expect(function () {
cookies.read('cookie_name');
}).to.throwError();

});

});
Loading

0 comments on commit 4193686

Please sign in to comment.