fixed cloudstorage dao it tests

This commit is contained in:
Tankred Hase 2013-05-19 04:00:53 +02:00
parent 6170c38219
commit f9461aaf25
7 changed files with 146 additions and 88 deletions

View File

@ -5,8 +5,11 @@
app.crypto.Crypto = function(window, util) {
'use strict';
var aes = new app.crypto.AesCBC(forge), // use AES-CBC mode by default
rsa = new app.crypto.RSA(forge, util); // use RSA for asym. crypto
var aes = new app.crypto.AesCBC(forge); // use AES-CBC mode by default
var rsa = new app.crypto.RSA(forge, util); // use RSA for asym. crypto
var keyStore = new app.dao.LocalStorageDAO(window);
var storageId; // storage id for the encrypted keypair in local storage
/**
* Initializes the crypto modules by fetching the user's
@ -28,18 +31,18 @@ app.crypto.Crypto = function(window, util) {
this.ivSize = args.keySize;
this.rsaKeySize = args.rsaKeySize;
storageId = self.emailAddress + '_encryptedKeypair';
// derive PBKDF2 from password in web worker thread
this.deriveKey(args.password, args.keySize, function(pbkdf2) {
this.deriveKey(args.password, self.keySize, function(pbkdf2) {
// fetch user's encrypted secret key from keychain/storage
var keyStore = new app.dao.LocalStorageDAO(window);
var storageId = args.emailAddress + '_encryptedKeypair';
var storedKeypair = keyStore.read(storageId);
// check if key exists
if (!storedKeypair) {
// generate keys, encrypt and persist if none exists
generateKeypair(keyStore, storageId, pbkdf2);
generateKeypair(pbkdf2);
} else {
// decrypt key
decryptKeypair(storedKeypair, pbkdf2);
@ -47,7 +50,7 @@ app.crypto.Crypto = function(window, util) {
});
function generateKeypair(keyStore, storageId, pbkdf2) {
function generateKeypair(pbkdf2) {
// generate RSA keypair in web worker
rsa.generateKeypair(self.rsaKeySize, function(err) {
if (err) {
@ -64,7 +67,7 @@ app.crypto.Crypto = function(window, util) {
// store encrypted keypair
var newStoredKeypair = {
_id: keypair._id,
userId: args.emailAddress,
userId: self.emailAddress,
encryptedKey: encryptedKeys,
iv: iv
};
@ -106,6 +109,31 @@ app.crypto.Crypto = function(window, util) {
};
};
/**
* Return a Private Key object containing the encrypted private key
*/
this.getEncryptedPrivateKey = function(emailAddress) {
if (!emailAddress && !storageId) {
throw new Error('Emailaddress needs to be set or crypto needs to be initiated!');
}
var strgId = (storageId) ? storageId : emailAddress + '_encryptedKeypair';
var storedKeypair = keyStore.read(strgId);
return storedKeypair;
};
this.putEncryptedPrivateKey = function(privkey) {
var strgId = (storageId) ? storageId : privkey.userId + '_encryptedKeypair';
// validate private key object
if (!strgId || !privkey || !privkey._id || !privkey.userId || !privkey.encryptedKey || !privkey.iv) {
throw new Error('Invalid encrypted private key object... will not store!');
}
return keyStore.persist(strgId, privkey);
};
/**
* Do PBKDF2 key derivation in a WebWorker thread
*/

View File

@ -143,32 +143,21 @@ app.dao.CloudStorage = function(window, $) {
};
//
// Secret Key
// Ecrypted Private Key
//
/**
* Persist encrypted user key to cloud service
* Persist encrypted private key to cloud service
*/
this.putUserSecretKey = function(emailAddress, callback) {
this.putPrivateKey = function(privkey, callback) {
// fetch user's encrypted secret key from keychain/storage
var keyStore = new app.dao.LocalStorageDAO(window),
storageId = emailAddress + '_encryptedSymmetricKey',
storedKey = keyStore.read(storageId),
uri;
var uri;
if (!storedKey) {
callback({
error: 'err',
status: 'No key found in storage!'
});
return;
}
uri = app.config.cloudUrl + '/secretkey/user/' + emailAddress + '/key/' + storedKey._id;
uri = app.config.cloudUrl + '/privatekey/user/' + privkey.userId + '/key/' + privkey._id;
$.ajax({
url: uri,
type: 'PUT',
data: JSON.stringify(storedKey),
data: JSON.stringify(privkey),
contentType: 'application/json',
success: function() {
callback();
@ -183,17 +172,14 @@ app.dao.CloudStorage = function(window, $) {
};
/**
* Get encrypted user key from cloud service
* Sync encrypted private key from cloud service
*/
this.getUserSecretKey = function(emailAddress, callback, replaceCallback) {
this.syncPrivateKey = function(emailAddress, storedkey, callback, replaceCallback) {
// fetch user's encrypted secret key from keychain/storage
var self = this,
keyStore = new app.dao.LocalStorageDAO(window),
storageId = emailAddress + '_encryptedSymmetricKey',
storedKey = keyStore.read(storageId),
gottenKey, uri;
uri = app.config.cloudUrl + '/secretkey/user/' + emailAddress;
uri = app.config.cloudUrl + '/privatekey/user/' + emailAddress;
$.ajax({
url: uri,
type: 'GET',
@ -223,25 +209,23 @@ app.dao.CloudStorage = function(window, $) {
});
function handleKey(fetchedKey, callback) {
if ((!storedKey || !storedKey.encryptedKey) && fetchedKey && fetchedKey.encryptedKey && fetchedKey.keyIV) {
if ((!storedkey || !storedkey.encryptedKey) && fetchedKey && fetchedKey.encryptedKey) {
// no local key... persist fetched key
keyStore.persist(storageId, fetchedKey);
replaceCallback();
replaceCallback(fetchedKey);
} else if (!fetchedKey && storedKey && storedKey.encryptedKey && storedKey.keyIV) {
} else if (!fetchedKey && storedkey && storedkey.encryptedKey) {
// no key in cloud... push local key to cloud
self.putUserSecretKey(emailAddress, callback);
self.putPrivateKey(storedkey, callback);
} else if (storedKey && fetchedKey && (storedKey.encryptedKey !== fetchedKey.encryptedKey || storedKey.keyIV !== fetchedKey.keyIV)) {
} else if (storedkey && fetchedKey && (storedkey.encryptedKey !== fetchedKey.encryptedKey || storedkey.iv !== fetchedKey.iv)) {
// local and fetched keys are not equal
if (window.confirm('Swap local key?')) {
// replace local key with fetched key
keyStore.persist(storageId, fetchedKey);
replaceCallback();
replaceCallback(fetchedKey);
} else {
if (window.confirm('Swap cloud key?')) {
// upload local key to cloud
self.putUserSecretKey(emailAddress, callback);
self.putPrivateKey(emailAddress, callback);
} else {
callback({
error: 'err',

View File

@ -12,15 +12,18 @@ app.dao.EmailDAO = function(_, crypto, devicestorage, cloudstorage, util) {
this.account = account;
// sync user's cloud key with local storage
cloudstorage.getUserSecretKey(account.get('emailAddress'), function(err) {
var storedKey = crypto.getEncryptedPrivateKey(account.get('emailAddress'));
cloudstorage.syncPrivateKey(account.get('emailAddress'), storedKey, function(err) {
if (err) {
console.log('Error syncing secret key to cloud: ' + err);
}
// init crypto
initCrypto();
}, function() {
// replaced local key with cloud key... whipe local storage
}, function(fetchedKey) {
// replace local key with cloud key
crypto.putEncryptedPrivateKey(fetchedKey);
// whipe local storage
devicestorage.clear(function() {
initCrypto();
});

View File

@ -4,18 +4,18 @@ var cloudstoragedao_test = {
user: 'email.dao.it.test@mail.whiteout.io',
password: 'hellosafe',
keySize: 128,
ivSize: 128
ivSize: 128,
rsaKeySize: 1024
};
asyncTest("Init", 1, function() {
// init dependencies
cloudstoragedao_test.util = new app.crypto.Util(window, uuid);
var jsonDao = new app.dao.LawnchairDAO(window);
var crypto = new app.crypto.Crypto(window, cloudstoragedao_test.util);
var naclCrypto = new app.crypto.NaclCrypto(nacl, cloudstoragedao_test.util);
cloudstoragedao_test.storage = new app.dao.DeviceStorage(cloudstoragedao_test.util, crypto, jsonDao, null);
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);
cloudstoragedao_test.cloudstorage = new app.dao.CloudStorage(window, $);
cloudstoragedao_test.emailDao = new app.dao.EmailDAO(_, crypto, cloudstoragedao_test.storage, cloudstoragedao_test.cloudstorage, naclCrypto, cloudstoragedao_test.util);
cloudstoragedao_test.emailDao = new app.dao.EmailDAO(_, cloudstoragedao_test.crypto, cloudstoragedao_test.storage, cloudstoragedao_test.cloudstorage, cloudstoragedao_test.util);
// clear db before tests
jsonDao.clear(function(err) {
@ -28,11 +28,33 @@ asyncTest("Init", 1, function() {
asyncTest("Persist public key to cloud", 1, function() {
// testdata
cloudstoragedao_test.privateKey = "Bv51afjeuH8CatKo75HOHQRT1B3amvF+DEwijka79nA=";
cloudstoragedao_test.privateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" +
"MIICXAIBAAKBgQDK6H7BiPcwiRWnWDuqndw+t+3vIhSmwEEn38kPLenbd+iWb2dX\r\n" +
"M5y5aBFIgqqHBrcZLwzhMQ10BUTcOgB6Kr3AK7lONKxZ+HD5hX6koj9X5uHtFYF1\r\n" +
"NYkQv+5WKzHGHRFqoKityZ6AqTxgPss29s6EIOqF/dvvKMiFhgp+4JPsJQIDAQAB\r\n" +
"AoGAQxIM7C44/zshBDrfJiueJMEpjhUm3GPKZcLMNA9KMPh20lsqvqFZ2dNzexNu\r\n" +
"CMoIdfOef0V2m/Yt59noVHmSVL7itN4nvbTcD39UQacFiyzT7GRQjeaVAs8ZyeO5\r\n" +
"2AXtJTNipEyvJ3TbJZCOCML/wOEvCimyHLNCMcoDvkjAbMECQQD81xbRonOZt/7E\r\n" +
"fBHZQonaTQU/x88l8bXDHvcPfMfg4QkPO+pZ8dBQ4+IpuG60kl4TSmmme4frcJoj\r\n" +
"jSqd54VVAkEAzXGon2gP+9ZjhbOWESpw+JXiRBytAgailnblFnCJt+o+UoXU8hwH\r\n" +
"1D5rG2yOIO1vOiqGDQq/Bs61DsfeotvLkQJBAKo6tmZWFba9Jo5raij4n4+Wo54Z\r\n" +
"jOJjJplEU9rdjEVfvZXAJTyBjlun0jF8tyxkD2q1gwRPz2c43M5q0PKXWjECQCl4\r\n" +
"UO5khh1yyEIb3yX16Dn1n2faVf37suQmedXOv631RcFIrJR2ngn005AEmKgC5Znb\r\n" +
"LZYCXk8UeK3UIJfFQFECQGkP1NPyd10Z76LR0lXeL15iP22M/OCaQUIsSi/S+idL\r\n" +
"YCVcgDpdgVXef0NeNk6w821rlqUjseZyGGKpJ4VNywU=\r\n" +
"-----END RSA PRIVATE KEY-----";
var pk = "-----BEGIN PUBLIC KEY-----\r\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK6H7BiPcwiRWnWDuqndw+t+3v\r\n" +
"IhSmwEEn38kPLenbd+iWb2dXM5y5aBFIgqqHBrcZLwzhMQ10BUTcOgB6Kr3AK7lO\r\n" +
"NKxZ+HD5hX6koj9X5uHtFYF1NYkQv+5WKzHGHRFqoKityZ6AqTxgPss29s6EIOqF\r\n" +
"/dvvKMiFhgp+4JPsJQIDAQAB\r\n" +
"-----END PUBLIC KEY-----";
cloudstoragedao_test.publicKey = new app.model.PublicKey({
_id: "da4bfa93-ba87-490e-877c-e4020a6f6729",
_id: "e91f04a2-a634-42df-a1a4-6a7f1448dbf6",
userId: 'integration@atlasdev.onmicrosoft.com',
publicKey: "yHUhh3Pcbjmh2k367pSXfE8hDwPsAxQs0QETm9mfmz0="
publicKey: pk
});
cloudstoragedao_test.cloudstorage.putPublicKey(cloudstoragedao_test.publicKey.toJSON(), function(err) {
@ -51,12 +73,15 @@ asyncTest("Get Public key from cloud", 2, function() {
});
});
asyncTest("Get user secret key from cloud", 1, function() {
cloudstoragedao_test.cloudstorage.getUserSecretKey(cloudstoragedao_test.user, function(err) {
asyncTest("Sync private key from cloud", 1, function() {
cloudstoragedao_test.cloudstorage.syncPrivateKey(cloudstoragedao_test.user, null, function(err) {
ok(!err, 'Get/Sync key from cloud');
start();
}, function() {
}, function(fetchedKey) {
// replace local key with cloud key
cloudstoragedao_test.crypto.putEncryptedPrivateKey(fetchedKey);
// whipe local storage
cloudstoragedao_test.storage.clear(function(err) {
ok(!err, 'DB cleared. Error status: ' + err);
@ -65,8 +90,10 @@ asyncTest("Get user secret key from cloud", 1, function() {
});
});
asyncTest("Persist user secret key to cloud", 1, function() {
cloudstoragedao_test.cloudstorage.putUserSecretKey(cloudstoragedao_test.user, function(err) {
asyncTest("Persist private key to cloud", 1, function() {
var storedKey = cloudstoragedao_test.crypto.getEncryptedPrivateKey(cloudstoragedao_test.user);
cloudstoragedao_test.cloudstorage.putPrivateKey(storedKey, function(err) {
ok(!err, 'Persist key to cloud');
start();
@ -81,7 +108,8 @@ asyncTest("Init", 1, function() {
var account = new app.model.Account({
emailAddress: cloudstoragedao_test.user,
symKeySize: cloudstoragedao_test.keySize,
symIvSize: cloudstoragedao_test.ivSize
symIvSize: cloudstoragedao_test.ivSize,
asymKeySize: cloudstoragedao_test.rsaKeySize
});
cloudstoragedao_test.emailDao.init(account, cloudstoragedao_test.password, function(err) {
@ -91,39 +119,39 @@ 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) {
ok(!err, 'Synced items');
// asyncTest("Check virtual inbox, re-encrypt and push to cloud", 1, function() {
// cloudstoragedao_test.emailDao.checkVInbox(function(err) {
// ok(!err, 'Synced items');
start();
});
});
// start();
// });
// });
asyncTest("Sync emails from cloud", 2, function() {
cloudstoragedao_test.emailDao.syncFromCloud('inbox', function(err) {
ok(!err, 'Synced items');
// asyncTest("Sync emails from cloud", 2, 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');
// cloudstoragedao_test.emailDao.listItems('inbox', 0, null, function(collection) {
// ok(collection.length > 0, 'Read synced items');
start();
});
});
});
// start();
// });
// });
// });

View File

@ -32,6 +32,19 @@ test("Get Public Key PEM", 2, function() {
ok(pk.publicKey.indexOf('-----BEGIN PUBLIC KEY-----') === 0, pk.publicKey);
});
test("Get Encrypted Private Key", 2, function() {
var prk = crypto_test.crypto.getEncryptedPrivateKey();
ok(prk._id && prk.userId, 'Key ID: ' + prk._id);
ok(prk.encryptedKey, prk.encryptedKey);
crypto_test.prk = prk;
});
test("Put Encrypted Private Key", 1, function() {
crypto_test.crypto.putEncryptedPrivateKey(crypto_test.prk);
ok(true);
});
asyncTest("PBKDF2 (Async/Worker)", 1, function() {
crypto_test.crypto.deriveKey(crypto_test.password, crypto_test.keySize, function(key) {
equal(crypto_test.util.base642Str(key).length * 8, crypto_test.keySize, 'Keysize ' + crypto_test.keySize);

View File

@ -4,7 +4,8 @@ var devicestorage_test = {
user: 'devicestorage_test@example.com',
password: 'Password',
keySize: 128,
ivSize: 128
ivSize: 128,
rsaKeySize: 1024
};
asyncTest("Init", 3, function() {
@ -22,7 +23,8 @@ asyncTest("Init", 3, function() {
devicestorage_test.crypto.init({
emailAddress: devicestorage_test.user,
password: devicestorage_test.password,
keySize: devicestorage_test.keySize
keySize: devicestorage_test.keySize,
rsaKeySize: devicestorage_test.rsaKeySize
}, function(err) {
ok(!err, 'Init crypto');

View File

@ -16,7 +16,7 @@ asyncTest("Init", 3, function() {
emaildao_test.storage = new app.dao.DeviceStorage(util, emaildao_test.crypto, jsonDao, null);
// cloud storage stub
var cloudstorageStub = {
getUserSecretKey: function(emailAdress, callback) {
syncPrivateKey: function(emailAdress, storedKey, callback) {
callback();
},
putPublicKey: function(pk, callback) {