diff --git a/src/js/app-router.js b/src/js/app-router.js index 9de5965..59f0b68 100644 --- a/src/js/app-router.js +++ b/src/js/app-router.js @@ -17,12 +17,12 @@ login: function() { // init email dao and dependencies var util = new cryptoLib.Util(window, uuid); - var jsonDao = new app.dao.LawnchairDAO(Lawnchair); var crypto = new app.crypto.Crypto(window, util); var cloudstorage = new app.dao.CloudStorage(window, $); + var jsonDao = new app.dao.LawnchairDAO(Lawnchair); var devicestorage = new app.dao.DeviceStorage(util, crypto, jsonDao, null); var keychain = new app.dao.KeychainDAO(jsonDao, cloudstorage); - this.emailDao = new app.dao.EmailDAO(_, crypto, devicestorage, cloudstorage, util, keychain); + this.emailDao = new app.dao.EmailDAO(jsonDao, crypto, devicestorage, cloudstorage, util, keychain); var loginView = new app.view.LoginView({ dao: this.emailDao diff --git a/src/js/dao/cloudstorage-dao.js b/src/js/dao/cloudstorage-dao.js index 9cd5c8f..3d0ccda 100644 --- a/src/js/dao/cloudstorage-dao.js +++ b/src/js/dao/cloudstorage-dao.js @@ -126,6 +126,36 @@ app.dao.CloudStorage = function(window, $) { }); }; + /** + * Find the user's corresponding public key by email + */ + this.getPublicKeyByUserId = function(userId, callback) { + var uri = app.config.cloudUrl + '/publickey/user/' + userId; + + this.get(uri, function(err, keys) { + if (err) { + callback(err); + return; + } + + if (!keys || keys.length < 1) { + callback({ + errMsg: 'No public key for that user!' + }); + return; + } + + if (keys.length > 1) { + callback({ + errMsg: 'That user has multiple public keys!' + }); + return; + } + + callback(null, keys[0]); + }); + }; + /** * Persist the user's publc key */ diff --git a/src/js/dao/email-dao.js b/src/js/dao/email-dao.js index 0e6d8f0..e54a2dc 100644 --- a/src/js/dao/email-dao.js +++ b/src/js/dao/email-dao.js @@ -2,7 +2,7 @@ * A high-level Data-Access Api for handling Email synchronization * between the cloud service and the device's local storage */ -app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util, keychain) { +app.dao.EmailDAO = function(jsonDB, crypto, devicestorage, cloudstorage, util, keychain) { 'use strict'; /** @@ -11,8 +11,20 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util, keycha this.init = function(account, password, callback) { this.account = account; + // validate email address + var emailAddress = account.get('emailAddress'); + if (!validateEmail(emailAddress)) { + callback({ + errMsg: 'The user email address must be specified!' + }); + return; + } + + // init user's local database + jsonDB.init(emailAddress); + // call getUserKeyPair to read/sync keypair with devicestorage/cloud - keychain.getUserKeyPair(account.get('emailAddress'), function(err, storedKeypair) { + keychain.getUserKeyPair(emailAddress, function(err, storedKeypair) { if (err) { callback(err); return; @@ -23,7 +35,7 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util, keycha function initCrypto(storedKeypair) { crypto.init({ - emailAddress: account.get('emailAddress'), + emailAddress: emailAddress, password: password, keySize: account.get('symKeySize'), rsaKeySize: account.get('asymKeySize'), @@ -201,11 +213,11 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util, keycha cloudstorage.putEncryptedItem(email, 'email', userId, 'outbox', function(err) { callback(err); }); - - function validateEmail(email) { - var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - return re.test(email); - } }; + function validateEmail(email) { + var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return re.test(email); + } + }; \ No newline at end of file diff --git a/src/js/dao/keychain-dao.js b/src/js/dao/keychain-dao.js index e618f91..199e3ef 100644 --- a/src/js/dao/keychain-dao.js +++ b/src/js/dao/keychain-dao.js @@ -50,40 +50,67 @@ app.dao.KeychainDAO = function(jsonDao, cloudstorage) { * return [Object] The user's key pair {publicKey, privateKey} */ this.getUserKeyPair = function(userId, callback) { - // search for user's public key + // search for user's public key locally jsonDao.list('publickey', 0, null, function(allPubkeys) { var pubkey = _.findWhere(allPubkeys, { userId: userId }); - if (!pubkey) { + if (!pubkey || !pubkey._id) { // no public key by that user id in storage - // TODO: find from cloud - // TODO: persist in local storage - callback(); - return; - } + // find from cloud by email address + cloudstorage.getPublicKeyByUserId(userId, function(err, cloudPubkey) { + if (err) { + callback(err); + return; + } - // public key found - // get corresponding private key - fetchEncryptedPrivateKey(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; + } + }); + + } else { + // that user's public key is already in local storage... + // sync keypair to the cloud + syncKeypair(pubkey._id); + } }); - function fetchEncryptedPrivateKey(publicKey) { - // try to read private key from local storage - lookupPrivateKey(publicKey._id, function(err, privkey) { - if (err || !privkey) { - callback({ - errMsg: 'Error looking up private key!', - err: err - }); + function syncKeypair(keypairId) { + // persist key pair in local storage + lookupPublicKey(keypairId, function(err, savedPubkey) { + if (err) { + callback(err); return; } - // private key found - callback(null, { - publicKey: publicKey, - privateKey: privkey + // 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; + } }); }); } diff --git a/test/integration/cloudstorage-dao-test.js b/test/integration/cloudstorage-dao-test.js index 854d10c..b863751 100644 --- a/test/integration/cloudstorage-dao-test.js +++ b/test/integration/cloudstorage-dao-test.js @@ -39,7 +39,7 @@ asyncTest("Init", 1, function() { cloudstoragedao_test.storage = new app.dao.DeviceStorage(cloudstoragedao_test.util, cloudstoragedao_test.crypto, jsonDao, null); cloudstoragedao_test.cloudstorage = new app.dao.CloudStorage(window, $); cloudstoragedao_test.keychain = new app.dao.KeychainDAO(jsonDao, cloudstoragedao_test.cloudstorage); - cloudstoragedao_test.emailDao = new app.dao.EmailDAO(_, cloudstoragedao_test.crypto, cloudstoragedao_test.storage, cloudstoragedao_test.cloudstorage, cloudstoragedao_test.util, cloudstoragedao_test.keychain); + cloudstoragedao_test.emailDao = new app.dao.EmailDAO(jsonDao, cloudstoragedao_test.crypto, cloudstoragedao_test.storage, cloudstoragedao_test.cloudstorage, cloudstoragedao_test.util, cloudstoragedao_test.keychain); // clear db before tests jsonDao.clear(function(err) { @@ -57,7 +57,7 @@ asyncTest("Put public key to cloud", 1, function() { }); }); -asyncTest("Get Public key from cloud", 2, function() { +asyncTest("Get Public key from cloud by id", 2, function() { cloudstoragedao_test.cloudstorage.getPublicKey(cloudstoragedao_test.keypair.publicKey._id, function(err, data) { ok(!err && data && data.publicKey, 'Get public key from cloud'); deepEqual(data, cloudstoragedao_test.keypair.publicKey, 'Public key is equal'); @@ -66,6 +66,15 @@ asyncTest("Get Public key from cloud", 2, function() { }); }); +asyncTest("Get Public key from cloud by email", 2, function() { + cloudstoragedao_test.cloudstorage.getPublicKeyByUserId(cloudstoragedao_test.keypair.publicKey.userId, function(err, data) { + ok(!err && data && data.publicKey, 'Get public key from cloud'); + deepEqual(data, cloudstoragedao_test.keypair.publicKey, 'Public key is equal'); + + start(); + }); +}); + asyncTest("Delete Public key from cloud", 1, function() { cloudstoragedao_test.cloudstorage.removePublicKey(cloudstoragedao_test.keypair.publicKey._id, function(err) { ok(!err, 'Delete public key from cloud'); diff --git a/test/unit/email-dao-test.js b/test/unit/email-dao-test.js index fe96c82..067af45 100644 --- a/test/unit/email-dao-test.js +++ b/test/unit/email-dao-test.js @@ -22,10 +22,13 @@ asyncTest("Init", 3, function() { }, putPrivateKey: function(prk, callback) { callback(); + }, + getPublicKeyByUserId: function(userId, callback) { + callback(); } }; emaildao_test.keychain = new app.dao.KeychainDAO(jsonDao, cloudstorageStub); - emaildao_test.emailDao = new app.dao.EmailDAO(_, emaildao_test.crypto, emaildao_test.storage, cloudstorageStub, util, emaildao_test.keychain); + emaildao_test.emailDao = new app.dao.EmailDAO(jsonDao, emaildao_test.crypto, emaildao_test.storage, cloudstorageStub, util, emaildao_test.keychain); // generate test data emaildao_test.list = new TestData().getEmailCollection(100);