Giter Club home page Giter Club logo

cross-storage's Introduction

cross-storage

Cross domain local storage, with permissions. Enables multiple browser windows/tabs, across a variety of domains, to share a single localStorage. Features an API using ES6 promises.

Build Status

Overview

The library is a convenient alternative to sharing a root domain cookie. Unlike cookies, your client-side data isn't limited to a few kilobytes - you get a guaranteed 2.49Mb. For a client-heavy application, you can potentially shave a few KB off your request headers by avoiding cookies. This is all thanks to LocalStorage, which is available in IE 8+, FF 3.5+, Chrome 4+, as well as a majority of mobile browsers. For a list of compatible browsers, refer to caniuse.

How does it work? The library is divided into two types of components: hubs and clients. The hubs reside on a host of choice and interact directly with the LocalStorage API. The clients then load said hub over an embedded iframe and post messages, requesting data to be stored, retrieved, and deleted. This allows multiple clients to access and share the data located in a single store.

Care should be made to limit the origins of the bidirectional communication. As such, when initializing the hub, an array of permissions objects is passed. Any messages from clients whose origin does not match the pattern are ignored, as well as those not within the allowed set of methods. The set of permissions are enforced thanks to the same-origin policy. However, keep in mind that any user has full control of their local storage data - it's still client data. This only restricts access on a per-domain or web app level.

Hub

// Config s.t. subdomains can get, but only the root domain can set and del
CrossStorageHub.init([
  {origin: /\.example.com$/,        allow: ['get']},
  {origin: /:(www\.)?example.com$/, allow: ['get', 'set', 'del']}
]);

Note the $ for matching the end of the string. The RegExps in the above example will match origins such as valid.example.com, but not invalid.example.com.malicious.com.

Client

var storage = new CrossStorageClient('https://store.example.com/hub.html');

storage.onConnect().then(function() {
  // Set a key with a TTL of 90 seconds
  return storage.set('newKey', 'foobar', 90000);
}).then(function() {
  return storage.get('existingKey', 'newKey');
}).then(function(res) {
  console.log(res.length); // 2
}).catch(function(err) {
  // Handle error
});

Installation

The library can be installed via bower:

bower install cross-storage

Or using npm:

npm install cross-storage

When serving the hub, you may want to set the CORS and CSP headers for your server depending on client/hub location. For example:

{
  'Access-Control-Allow-Origin':  '*',
  'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE',
  'Access-Control-Allow-Headers': 'X-Requested-With',
  'Content-Security-Policy':      "default-src 'unsafe-inline' *",
  'X-Content-Security-Policy':    "default-src 'unsafe-inline' *",
  'X-WebKit-CSP':                 "default-src 'unsafe-inline' *",
}

If using inline JS to create the hub, you'll need to specify unsafe-inline for the CSP headers. Otherwise, it can be left out if simply including the init code via another resource.

API

CrossStorageHub.init(permissions)

Accepts an array of objects with two keys: origin and allow. The value of origin is expected to be a RegExp, and allow, an array of strings. The cross storage hub is then initialized to accept requests from any of the matching origins, allowing access to the associated lists of methods. Methods may include any of: get, set, del, and getKeys. A 'ready' message is sent to the parent window once complete.

CrossStorageHub.init([
  {origin: /localhost:3000$/, allow: ['get', 'set', 'del', 'getKeys']}
]);

new CrossStorageClient(url, [opts])

Constructs a new cross storage client given the url to a hub. By default, an iframe is created within the document body that points to the url. It also accepts an options object, which may include a timeout and frameId. The timeout, in milliseconds, is applied to each request and defaults to 3000ms. The options object may also include a frameId, identifying an existing frame on which to install its listeners.

var storage = new CrossStorageClient('http://localhost:3000/hub.html');

var storage = new CrossStorageClient('http://localhost:3000/hub.html', {
  timeout: 5000,
  frameId: 'storageFrame'
});

CrossStorageClient.prototype.onConnect()

Returns a promise that is fulfilled when a connection has been established with the cross storage hub. Its use is recommended to avoid sending any requests prior to initialization being complete.

storage.onConnect().then(function() {
  // ready!
});

CrossStorageClient.prototype.set(key, value, [ttl])

Sets a key to the specified value, optionally accepting a ttl to passively expire the key after a number of milliseconds. Returns a promise that is fulfilled on success, or rejected if any errors setting the key occurred, or the request timed out.

storage.onConnect().then(function() {
  return storage.set('key', {foo: 'bar'});
}).then(function() {
  return storage.set('expiringKey', 'foobar', 10000);
});

CrossStorageClient.prototype.get(key1, [key2], [...])

Accepts one or more keys for which to retrieve their values. Returns a promise that is settled on hub response or timeout. On success, it is fulfilled with the value of the key if only passed a single argument. Otherwise it's resolved with an array of values. On failure, it is rejected with the corresponding error message.

storage.onConnect().then(function() {
  return storage.get('key1');
}).then(function(res) {
  return storage.get('key1', 'key2', 'key3');
}).then(function(res) {
  // ...
});

CrossStorageClient.prototype.del(key1, [key2], [...])

Accepts one or more keys for deletion. Returns a promise that is settled on hub response or timeout.

storage.onConnect().then(function() {
  return storage.del('key1', 'key2');
});

CrossStorageClient.prototype.getKeys()

Returns a promise that, when resolved, passes an array of keys currently in storage.

storage.onConnect().then(function() {
  return storage.getKeys();
}).then(function(keys) {
  // ['key1', 'key2', ...]
});

CrossStorageClient.prototype.close()

Deletes the iframe and sets the connected state to false. The client can no longer be used after being invoked.

storage.onConnect().then(function() {
  return storage.set('key1', 'key2');
}).catch(function(err) {
  // Handle error
}).then(function() {
  storage.close();
});

Compatibility

For compatibility with older browsers, simply load a Promise polyfill such as es6-promise.

<script src="https://s3.amazonaws.com/es6-promises/promise-1.0.0.min.js"></script>

You can also use RSVP or any other ES6 compliant promise library. Supports IE8 and up using the above polyfill. A JSON polyfill is also required for IE8 in Compatibility View. Also note that catch is a reserved word in IE8, and so error handling with promises can be done as:

storage.onConnect().then(function() {
  return storage.get('key1');
}).then(function(res) {
  // ... on success
})['catch'](function(err) {
  // ... on error
});

Building

The minified, production JavaScript can be generated with gulp by running gulp dist. If not already on your system, gulp can be installed using npm install -g gulp

Tests

Tests can be ran locally using npm test. Tests are ran using Zuul, and the Travis CI build uses Sauce Labs for multi-browser testing as well.

Copyright and license

Copyright 2014 Zendesk

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

cross-storage's People

Contributors

danielstjules avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.