From 6a33f17f42d234a2c17f1f34ffe87218e9e7d495 Mon Sep 17 00:00:00 2001 From: Tankred Hase Date: Mon, 27 May 2013 19:25:45 +0200 Subject: [PATCH] implemented storage and lookup of user keypair --- src/js/dao/email-dao.js | 9 ++- src/js/dao/keychain-dao.js | 93 +++++++++++++++++++---- test/integration/cloudstorage-dao-test.js | 52 +++++++------ test/unit/keychain-dao-test.js | 34 ++++++++- 4 files changed, 146 insertions(+), 42 deletions(-) diff --git a/src/js/dao/email-dao.js b/src/js/dao/email-dao.js index 94ad0a3..8a046bc 100644 --- a/src/js/dao/email-dao.js +++ b/src/js/dao/email-dao.js @@ -11,6 +11,8 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util) { this.init = function(account, password, callback) { this.account = account; + // TODO: call getUserKeyPair to read/sync keypair with devicestorage/cloud + // sync user's cloud key with local storage var storedKey = crypto.getEncryptedPrivateKey(account.get('emailAddress')); cloudstorage.syncPrivateKey(account.get('emailAddress'), storedKey, function(err) { @@ -30,6 +32,9 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util) { }); function initCrypto() { + + // TODO: passed fetched keypair from keychain dao + crypto.init({ emailAddress: account.get('emailAddress'), password: password, @@ -45,6 +50,8 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util) { }); } + // TODO: refactor to be part of sync in getUserKeypair + function publishPublicKey() { // get public key from crypto var pubkey = crypto.getPublicKey(); @@ -84,7 +91,7 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util) { if (!folder) { // get items from storage - devicestorage.listItems('email_' + folderName, offset, num, function(err, decryptedList) { + devicestorage.listItems('email_' + folderName, offset, num, null, function(err, decryptedList) { if (err) { callback(err); return; diff --git a/src/js/dao/keychain-dao.js b/src/js/dao/keychain-dao.js index a5b090b..dfbe7e0 100644 --- a/src/js/dao/keychain-dao.js +++ b/src/js/dao/keychain-dao.js @@ -22,25 +22,28 @@ app.dao.KeychainDAO = function(jsonDao, cloudstorage) { * return [Object] The user's key pair {publicKey, privateKey} */ this.getUserKeyPair = function(userId, callback) { - // try to read public key from local storage - jsonDao.read(userId + '_publickey', function(pubkey) { - if (!pubkey) { - // no public key in storage - // TODO: fetch from cloud - // TODO: persist in local storage - callback({ - errMsg: 'Not implemented yet!' - }); - } else { - // public key found - // get corresponding private key - fetchEncryptedPrivateKey(pubkey); - } + // loojup public key id + jsonDao.read('publickey_' + userId, function(pubkeyId) { + // try to read public key from local storage + jsonDao.read('publickey_' + pubkeyId._id, function(pubkey) { + if (!pubkey) { + // no public key in storage + // TODO: fetch from cloud + // TODO: persist in local storage + callback({ + errMsg: 'Not implemented yet!' + }); + } else { + // public key found + // get corresponding private key + fetchEncryptedPrivateKey(pubkey); + } + }); }); function fetchEncryptedPrivateKey(publicKey) { // try to read private key from local storage - jsonDao.read(userId + '_privatekey_' + publicKey._id, function(privkey) { + jsonDao.read('privatekey_' + publicKey._id, function(privkey) { if (!privkey) { // no private key in storage // TODO: fetch from cloud @@ -65,7 +68,67 @@ app.dao.KeychainDAO = function(jsonDao, cloudstorage) { * @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!' + }); + return; + } + // persist public key (email, _id) + var pkLookupKey = 'publickey_' + keypair.publicKey.userId; + jsonDao.persist(pkLookupKey, { + _id: keypair.publicKey._id + }, function(res1) { + // validate result + if (res1.key !== pkLookupKey) { + callback({ + errMsg: 'Persisting went wrong!' + }); + return; + } + + // persist public key + var pkKey = 'publickey_' + keypair.publicKey._id; + jsonDao.persist(pkKey, keypair.publicKey, function(res2) { + // validate result + if (res2.key !== pkKey) { + callback({ + errMsg: 'Persisting went wrong!' + }); + return; + } + + // persist public key (email, _id) + var prkLookupKey = 'privatekey_' + keypair.privateKey.userId; + jsonDao.persist(prkLookupKey, { + _id: keypair.privateKey._id + }, function(res3) { + // validate result + if (res3.key !== prkLookupKey) { + callback({ + errMsg: 'Persisting went wrong!' + }); + return; + } + + // persist private key + var prkKey = 'privatekey_' + keypair.privateKey._id; + jsonDao.persist(prkKey, keypair.privateKey, function(res4) { + // validate result + if (res4.key !== prkKey) { + callback({ + errMsg: 'Persisting went wrong!' + }); + return; + } + + callback(null); + }); + }); + }); + }); }; }; \ No newline at end of file diff --git a/test/integration/cloudstorage-dao-test.js b/test/integration/cloudstorage-dao-test.js index fac0045..9a714e6 100644 --- a/test/integration/cloudstorage-dao-test.js +++ b/test/integration/cloudstorage-dao-test.js @@ -10,7 +10,7 @@ var cloudstoragedao_test = { asyncTest("Init", 1, function() { // init dependencies - cloudstoragedao_test.util = new app.crypto.Util(window, uuid); + cloudstoragedao_test.util = new cryptoLib.Util(window, uuid); var jsonDao = new app.dao.LawnchairDAO(window); cloudstoragedao_test.crypto = new app.crypto.Crypto(window, cloudstoragedao_test.util); cloudstoragedao_test.storage = new app.dao.DeviceStorage(cloudstoragedao_test.util, cloudstoragedao_test.crypto, jsonDao, null); @@ -119,22 +119,22 @@ asyncTest("Init", 1, function() { }); }); -// asyncTest("Send Plaintext Email item", 1, function() { +asyncTest("Send Plaintext Email item", 1, function() { -// var email = new app.model.Email({ -// id: cloudstoragedao_test.util.UUID(), -// from: cloudstoragedao_test.user, // sender address -// to: [cloudstoragedao_test.user], // list of receivers -// subject: 'Client Email DAO Test', // Subject line -// body: 'Hello world' // plaintext body -// }); + var email = new app.model.Email({ + id: cloudstoragedao_test.util.UUID(), + from: cloudstoragedao_test.user, // sender address + to: [cloudstoragedao_test.user], // list of receivers + subject: 'Client Email DAO Test', // Subject line + body: 'Hello world' // plaintext body + }); -// cloudstoragedao_test.emailDao.sendEmail(email, function(err) { -// ok(!err, 'Email sent'); + cloudstoragedao_test.emailDao.sendEmail(email, function(err) { + ok(!err, 'Email sent'); -// start(); -// }); -// }); + start(); + }); +}); // asyncTest("Check virtual inbox, re-encrypt and push to cloud", 1, function() { // cloudstoragedao_test.emailDao.checkVInbox(function(err) { @@ -144,14 +144,20 @@ asyncTest("Init", 1, function() { // }); // }); -// asyncTest("Sync emails from cloud", 2, function() { -// cloudstoragedao_test.emailDao.syncFromCloud('inbox', function(err) { -// ok(!err, 'Synced items'); +asyncTest("Sync emails from cloud", 1, function() { + cloudstoragedao_test.emailDao.syncFromCloud('inbox', function(err) { + ok(!err, 'Synced items'); -// cloudstoragedao_test.emailDao.listItems('inbox', 0, null, function(collection) { -// ok(collection.length > 0, 'Read synced items'); + start(); + }); +}); -// start(); -// }); -// }); -// }); \ No newline at end of file +asyncTest("List emails from cloud", 3, function() { + + cloudstoragedao_test.emailDao.listItems('inbox', 0, null, function(err, collection) { + ok(!err); + ok(collection.length > 0, 'Read synced items'); + + start(); + }); +}); \ No newline at end of file diff --git a/test/unit/keychain-dao-test.js b/test/unit/keychain-dao-test.js index 974ce93..dbe4f75 100644 --- a/test/unit/keychain-dao-test.js +++ b/test/unit/keychain-dao-test.js @@ -5,10 +5,10 @@ var keychaindao_test = { password: 'Password', keySize: 128, ivSize: 128, - rsaKeySize: 1024 + rsaKeySize: 512 }; -asyncTest("Init", 1, function() { +asyncTest("Init", 2, function() { // init dependencies var util = new cryptoLib.Util(window, uuid); var jsonDao = new app.dao.LawnchairDAO(window); @@ -26,7 +26,35 @@ asyncTest("Init", 1, function() { keychaindao_test.keychainDao = new app.dao.KeychainDAO(jsonDao, cloudstorageStub); ok(keychaindao_test.keychainDao); - start(); + // clear db before test + jsonDao.clear(function() { + ok(true, 'cleared db'); + + start(); + }); +}); + +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' + } + }; + + keychaindao_test.keychainDao.putUserKeyPair(keychaindao_test.keypair, function(err) { + ok(!err); + + start(); + }); }); asyncTest("Get User Keypair", 2, function() {