Skip to content

Commit

Permalink
Fixed #4: Removing cookies are failing when the domain or path were s…
Browse files Browse the repository at this point in the history
…et in the options
  • Loading branch information
jherax committed Apr 21, 2017
1 parent 9d8600f commit 2e70276
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 46 deletions.
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,10 +339,37 @@ cookieStore.setItem('testing3', 3, {
});
```

**Important**: Take into account that if you want to modify or remove a cookie
that was created with a specific `path` or `domain` / subdomain, you need to
explicitate the domain attribute in `setItem(key, value, options)`.

![cookies](https://www.dropbox.com/s/wlvgm0t8xc07me1/cookies-metadata.gif?dl=1)

If you have created the cookie with **proxyStorage**, it will handle the
metadata internally, so that you can call `removeItem(key)` safely.

But if you want to modify / remove a cookie that was created from another page,
then you should provide the metadata as `path` or `domain` in order to match
the right cookie:

```javascript
// change the value of an external cookie in /answers
cookieStore.setItem('landedAnswers', 999, {
path: '/answers',
});

// remove an external cookie in a subdomain
cookieStore.setItem('optimizelyEndUserId', '', {
domain: '.healthcare.org',
expires: {days: -1}, // trick!
});
```

### Looping the storage

You can loop over the items in the storage instance, e.g.
`localStorage`, `sessionStorage`, `cookieStorage`, or `memoryStorage`.
`localStorage`, `sessionStorage`, `cookieStorage`, or `memoryStorage`,
but it is not a good practice, see the notes below.

```javascript
const sessionStore = new WebStorage('sessionStorage');
Expand All @@ -361,6 +388,23 @@ for (let key in sessionStore) {
}
```

**Important**: Although you can loop over the storage items, it is
recommended to use the API methods instead, this is because navigable
items in the storage instance are not synchronized for external changes,
e.g. a domain cookie was created from another page, or a cookie has expired.

```javascript
// not recommended, they are not synchronized
var title = cookieStorage['title'];
var session = cookieStorage.sessionId;
cookieStorage['sessionId'] = 'E6URTG5';

// the good way, it tracks external changes
var title = cookieStorage.getItem('title');
var session = cookieStorage.getItem('sessionId');
cookieStorage.setItem('sessionId', 'E6URTG5');
```

### Clearing data

You can use the `removeItem(key)` method to delete a specific item in
Expand Down
52 changes: 30 additions & 22 deletions dist/proxy-storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ function executeInterceptors(command) {
}
return _interceptors[command].reduce(function (val, action) {
var transformed = action.apply(undefined, [key, val].concat(args));
if (transformed === undefined) return val;
if (transformed == null) return val;
return transformed;
}, value);
}
Expand Down Expand Up @@ -379,7 +379,10 @@ var WebStorage = function () {
var v = executeInterceptors('setItem', key, value, options);
if (v !== undefined) value = v;
this[key] = value;
value = JSON.stringify(value);
// prevents converting strings to JSON to avoid extra quotes
if (typeof value !== 'string') value = JSON.stringify(value);
// TODO: should add setTimeout for options.expires?
// TODO: prevent adding cookies when the domain or path are not valid?
_proxyMechanism.proxy[this.__storage__].setItem(key, value, options);
}

Expand Down Expand Up @@ -520,8 +523,8 @@ var $cookie = {
},
set: function set(value) {
document.cookie = value;
}
};
},
data: {} };

/**
* @private
Expand All @@ -536,9 +539,14 @@ var $cookie = {
/* eslint-disable no-invalid-this */
function buildExpirationString(date) {
var expires = date instanceof Date ? (0, _utils.alterDate)({ date: date }) : (0, _utils.alterDate)(date);
return '; expires=' + expires.toUTCString();
return expires.toUTCString();
}

// @private
var buildStringFor = function buildStringFor(key, data) {
return data[key] && '; ' + key + '=' + data[key] || '';
};

/**
* @private
*
Expand All @@ -564,24 +572,21 @@ function findCookie(cookie) {
function cookieStorage() {
var api = {
setItem: function setItem(key, value, options) {
var domain = '',
expires = '';
options = Object.assign({ path: '/' }, options);
// keep track of the metadata associated to the cookie
$cookie.data[key] = { path: options.path };
var metadata = $cookie.data[key];
if ((0, _utils.isObject)(options.expires) || options.expires instanceof Date) {
expires = buildExpirationString(options.expires);
metadata.expires = buildExpirationString(options.expires);
}
// http://stackoverflow.com/a/5671466/2247494
if (typeof options.domain === 'string') {
domain = '; domain=' + options.domain.trim();
if (options.domain && typeof options.domain === 'string') {
metadata.domain = options.domain.trim();
}
var cookie = key + '=' + encodeURIComponent(value) + expires + domain + '; path=' + options.path;
// TODO: add metadata to store options for the cookie
// TODO: remove cookies are failing when domain or path were set
// TODO: prevent adding cookies when the domain or path are not valid
// TODO: remove expired cookies through getItem or setTimeout for expires
// console.log('before set', $cookie.get()); // eslint-disable-line
var expires = buildStringFor('expires', metadata);
var domain = buildStringFor('domain', metadata);
var path = buildStringFor('path', metadata);
var cookie = key + '=' + encodeURIComponent(value) + expires + domain + path;
$cookie.set(cookie);
// console.log('after set', $cookie.get()); // eslint-disable-line
},
getItem: function getItem(key) {
var value = null;
Expand All @@ -592,17 +597,20 @@ function cookieStorage() {
value = cookie.trim().substring(nameEQ.length, cookie.length);
value = decodeURIComponent(value);
}
if (value === null) delete $cookie.data[key];
return value;
},
removeItem: function removeItem(key) {
api.setItem(key, '', { expires: { days: -1 } });
var metadata = Object.assign({}, $cookie.data[key]);
metadata.expires = { days: -1 };
api.setItem(key, '', metadata);
delete $cookie.data[key];
},
clear: function clear() {
var eq = '=';
var key = void 0,
indexEQ = void 0;
indexEQ = void 0; // eslint-disable-line
$cookie.get().split(';').forEach(function (cookie) {
indexEQ = cookie.indexOf(eq);
indexEQ = cookie.indexOf('=');
if (indexEQ > -1) {
key = cookie.substring(0, indexEQ);
// prevent leading spaces before the key
Expand Down
Loading

0 comments on commit 2e70276

Please sign in to comment.