diff --git a/src/js/dao/devicestorage-dao.js b/src/js/dao/devicestorage-dao.js index 0b96f3d..300ba41 100644 --- a/src/js/dao/devicestorage-dao.js +++ b/src/js/dao/devicestorage-dao.js @@ -5,67 +5,67 @@ * used to encrypt data on the fly before persisting via a JSON store. */ define(['cryptoLib/util', 'js/crypto/crypto', 'js/dao/lawnchair-dao'], function(util, crypto, jsonDao) { - 'use strict'; + 'use strict'; - var self = {}; + var self = {}; - /** - * Stores a list of encrypted items in the object store - * @param list [Array] The list of items to be persisted - * @param type [String] The type of item to be persisted e.g. 'email' - */ - self.storeEcryptedList = function(list, type, callback) { - var date, key, items = []; + /** + * Stores a list of encrypted items in the object store + * @param list [Array] The list of items to be persisted + * @param type [String] The type of item to be persisted e.g. 'email' + */ + self.storeEcryptedList = function(list, type, callback) { + var date, key, items = []; - // nothing to store - if (list.length === 0) { - callback(); - return; - } + // nothing to store + if (list.length === 0) { + callback(); + return; + } - // format items for batch storing in dao - list.forEach(function(i) { + // format items for batch storing in dao + list.forEach(function(i) { - // put date in key if available... for easy querying - if (i.sentDate) { - date = util.parseDate(i.sentDate); - key = type + '_' + i.sentDate + '_' + i.id; - } else { - key = type + '_' + i.id; - } + // put date in key if available... for easy querying + if (i.sentDate) { + date = util.parseDate(i.sentDate); + key = type + '_' + i.sentDate + '_' + i.id; + } else { + key = type + '_' + i.id; + } - items.push({ - key: key, - object: i - }); + items.push({ + key: key, + object: i + }); - }); + }); - jsonDao.batch(items, function() { - callback(); - }); - }; + jsonDao.batch(items, function() { + callback(); + }); + }; - /** - * List stored items of a given type - * @param type [String] The type of item e.g. 'email' - * @param offset [Number] The offset of items to fetch (0 is the last stored item) - * @param num [Number] The number of items to fetch (null means fetch all) - */ - self.listEncryptedItems = function(type, offset, num, callback) { - // fetch all items of a certain type from the data-store - jsonDao.list(type, offset, num, function(encryptedList) { + /** + * List stored items of a given type + * @param type [String] The type of item e.g. 'email' + * @param offset [Number] The offset of items to fetch (0 is the last stored item) + * @param num [Number] The number of items to fetch (null means fetch all) + */ + self.listEncryptedItems = function(type, offset, num, callback) { + // fetch all items of a certain type from the data-store + jsonDao.list(type, offset, num, function(encryptedList) { - callback(null, encryptedList); - }); - }; + callback(null, encryptedList); + }); + }; - /** - * Clear the whole device data-store - */ - self.clear = function(callback) { - jsonDao.clear(callback); - }; + /** + * Clear the whole device data-store + */ + self.clear = function(callback) { + jsonDao.clear(callback); + }; - return self; + return self; }); \ No newline at end of file diff --git a/src/js/dao/keychain-dao.js b/src/js/dao/keychain-dao.js index 8549003..b895efa 100644 --- a/src/js/dao/keychain-dao.js +++ b/src/js/dao/keychain-dao.js @@ -3,314 +3,326 @@ * between the cloud service and the device's local storage */ define(['underscore', 'js/dao/lawnchair-dao'], function(_, jsonDao) { - 'use strict'; + 'use strict'; - var KeychainDAO = function(cloudstorage) { - var self = this; + var KeychainDAO = function(cloudstorage) { + var self = this; - /** - * Get an array of public keys by looking in local storage and - * fetching missing keys from the cloud service. - * @param ids [Array] the key ids as [{_id, userId}] - * @return [PublicKeyCollection] The requiested public keys - */ - self.getPublicKeys = function(ids, callback) { - var already, pubkeys = []; + self._cloudstorage = cloudstorage; + }; - var after = _.after(ids.length, function() { - callback(null, pubkeys); - }); + /** + * Get an array of public keys by looking in local storage and + * fetching missing keys from the cloud service. + * @param ids [Array] the key ids as [{_id, userId}] + * @return [PublicKeyCollection] The requiested public keys + */ + KeychainDAO.prototype.getPublicKeys = function(ids, callback) { + var self = this, + after, already, pubkeys = []; - _.each(ids, function(i) { - // lookup locally and in storage - lookupPublicKey(i._id, function(err, pubkey) { - if (err || !pubkey) { - callback({ - errMsg: 'Error looking up public key!', - err: err - }); - return; - } + after = _.after(ids.length, function() { + callback(null, pubkeys); + }); - // check if public key with that id has already been fetched - already = null; - already = _.findWhere(pubkeys, { - _id: i._id - }); - if (!already) { - pubkeys.push(pubkey); - } + _.each(ids, function(i) { + // lookup locally and in storage + self.lookupPublicKey(i._id, function(err, pubkey) { + if (err || !pubkey) { + callback({ + errMsg: 'Error looking up public key!', + err: err + }); + return; + } - after(); // asynchronously iterate through objects - }); - }); - }; + // check if public key with that id has already been fetched + already = null; + already = _.findWhere(pubkeys, { + _id: i._id + }); + if (!already) { + pubkeys.push(pubkey); + } - /** - * Look up a reveiver's public key by user id - * @param userId [String] the receiver's email address - */ - self.getReveiverPublicKey = function(userId, callback) { - // search local keyring for public key - jsonDao.list('publickey', 0, null, function(allPubkeys) { - var pubkey = _.findWhere(allPubkeys, { - userId: userId - }); + after(); // asynchronously iterate through objects + }); + }); + }; - if (!pubkey || !pubkey._id) { - // no public key by that user id in storage - // find from cloud by email address - cloudstorage.getPublicKeyByUserId(userId, function(err, cloudPubkey) { - if (err || !cloudPubkey) { - callback(); - return; - } + /** + * Look up a reveiver's public key by user id + * @param userId [String] the receiver's email address + */ + KeychainDAO.prototype.getReveiverPublicKey = function(userId, callback) { + var self = this; - if (cloudPubkey && cloudPubkey._id) { - // there is a public key for that user already in the cloud... - // save to local storage - saveLocalPublicKey(cloudPubkey, function(err) { - if (err) { - callback(err); - return; - } + // search local keyring for public key + jsonDao.list('publickey', 0, null, function(allPubkeys) { + var pubkey = _.findWhere(allPubkeys, { + userId: userId + }); - callback(null, cloudPubkey); - }); - } else { - // no public key for that user - callback(); - return; - } - }); + if (!pubkey || !pubkey._id) { + // no public key by that user id in storage + // find from cloud by email address + self._cloudstorage.getPublicKeyByUserId(userId, function(err, cloudPubkey) { + if (err || !cloudPubkey) { + callback(); + return; + } - } else { - // that user's public key is already in local storage - callback(null, pubkey); - } - }); - }; + if (cloudPubkey && cloudPubkey._id) { + // there is a public key for that user already in the cloud... + // save to local storage + self.saveLocalPublicKey(cloudPubkey, function(err) { + if (err) { + callback(err); + return; + } - /** - * Gets the local user's key either from local storage - * or fetches it from the cloud. The private key is encrypted. - * If no key pair exists, null is returned. - * return [Object] The user's key pair {publicKey, privateKey} - */ - self.getUserKeyPair = function(userId, callback) { - // search for user's public key locally - jsonDao.list('publickey', 0, null, function(allPubkeys) { - var pubkey = _.findWhere(allPubkeys, { - userId: userId - }); + callback(null, cloudPubkey); + }); + } else { + // no public key for that user + callback(); + return; + } + }); - if (!pubkey || !pubkey._id) { - // no public key by that user id in storage - // find from cloud by email address - cloudstorage.getPublicKeyByUserId(userId, function(err, cloudPubkey) { - if (err) { - callback(err); - return; - } + } else { + // that user's public key is already in local storage + callback(null, pubkey); + } + }); + }; - if (cloudPubkey && cloudPubkey._id) { - // there is a public key for that user already in the cloud... - // sync keypair to local storage - syncKeypair(cloudPubkey._id); - } else { - // continue without keypair... generate in crypto.js - callback(); - return; - } - }); + /** + * Gets the local user's key either from local storage + * or fetches it from the cloud. The private key is encrypted. + * If no key pair exists, null is returned. + * return [Object] The user's key pair {publicKey, privateKey} + */ + KeychainDAO.prototype.getUserKeyPair = function(userId, callback) { + var self = this; - } else { - // that user's public key is already in local storage... - // sync keypair to the cloud - syncKeypair(pubkey._id); - } - }); + // search for user's public key locally + jsonDao.list('publickey', 0, null, function(allPubkeys) { + var pubkey = _.findWhere(allPubkeys, { + userId: userId + }); - function syncKeypair(keypairId) { - // persist key pair in local storage - lookupPublicKey(keypairId, function(err, savedPubkey) { - if (err) { - callback(err); - return; - } + if (!pubkey || !pubkey._id) { + // no public key by that user id in storage + // find from cloud by email address + self._cloudstorage.getPublicKeyByUserId(userId, function(err, cloudPubkey) { + if (err) { + callback(err); + return; + } - // persist private key in local storage - lookupPrivateKey(keypairId, function(err, savedPrivkey) { - if (err) { - callback(err); - return; - } + if (cloudPubkey && cloudPubkey._id) { + // there is a public key for that user already in the cloud... + // sync keypair to local storage + syncKeypair(cloudPubkey._id); + } else { + // continue without keypair... generate in crypto.js + callback(); + return; + } + }); - // validate fetched key - if (savedPubkey && savedPubkey.publicKey && savedPrivkey && savedPrivkey.encryptedKey) { - callback(null, { - publicKey: savedPubkey, - privateKey: savedPrivkey - }); - return; + } else { + // that user's public key is already in local storage... + // sync keypair to the cloud + syncKeypair(pubkey._id); + } + }); - } else { - // continue without keypair... generate in crypto.js - callback(); - return; - } - }); - }); - } - }; + function syncKeypair(keypairId) { + // persist key pair in local storage + self.lookupPublicKey(keypairId, function(err, savedPubkey) { + if (err) { + callback(err); + return; + } - /** - * Checks to see if the user's key pair is stored both - * locally and in the cloud and persist arccordingly - * @param [Object] The user's key pair {publicKey, privateKey} - */ - self.putUserKeyPair = function(keypair, callback) { - // validate input - if (!keypair || !keypair.publicKey || !keypair.privateKey || !keypair.publicKey.userId || keypair.publicKey.userId !== keypair.privateKey.userId) { - callback({ - errMsg: 'Incorrect input!' - }); - return; - } + // persist private key in local storage + self.lookupPrivateKey(keypairId, function(err, savedPrivkey) { + if (err) { + callback(err); + return; + } - // store public key locally - saveLocalPublicKey(keypair.publicKey, function(err) { - if (err) { - callback(err); - return; - } + // validate fetched key + if (savedPubkey && savedPubkey.publicKey && savedPrivkey && savedPrivkey.encryptedKey) { + callback(null, { + publicKey: savedPubkey, + privateKey: savedPrivkey + }); + return; - // persist public key in cloud storage - cloudstorage.putPublicKey(keypair.publicKey, function(err) { - // validate result - if (err) { - callback(err); - return; - } + } else { + // continue without keypair... generate in crypto.js + callback(); + return; + } + }); + }); + } + }; - // store private key locally - saveLocalPrivateKey(keypair.privateKey, function(err) { - if (err) { - callback(err); - return; - } + /** + * Checks to see if the user's key pair is stored both + * locally and in the cloud and persist arccordingly + * @param [Object] The user's key pair {publicKey, privateKey} + */ + KeychainDAO.prototype.putUserKeyPair = function(keypair, callback) { + var self = this; - // persist private key in cloud storage - cloudstorage.putPrivateKey(keypair.privateKey, function(err) { - // validate result - if (err) { - callback(err); - return; - } + // validate input + if (!keypair || !keypair.publicKey || !keypair.privateKey || !keypair.publicKey.userId || keypair.publicKey.userId !== keypair.privateKey.userId) { + callback({ + errMsg: 'Incorrect input!' + }); + return; + } - callback(null); - }); - }); - }); - }); - }; + // store public key locally + self.saveLocalPublicKey(keypair.publicKey, function(err) { + if (err) { + callback(err); + return; + } - // - // Helper functions - // + // persist public key in cloud storage + self._cloudstorage.putPublicKey(keypair.publicKey, function(err) { + // validate result + if (err) { + callback(err); + return; + } - function lookupPublicKey(id, callback) { - // lookup in local storage - jsonDao.read('publickey_' + id, function(pubkey) { - if (!pubkey) { - // fetch from cloud storage - cloudstorage.getPublicKey(id, function(err, cloudPubkey) { - if (err) { - callback(err); - return; - } + // store private key locally + self.saveLocalPrivateKey(keypair.privateKey, function(err) { + if (err) { + callback(err); + return; + } - // cache public key in cache - saveLocalPublicKey(cloudPubkey, function(err) { - if (err) { - callback(err); - return; - } + // persist private key in cloud storage + self._cloudstorage.putPrivateKey(keypair.privateKey, function(err) { + // validate result + if (err) { + callback(err); + return; + } - callback(null, cloudPubkey); - }); - }); + callback(null); + }); + }); + }); + }); + }; - } else { - callback(null, pubkey); - } - }); - } + // + // Helper functions + // - function lookupPrivateKey(id, callback) { - // lookup in local storage - jsonDao.read('privatekey_' + id, function(privkey) { - if (!privkey) { - // fetch from cloud storage - cloudstorage.getPrivateKey(id, function(err, cloudPrivkey) { - if (err) { - callback(err); - return; - } + KeychainDAO.prototype.lookupPublicKey = function(id, callback) { + var self = this; - // cache private key in cache - saveLocalPrivateKey(cloudPrivkey, function(err) { - if (err) { - callback(err); - return; - } + // lookup in local storage + jsonDao.read('publickey_' + id, function(pubkey) { + if (!pubkey) { + // fetch from cloud storage + self._cloudstorage.getPublicKey(id, function(err, cloudPubkey) { + if (err) { + callback(err); + return; + } - callback(null, cloudPrivkey); - }); + // cache public key in cache + self.saveLocalPublicKey(cloudPubkey, function(err) { + if (err) { + callback(err); + return; + } - }); + callback(null, cloudPubkey); + }); + }); - } else { - callback(null, privkey); - } - }); - } + } else { + callback(null, pubkey); + } + }); + }; - function saveLocalPublicKey(pubkey, callback) { - // persist public key (email, _id) - var pkLookupKey = 'publickey_' + pubkey._id; + KeychainDAO.prototype.lookupPrivateKey = function(id, callback) { + var self = this; - jsonDao.persist(pkLookupKey, pubkey, function(res1) { - // validate result - if (res1.key !== pkLookupKey) { - callback({ - errMsg: 'Persisting public key in local storage went wrong!' - }); - return; - } + // lookup in local storage + jsonDao.read('privatekey_' + id, function(privkey) { + if (!privkey) { + // fetch from cloud storage + self._cloudstorage.getPrivateKey(id, function(err, cloudPrivkey) { + if (err) { + callback(err); + return; + } - callback(); - }); - } + // cache private key in cache + self.saveLocalPrivateKey(cloudPrivkey, function(err) { + if (err) { + callback(err); + return; + } - function saveLocalPrivateKey(privkey, callback) { - // persist private key (email, _id) - var prkLookupKey = 'privatekey_' + privkey._id; + callback(null, cloudPrivkey); + }); - jsonDao.persist(prkLookupKey, privkey, function(res1) { - // validate result - if (res1.key !== prkLookupKey) { - callback({ - errMsg: 'Persisting private key in local storage went wrong!' - }); - return; - } + }); - callback(); - }); - } + } else { + callback(null, privkey); + } + }); + }; - }; + KeychainDAO.prototype.saveLocalPublicKey = function(pubkey, callback) { + // persist public key (email, _id) + var pkLookupKey = 'publickey_' + pubkey._id; - return KeychainDAO; + jsonDao.persist(pkLookupKey, pubkey, function(res1) { + // validate result + if (res1.key !== pkLookupKey) { + callback({ + errMsg: 'Persisting public key in local storage went wrong!' + }); + return; + } + + callback(); + }); + }; + + KeychainDAO.prototype.saveLocalPrivateKey = function(privkey, callback) { + // persist private key (email, _id) + var prkLookupKey = 'privatekey_' + privkey._id; + + jsonDao.persist(prkLookupKey, privkey, function(res1) { + // validate result + if (res1.key !== prkLookupKey) { + callback({ + errMsg: 'Persisting private key in local storage went wrong!' + }); + return; + } + + callback(); + }); + }; + + return KeychainDAO; }); \ No newline at end of file diff --git a/src/js/dao/lawnchair-dao.js b/src/js/dao/lawnchair-dao.js index cabc42d..94f93a2 100644 --- a/src/js/dao/lawnchair-dao.js +++ b/src/js/dao/lawnchair-dao.js @@ -2,124 +2,123 @@ * Handles generic caching of JSON objects in a lawnchair adapter */ define(['lawnchair', 'lawnchairSQL', 'lawnchairIDB'], function(Lawnchair) { - 'use strict'; + 'use strict'; - var self = {}; + var self = {}, + db; - var db; + self.init = function(dbName) { + if (!dbName) { + throw new Error('Lawnchair DB name must be specified!'); + } - self.init = function(dbName) { - if (!dbName) { - throw new Error('Lawnchair DB name must be specified!'); - } + db = new Lawnchair({ + name: dbName + }, function(lc) { + if (!lc) { + throw new Error('Lawnchair init failed!'); + } + }); + }; - db = new Lawnchair({ - name: dbName - }, function(lc) { - if (!lc) { - throw new Error('Lawnchair init failed!'); - } - }); - }; + /** + * Create or update an object + */ + self.persist = function(key, object, callback) { + db.save({ + key: key, + object: object + }, callback); + }; - /** - * Create or update an object - */ - self.persist = function(key, object, callback) { - db.save({ - key: key, - object: object - }, callback); - }; + /** + * Persist a bunch of items at once + */ + self.batch = function(list, callback) { + db.batch(list, callback); + }; - /** - * Persist a bunch of items at once - */ - self.batch = function(list, callback) { - db.batch(list, callback); - }; + /** + * Read a single item by its key + */ + self.read = function(key, callback) { + db.get(key, function(o) { + if (o) { + callback(o.object); + } else { + callback(null); + } + }); + }; - /** - * Read a single item by its key - */ - self.read = function(key, callback) { - db.get(key, function(o) { - if (o) { - callback(o.object); - } else { - callback(null); - } - }); - }; + /** + * List all the items of a certain type + * @param type [String] The type of item e.g. 'email' + * @param offset [Number] The offset of items to fetch (0 is the last stored item) + * @param num [Number] The number of items to fetch (null means fetch all) + */ + self.list = function(type, offset, num, callback) { + var i, from, to, + matchingKeys = [], + intervalKeys = [], + list = []; - /** - * List all the items of a certain type - * @param type [String] The type of item e.g. 'email' - * @param offset [Number] The offset of items to fetch (0 is the last stored item) - * @param num [Number] The number of items to fetch (null means fetch all) - */ - self.list = function(type, offset, num, callback) { - var i, from, to, - matchingKeys = [], - intervalKeys = [], - list = []; + // get all keys + db.keys(function(keys) { - // get all keys - db.keys(function(keys) { + // check if key begins with type + keys.forEach(function(key) { + if (key.indexOf(type) === 0) { + matchingKeys.push(key); + } + }); - // check if key begins with type - keys.forEach(function(key) { - if (key.indexOf(type) === 0) { - matchingKeys.push(key); - } - }); + // sort keys + matchingKeys.sort(); - // sort keys - matchingKeys.sort(); + // set window of items to fetch + // if num is null, list all items + from = (num) ? matchingKeys.length - offset - num : 0; + to = matchingKeys.length - 1 - offset; + // filter items within requested interval + for (i = 0; i < matchingKeys.length; i++) { + if (i >= from && i <= to) { + intervalKeys.push(matchingKeys[i]); + } + } - // set window of items to fetch - // if num is null, list all items - from = (num) ? matchingKeys.length - offset - num : 0; - to = matchingKeys.length - 1 - offset; - // filter items within requested interval - for (i = 0; i < matchingKeys.length; i++) { - if (i >= from && i <= to) { - intervalKeys.push(matchingKeys[i]); - } - } + // return if there are no matching keys + if (intervalKeys.length === 0) { + callback(list); + return; + } - // return if there are no matching keys - if (intervalKeys.length === 0) { - callback(list); - return; - } + // fetch all items from data-store with matching key + db.get(intervalKeys, function(intervalList) { + intervalList.forEach(function(item) { + list.push(item.object); + }); - // fetch all items from data-store with matching key - db.get(intervalKeys, function(intervalList) { - intervalList.forEach(function(item) { - list.push(item.object); - }); + // return only the interval between offset and num + callback(list); + }); - // return only the interval between offset and num - callback(list); - }); + }); + }; - }); - }; + /** + * Removes an object liter from local storage by its key (delete) + */ + self.remove = function(key, callback) { + db.remove(key, callback); + }; - /** - * Removes an object liter from local storage by its key (delete) - */ - self.remove = function(key, callback) { - db.remove(key, callback); - }; + /** + * Clears the whole local storage cache + */ + self.clear = function(callback) { + db.nuke(callback); + }; - /** - * Clears the whole local storage cache - */ - self.clear = function(callback) { - db.nuke(callback); - }; - - return self; + return self; }); \ No newline at end of file