File: crypt.io.js

Recommend this page to a friend!
  Classes of Jason Gerfen  >  secStore.js  >  crypt.io.js  >  Download  
File: crypt.io.js
Role: Class source
Content type: text/plain
Description: Class source
Class: secStore.js
Store data securely using AES encryption
Author: By
Last change: Update of crypt.io.js
Date: 8 months ago
Size: 12,558 bytes
 

Contents

Class file image Download
/**
 * crypt.io - Encryption enabled browser storage
 *
 * https://www.github.com/jas-/crypt.io
 *
 * Author: Jason Gerfen <jason.gerfen@gmail.com>
 * License: MIT (see LICENSE)
 */
(function(window, undefined) {

  'use strict';

  /**
   * @function cryptio
   * @abstract Namespace for saving/retrieving encrypted HTML5 storage engine
   * data
   */
  var cryptio = cryptio || function() {

    /**
     * @var {Object} defaults
     * @abstract Default set of options for plug-in
     *
     * @param {Boolean} encrypt Optionally encrypt stored data
     * @param {String} passphrase Passphrase to use (optional)
     * @param {String} storage Storage mechanism (local, session or cookies)
     */
    var defaults = {
      passphrase: '',
      storage: 'local'
    };

    /**
     * @method setup
     * @abstract Initial setup routines
     */
    var setup = setup || {

      /**
       * @function set
       * @abstract Initialization
       *
       * @param {Object} opts Plug-in option object
       */
      init: function(opts) {
        opts.passphrase = opts.passphrase || (crypto.key(opts.passphrase) || crypto.key());
      }
    };

    /**
     * @method storage
     * @abstract Interface to handle storage options
     */
    var storage = storage || {

      /**
       * @function quota
       * @abstract Tests specified storage option for current amount of space available.
       *  - Cookies: 4K
       *  - localStorage: 5MB
       *  - sessionStorage: 5MB
       *  - default: 5MB
       *
       * @param {String} t Type of storage specified
       *
       * @returns {Boolean}
       */
      quota: function(storage) {
        var max = /local|session/.test(storage) ? 1024 * 1025 * 5 :
          1024 * 4,
          cur = libs.total(storage),
          total = max - cur;

        return total > 0;
      },

      /**
       * @function set
       * @abstract Interface for saving to available storage mechanisms
       *
       * @param {Object} opts Default options
       * @param {String} key Index of storage object
       * @param {Object} data Data to be stored
       * @param {Function} cb Callback function
       *
       * @returns {Boolean}
       */
      set: function(opts, key, data, cb) {
        var ret = false;

        if (!storage.quota(opts.storage))
          cb('Browser storage quota has been exceeded.');

        if (opts.passphrase) {
          try {
            data = sjcl.encrypt(opts.passphrase, storage.fromJSON(data));
          } catch(err) {
            return cb(err);
          }
        }

        ret = this[opts.storage] ?
          this[opts.storage].set(key, data) :
          this.local.set(key, data);

        if (!ret) {
          cb('Error occured saving data');
        } else {
          cb(null, 'Successfully set data');
        }
      },

      /**
       * @function get
       * @abstract Interface for retrieving from available storage mechanisms
       *
       * @param {Object} opts Default options
       * @param {String} key Index of storage object
       * @param {Function} cb Callback function
       *
       * @returns {Object}
       */
      get: function(opts, key, cb) {
        var ret = false;

        ret = this[opts.storage] ?
          this[opts.storage].get(key) :
          this.local.get(key);

        try {
          ret = sjcl.decrypt(opts.passphrase, ret);
        } catch(err) {
          cb(err);
        }
        
        ret = storage.toJSON(ret);

        if (ret) {
          cb(null, ret);
        } else {
          cb('Error occured retrieving storage data');
        }
      },

      /**
       * @function fromJSON
       * @abstract Convert to JSON object to string
       *
       * @param {Object|Array|String} obj Object, Array or String to convert to JSON object
       *
       * @returns {String}
       */
      fromJSON: function(obj) {
        var ret;
        try {
          ret = JSON.stringify(obj);
        } catch (e) {
          ret = obj;
        }
        return ret;
      },

      /**
       * @function toJSON
       * @abstract Creates JSON object from formatted string
       *
       * @param {String} obj Object to convert to JSON object
       *
       * @returns {Object}
       */
      toJSON: function(obj) {
        var ret;
        try {
          ret = JSON.parse(obj);
        } catch (e) {
          ret = obj;
        }
        return ret;
      },

      /**
       * @method cookie
       * @abstract Method for handling setting & retrieving of cookie objects
       */
      cookie: {

        /**
         * @function set
         * @abstract Handle setting of cookie objects
         *
         * @param {String} key Key to use for cookies
         * @param {String|Object} value String or object to place in cookie
         *
         * @returns {Boolean}
         */
        set: function(key, value) {
          var date = new Date();
          date.setTime(date.getTime() + (30 * 24 * 60 * 60 * 1000));
          document.cookie = key + '=' + value + ';expires=' + date.toGMTString() +
            ';path=/;domain=' + this.domain();
          return true;
        },

        /**
         * @function get
         * @abstract Handle retrieval of cookie objects
         *
         * @param {String} key cookie key
         *
         * @returns {String|False}
         */
        get: function(key) {
          var i, index, value, content = document.cookie.split(";");
          for (i = 0; i < content.length; i++) {
            index = content[i].substr(0, content[i].indexOf('='));
            value = content[i].substr(content[i].indexOf('=') + 1);
            index = index.replace(/^\s+|\s+$/g, '');
            if (index == key) {
              return unescape(value);
            }
          }
          return false;
        },

        /**
         * @function domain
         * @abstract Provides current domain of client for cookie realm
         *
         * @returns {String}
         */
        domain: function() {
          return location.hostname;
        }
      },

      /**
       * @method local
       * @abstract Method for handling setting & retrieving of localStorage objects
       */
      local: {

        /**
         * @function set
         * @abstract Handle setting & retrieving of localStorage objects
         *
         * @param {String} key Index of storage object
         * @param {Object} data Data to be stored
         *
         * @returns {Boolean}
         */
        set: function(key, data) {
          try {
            window.localStorage.setItem(key, data);
            return true;
          } catch (e) {
            return false;
          }
        },

        /**
         * @function get
         * @abstract Handle retrieval of localStorage objects
         *
         * @param {String} key Index of storage object
         *
         * @returns {Object|String|Boolean}
         */
        get: function(key) {
          return window.localStorage.getItem(key);
        }
      },

      /**
       * @method session
       * @abstract Method for handling setting & retrieving of sessionStorage objects
       */
      session: {

        /**
         * @function set
         * @abstract Set session storage objects
         *
         * @param {String} key Index of storage object
         * @param {Object} data Data to be stoed
         *
         * @returns {Boolean}
         */
        set: function(key, data) {
          try {
            window.sessionStorage.setItem(key, data);
            return true;
          } catch (e) {
            return false;
          }
        },

        /**
         * @function get
         * @abstract Retrieves sessionStorage objects
         *
         * @param {String} key Index of storage object
         *
         * @returns {Object|String|Boolean}
         */
        get: function(key) {
          return window.sessionStorage.getItem(key);
        }
      }
    };

    /**
     * @method crypto
     * @abstract Interface to handle encryption option
     */
    var crypto = crypto || {

      /**
       * @function key
       * @abstract Prepares key for encryption/decryption routines
       *
       * @param {String} pass Optional passphrase
       * 
       * @returns {String}
       */
      key: function(pass) {
        pass = pass || this.muid();

        var salt = crypto.salt(pass);

        return sjcl.codec.hex.fromBits(sjcl.misc.pbkdf2(pass, salt));
      },

      /**
       * @function muid
       * @abstract Generates a machine identifier
       *
       * @returns {String}
       */
      muid: function() {
        var ret = window.navigator.appName +
          window.navigator.language +
          window.navigator.platform;

        return ret;
      },

      /**
       * @function salt
       * @abstract Creates salt from string & iv
       *
       * @param {String} str Machine identification used as salt
       *
       * @returns {String}
       */
      salt: function(str) {
        return sjcl.codec.base64.fromBits(
                sjcl.hash.sha256.hash(window.navigator.appName));
      }
    };

    /**
     * @method libs
     * @abstract Miscellaneous helper libraries
     */
    var libs = libs || {

      /**
       * @function total
       * @abstract Returns size of specified storage
       *
       * @param {String} engine Storage mechanism
       *
       * @returns {Insteger}
       */
      total: function(storage) {
        var current = '',
          engine = window.storage + 'Storage';

        for (var key in engine) {
          if (engine.hasOwnProperty(key)) {
            current += engine[key];
          }
        }

        return current ? 3 + ((current.length * 16) / (8 * 1024)) : 0;
      },

      /**
       * @function size
       * @abstract Perform calculation on objects
       *
       * @param {Object|Array} obj The object/array to calculate
       *
       * @returns {Integer}
       */
      size: function(obj) {
        var n = 0;

        if (/object/.test(typeof(obj))) {
          for (var i in obj) {
            if (obj.hasOwnProperty(obj[i])) n++;
          }
        } else if (/array/.test(typeof(obj))) {
          n = obj.length;
        }
        return n;
      },

      /**
       * @function merge
       * @abstract Perform preliminary option/default object merge
       *
       * @param {Object} defaults Application defaults
       * @param {Object} obj User supplied object
       *
       * @returns {Object}
       */
      merge: function(defaults, obj) {
        defaults = defaults || {};

        for (var item in defaults) {
          if (defaults.hasOwnProperty(item)) {
            obj[item] = (/object/.test(typeof(defaults[item]))) ?
              this.merge(obj[item], defaults[item]) : defaults[item];
          }
          obj[item] = defaults[item];
        }

        return obj;
      }
    };

    /**
     * @function get
     * @abstract Retrieves storage engine data
     *
     * @param {Object} obj User supplied options
     * @param {String} key Key of storage object to retrieve
     * @param {Function} cb User supplied callback function
     */
    cryptio.prototype.get = function(obj, key, cb) {
      if (cb == undefined)
        cb = key, key = obj, obj = {};

      var opts = libs.merge(obj, defaults);

      setup.init(opts);

      storage.get(opts, key, cb);
    };

    /**
     * @function set
     * @abstract Saves data to specified storage engine
     *
     * @param {Object} obj User supplied options
     * @param {String} key Key of storage object to retrieve
     * @param {Object} data User provided data to store
     * @param {Function} cb User supplied callback function
     */
    cryptio.prototype.set = function(obj, key, data, cb) {
      if (cb == undefined)
        cb = data,data = key, key = obj, obj = {};

      var opts = libs.merge(obj, defaults);

      setup.init(opts);

      storage.set(opts, key, data, cb);
    };

  };

  /* crypt.io, do work */
  window.cryptio = new cryptio;

})(window);