From 5d409933e5f22f1f08736c4e0df69163a57eecab Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Mon, 10 Jun 2013 22:45:21 +0200 Subject: [PATCH] refactored keychaindao --- src/js/dao/keychain-dao.js | 454 +++++++++++++++++---------------- test/unit/keychain-dao-test.js | 127 ++++----- test/unit/main.js | 7 +- 3 files changed, 299 insertions(+), 289 deletions(-) diff --git a/src/js/dao/keychain-dao.js b/src/js/dao/keychain-dao.js index 199e3ef..10b05f8 100644 --- a/src/js/dao/keychain-dao.js +++ b/src/js/dao/keychain-dao.js @@ -2,264 +2,270 @@ * A high-level Data-Access Api for handling Keypair synchronization * between the cloud service and the device's local storage */ -app.dao.KeychainDAO = function(jsonDao, cloudstorage) { +define(['underscore', 'js/dao/lawnchair-dao'], function(_, jsonDao) { 'use strict'; - /** - * 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 - */ - this.getPublicKeys = function(ids, callback) { - var already, pubkeys = []; + var KeychainDAO = function(cloudstorage) { + var self = this; - 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 + */ + self.getPublicKeys = function(ids, callback) { + var 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; - } - - // check if public key with that id has already been fetched - already = null; - already = _.findWhere(pubkeys, { - _id: i._id - }); - if (!already) { - pubkeys.push(pubkey); - } - - after(); // asynchronously iterate through objects - }); - }); - }; - - /** - * 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} - */ - this.getUserKeyPair = function(userId, callback) { - // search for user's public key locally - jsonDao.list('publickey', 0, null, function(allPubkeys) { - var pubkey = _.findWhere(allPubkeys, { - userId: userId + var after = _.after(ids.length, function() { + callback(null, pubkeys); }); - 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; - } - - 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; - } - }); - - } else { - // that user's public key is already in local storage... - // sync keypair to the cloud - syncKeypair(pubkey._id); - } - }); - - function syncKeypair(keypairId) { - // persist key pair in local storage - lookupPublicKey(keypairId, function(err, savedPubkey) { - if (err) { - callback(err); - return; - } - - // persist private key in local storage - lookupPrivateKey(keypairId, function(err, savedPrivkey) { - if (err) { - callback(err); - return; - } - - // validate fetched key - if (savedPubkey && savedPubkey.publicKey && savedPrivkey && savedPrivkey.encryptedKey) { - callback(null, { - publicKey: savedPubkey, - privateKey: savedPrivkey + _.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; - - } else { - // continue without keypair... generate in crypto.js - callback(); - return; } + + // check if public key with that id has already been fetched + already = null; + already = _.findWhere(pubkeys, { + _id: i._id + }); + if (!already) { + pubkeys.push(pubkey); + } + + after(); // asynchronously iterate through objects }); }); - } - }; + }; - /** - * 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} - */ - this.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!' + /** + * 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 + }); + + 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; + } + + 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; + } + }); + + } else { + // that user's public key is already in local storage... + // sync keypair to the cloud + syncKeypair(pubkey._id); + } }); - return; - } - // store public key locally - saveLocalPublicKey(keypair.publicKey, function(err) { - if (err) { - callback(err); + function syncKeypair(keypairId) { + // persist key pair in local storage + lookupPublicKey(keypairId, function(err, savedPubkey) { + if (err) { + callback(err); + return; + } + + // persist private key in local storage + lookupPrivateKey(keypairId, function(err, savedPrivkey) { + if (err) { + callback(err); + return; + } + + // validate fetched key + if (savedPubkey && savedPubkey.publicKey && savedPrivkey && savedPrivkey.encryptedKey) { + callback(null, { + publicKey: savedPubkey, + privateKey: savedPrivkey + }); + return; + + } else { + // continue without keypair... generate in crypto.js + callback(); + 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 public key in cloud storage - cloudstorage.putPublicKey(keypair.publicKey, function(err) { - // validate result + // store public key locally + saveLocalPublicKey(keypair.publicKey, function(err) { if (err) { callback(err); return; } - // store private key locally - saveLocalPrivateKey(keypair.privateKey, function(err) { + // persist public key in cloud storage + cloudstorage.putPublicKey(keypair.publicKey, function(err) { + // validate result if (err) { callback(err); return; } - // persist private key in cloud storage - cloudstorage.putPrivateKey(keypair.privateKey, function(err) { - // validate result + // store private key locally + saveLocalPrivateKey(keypair.privateKey, function(err) { if (err) { callback(err); return; } - callback(null); + // persist private key in cloud storage + cloudstorage.putPrivateKey(keypair.privateKey, function(err) { + // validate result + if (err) { + callback(err); + return; + } + + callback(null); + }); }); }); }); - }); + }; + + // + // Helper functions + // + + 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; + } + + // cache public key in cache + saveLocalPublicKey(cloudPubkey, function(err) { + if (err) { + callback(err); + return; + } + + callback(null, cloudPubkey); + }); + }); + + } else { + callback(null, pubkey); + } + }); + } + + 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; + } + + // cache private key in cache + saveLocalPrivateKey(cloudPrivkey, function(err) { + if (err) { + callback(err); + return; + } + + callback(null, cloudPrivkey); + }); + + }); + + } else { + callback(null, privkey); + } + }); + } + + function saveLocalPublicKey(pubkey, callback) { + // persist public key (email, _id) + var pkLookupKey = 'publickey_' + pubkey._id; + + jsonDao.persist(pkLookupKey, pubkey, function(res1) { + // validate result + if (res1.key !== pkLookupKey) { + callback({ + errMsg: 'Persisting public key in local storage went wrong!' + }); + return; + } + + callback(); + }); + } + + function saveLocalPrivateKey(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(); + }); + } + }; - // - // Helper functions - // - - 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; - } - - // cache public key in cache - saveLocalPublicKey(cloudPubkey, function(err) { - if (err) { - callback(err); - return; - } - - callback(null, cloudPubkey); - }); - }); - - } else { - callback(null, pubkey); - } - }); - } - - 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; - } - - // cache private key in cache - saveLocalPrivateKey(cloudPrivkey, function(err) { - if (err) { - callback(err); - return; - } - - callback(null, cloudPrivkey); - }); - - }); - - } else { - callback(null, privkey); - } - }); - } - - function saveLocalPublicKey(pubkey, callback) { - // persist public key (email, _id) - var pkLookupKey = 'publickey_' + pubkey._id; - - jsonDao.persist(pkLookupKey, pubkey, function(res1) { - // validate result - if (res1.key !== pkLookupKey) { - callback({ - errMsg: 'Persisting public key in local storage went wrong!' - }); - return; - } - - callback(); - }); - } - - function saveLocalPrivateKey(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(); - }); - } - -}; \ No newline at end of file + return KeychainDAO; +}); \ No newline at end of file diff --git a/test/unit/keychain-dao-test.js b/test/unit/keychain-dao-test.js index e6ac566..1b51ccc 100644 --- a/test/unit/keychain-dao-test.js +++ b/test/unit/keychain-dao-test.js @@ -1,81 +1,84 @@ -module("Keychain DAO"); +define(['js/dao/keychain-dao', 'js/dao/lawnchair-dao'], function(KeychainDAO, jsonDao) { + 'use strict'; -var keychaindao_test = { - user: 'keychaindao_test@example.com', - password: 'Password', - keySize: 128, - ivSize: 128, - rsaKeySize: 512 -}; + module("Keychain DAO"); -asyncTest("Init", 2, function() { - // init dependencies - var util = new cryptoLib.Util(window, uuid); - var jsonDao = new app.dao.LawnchairDAO(Lawnchair); - jsonDao.init(keychaindao_test.user); - var crypto = new app.crypto.Crypto(window, util); - // cloud storage stub - var cloudstorageStub = { - putPublicKey: function(pk, callback) { - callback(); - }, - putPrivateKey: function(prk, callback) { - callback(); - } + var keychaindaoTest = { + user: 'keychaindao_test@example.com', + password: 'Password', + keySize: 128, + ivSize: 128, + rsaKeySize: 512 }; - keychaindao_test.keychainDao = new app.dao.KeychainDAO(jsonDao, cloudstorageStub); - ok(keychaindao_test.keychainDao); + asyncTest("Init", 2, function() { - // clear db before test - jsonDao.clear(function() { - ok(true, 'cleared db'); + // stubbing + var cloudstorageStub = { + putPublicKey: function(pk, callback) { + callback(); + }, + putPrivateKey: function(prk, callback) { + callback(); + } + }; - start(); + // module instancing + keychaindaoTest.keychainDao = new KeychainDAO(cloudstorageStub); + ok(keychaindaoTest.keychainDao); + + // init and clear db before test + jsonDao.init(keychaindaoTest.user); + jsonDao.clear(function() { + ok(true, 'cleared db'); + + start(); + }); }); -}); -asyncTest("Put User Keypair", 1, function() { + asyncTest("Put User Keypair", 1, function() { - keychaindao_test.keypair = { - publicKey: { - _id: '1', - userId: keychaindao_test.user, - publicKey: 'asdf' - }, - privateKey: { - _id: '1', - userId: keychaindao_test.user, - encryptedKey: 'qwer', - iv: 'yxvc' - } - }; + keychaindaoTest.keypair = { + publicKey: { + _id: '123', + userId: keychaindaoTest.user, + publicKey: 'asdf' + }, + privateKey: { + _id: '123', + userId: keychaindaoTest.user, + encryptedKey: 'qwer', + iv: 'yxvc' + } + }; - keychaindao_test.keychainDao.putUserKeyPair(keychaindao_test.keypair, function(err) { - ok(!err); + keychaindaoTest.keychainDao.putUserKeyPair(keychaindaoTest.keypair, function(err) { + ok(!err); - start(); + start(); + }); }); -}); -asyncTest("Get User Keypair", 2, function() { - keychaindao_test.keychainDao.getUserKeyPair(keychaindao_test.user, function(err, keypair) { - ok(!err); - ok(keypair && keypair.publicKey && keypair.privateKey); + asyncTest("Get User Keypair", 2, function() { + keychaindaoTest.keychainDao.getUserKeyPair(keychaindaoTest.user, function(err, keypair) { + ok(!err); + ok(keypair && keypair.publicKey && keypair.privateKey); - start(); + start(); + }); }); -}); -asyncTest("Get Public Keys", 2, function() { - var pubkeyIds = [{ - _id: keychaindao_test.keypair.publicKey._id - } - ]; - keychaindao_test.keychainDao.getPublicKeys(pubkeyIds, function(err, pubkeys) { - ok(!err); - deepEqual(pubkeys[0], keychaindao_test.keypair.publicKey, "Fetch public key"); + asyncTest("Get Public Keys", 2, function() { + var pubkeyIds = [{ + _id: keychaindaoTest.keypair.publicKey._id + } + ]; + keychaindaoTest.keychainDao.getPublicKeys(pubkeyIds, function(err, pubkeys) { + ok(!err); + deepEqual(pubkeys[0], keychaindaoTest.keypair.publicKey, "Fetch public key"); - start(); + start(); + }); }); + }); \ No newline at end of file diff --git a/test/unit/main.js b/test/unit/main.js index 300b96a..59a9ad6 100644 --- a/test/unit/main.js +++ b/test/unit/main.js @@ -24,9 +24,10 @@ function startTests() { 'test/unit/forge-test', 'test/unit/aes-test', 'test/unit/rsa-test', - 'test/unit/lawnchair-dao-test' + 'test/unit/lawnchair-dao-test', + 'test/unit/keychain-dao-test' ], function() { - - QUnit.start(); //Tests loaded, run tests + //Tests loaded, run tests + QUnit.start(); }); } \ No newline at end of file