From 628cb0ddd944b9fa4472a715d5ae6f087579c24c Mon Sep 17 00:00:00 2001 From: Tankred Hase <tankred@whiteout.io> Date: Fri, 30 Aug 2013 16:05:33 +0200 Subject: [PATCH] crypto error handling cleanup --- src/js/crypto/aes-cbc.js | 134 ++++--- src/js/crypto/crypto-batch-worker.js | 59 ++- src/js/crypto/crypto-batch.js | 4 +- src/js/crypto/crypto.js | 529 ++++++++++++++------------- src/js/dao/email-dao.js | 11 +- test/new-unit/email-dao-test.js | 2 +- 6 files changed, 399 insertions(+), 340 deletions(-) diff --git a/src/js/crypto/aes-cbc.js b/src/js/crypto/aes-cbc.js index 91e317a..6f5ad6f 100644 --- a/src/js/crypto/aes-cbc.js +++ b/src/js/crypto/aes-cbc.js @@ -1,69 +1,91 @@ (function() { - 'use strict'; + 'use strict'; - /** - * A Wrapper for Forge's AES-CBC encryption - */ - var AesCBC = function(forge) { + /** + * A Wrapper for Forge's AES-CBC encryption + */ + var AesCBC = function(forge) { + this._forge = forge; + }; - var utl = forge.util; + /** + * Encrypt a String using AES-CBC-Pkcs7 using the provided keysize (e.g. 128, 256) + * @param plaintext [String] The input string in UTF-16 + * @param key [String] The base64 encoded key + * @param iv [String] The base64 encoded IV + * @return [String] The base64 encoded ciphertext + */ + AesCBC.prototype.encrypt = function(plaintext, key, iv) { + // validate args + if (!plaintext || !key || !iv) { + throw new Error("Missing args for encryption!"); + } - /** - * Encrypt a String using AES-CBC-Pkcs7 using the provided keysize (e.g. 128, 256) - * @param plaintext [String] The input string in UTF-16 - * @param key [String] The base64 encoded key - * @param iv [String] The base64 encoded IV - * @return [String] The base64 encoded ciphertext - */ - this.encrypt = function(plaintext, key, iv) { - // validate args - if (!plaintext || !key || !iv) { - throw new Error("Missing args for encryption!"); - } + // decode args to utf8 and encrypt + var cipher = this._forge.aes.createEncryptionCipher(this._forge.util.decode64(key)); + cipher.start(this._forge.util.decode64(iv)); + cipher.update(this._forge.util.createBuffer(this._forge.util.encodeUtf8(plaintext))); + cipher.finish(); - // decode args to utf8 and encrypt - var cipher = forge.aes.createEncryptionCipher(utl.decode64(key)); - cipher.start(utl.decode64(iv)); - cipher.update(utl.createBuffer(utl.encodeUtf8(plaintext))); - cipher.finish(); + // encode to base64 + return this._forge.util.encode64(cipher.output.getBytes()); + }; - // encode to base64 - return utl.encode64(cipher.output.getBytes()); - }; + /** + * Decrypt a String using AES-CBC-Pkcs7 using the provided keysize (e.g. 128, 256) + * @param ciphertext [String] The base64 encoded ciphertext + * @param key [String] The base64 encoded key + * @param iv [String] The base64 encoded IV + * @return [String] The decrypted plaintext in UTF-16 + */ + AesCBC.prototype.decrypt = function(ciphertext, key, iv) { + // validate args + if (!ciphertext || !key || !iv) { + throw new Error("Missing args for decryption!"); + } - /** - * Decrypt a String using AES-CBC-Pkcs7 using the provided keysize (e.g. 128, 256) - * @param ciphertext [String] The base64 encoded ciphertext - * @param key [String] The base64 encoded key - * @param iv [String] The base64 encoded IV - * @return [String] The decrypted plaintext in UTF-16 - */ - this.decrypt = function(ciphertext, key, iv) { - // validate args - if (!ciphertext || !key || !iv) { - throw new Error("Missing args for decryption!"); - } + // decode args input to utf8 decrypt + var cipher = this._forge.aes.createDecryptionCipher(this._forge.util.decode64(key)); + cipher.start(this._forge.util.decode64(iv)); + cipher.update(this._forge.util.createBuffer(this._forge.util.decode64(ciphertext))); + cipher.finish(); - // decode args input to utf8 decrypt - var cipher = forge.aes.createDecryptionCipher(utl.decode64(key)); - cipher.start(utl.decode64(iv)); - cipher.update(utl.createBuffer(utl.decode64(ciphertext))); - cipher.finish(); + // decode to utf16 + return this._forge.util.decodeUtf8(cipher.output.getBytes()); + }; - // decode to utf16 - return utl.decodeUtf8(cipher.output.getBytes()); - }; + /** + * Calculate a hmac using SHA-256 for a given input + * @param parts [Array] Array of Base64 encoded parts + * @param key [String] The base64 encoded key + * @return [String] The Base64 encoded hmac + */ + AesCBC.prototype.hmac = function(parts, key) { + var self = this; - }; + // validate args + if (!parts || !key) { + throw new Error("Missing args for hmac processing!"); + } - if (typeof define !== 'undefined' && define.amd) { - // AMD - define(['forge'], function(forge) { - return new AesCBC(forge); - }); - } else if (typeof module !== 'undefined' && module.exports) { - // node.js - module.exports = new AesCBC(require('node-forge')); - } + var hmac = self._forge.hmac.create(); + hmac.start('sha256', self._forge.util.decode64(key)); + parts.forEach(function(i) { + // decode base64 part and append to hmac msg + hmac.update(self._forge.util.decode64(i)); + }); + + return self._forge.util.encode64(hmac.digest().getBytes()); + }; + + if (typeof define !== 'undefined' && define.amd) { + // AMD + define(['forge'], function(forge) { + return new AesCBC(forge); + }); + } else if (typeof module !== 'undefined' && module.exports) { + // node.js + module.exports = new AesCBC(require('node-forge')); + } })(); \ No newline at end of file diff --git a/src/js/crypto/crypto-batch-worker.js b/src/js/crypto/crypto-batch-worker.js index e476624..05a06cd 100644 --- a/src/js/crypto/crypto-batch-worker.js +++ b/src/js/crypto/crypto-batch-worker.js @@ -17,27 +17,16 @@ require(['cryptoLib/crypto-batch'], function(batch) { - var i = e.data, - output = null; + var output; - if (i.type === 'encrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) { - // start encryption - output = batch.encryptListForUser(i.list, i.receiverPubkeys, i.senderPrivkey); - - } else if (i.type === 'decrypt' && i.senderPubkeys && i.receiverPrivkey && i.list) { - // start decryption - output = batch.decryptListForUser(i.list, i.senderPubkeys, i.receiverPrivkey); - - } else if (i.type === 'reencrypt' && i.senderPubkeys && i.receiverPrivkey && i.list && i.symKey) { - // start validation and re-encryption - output = batch.reencryptListKeysForUser(i.list, i.senderPubkeys, i.receiverPrivkey, i.symKey); - - } else if (i.type === 'decryptItems' && i.symKey && i.list) { - // start decryption - output = batch.decryptKeysAndList(i.list, i.symKey); - - } else { - throw 'Not all arguments for web worker crypto are defined!'; + try { + output = doOperation(batch, e.data); + } catch (e) { + output = { + err: { + errMsg: (e.message) ? e.message : e + } + }; } // pass output back to main thread @@ -47,4 +36,34 @@ }); }; + function doOperation(batch, i) { + var output; + + if (i.type === 'encrypt' && i.receiverPubkeys && i.senderPrivkey && i.list) { + // start encryption + output = batch.encryptListForUser(i.list, i.receiverPubkeys, i.senderPrivkey); + + } else if (i.type === 'decrypt' && i.senderPubkeys && i.receiverPrivkey && i.list) { + // start decryption + output = batch.decryptListForUser(i.list, i.senderPubkeys, i.receiverPrivkey); + + } else if (i.type === 'reencrypt' && i.senderPubkeys && i.receiverPrivkey && i.list && i.symKey) { + // start validation and re-encryption + output = batch.reencryptListKeysForUser(i.list, i.senderPubkeys, i.receiverPrivkey, i.symKey); + + } else if (i.type === 'decryptItems' && i.symKey && i.list) { + // start decryption + output = batch.decryptKeysAndList(i.list, i.symKey); + + } else { + output = { + err: { + errMsg: 'Not all arguments for web worker crypto are defined!' + } + }; + } + + return output; + } + }()); \ No newline at end of file diff --git a/src/js/crypto/crypto-batch.js b/src/js/crypto/crypto-batch.js index 76ca295..66a865a 100644 --- a/src/js/crypto/crypto-batch.js +++ b/src/js/crypto/crypto-batch.js @@ -28,7 +28,7 @@ // set sender's keypair id for later verification i.senderPk = senderKeyId; // sign the bundle - i.signature = rsa.sign([i.iv, util.str2Base64(i.id), util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext]); + i.signature = rsa.sign([i.iv, util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext]); // delete plaintext values delete i.plaintext; @@ -79,7 +79,7 @@ rsa.init(senderPubkey); // verify signature - if (!rsa.verify([i.iv, util.str2Base64(i.id), util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext], i.signature)) { + if (!rsa.verify([i.iv, util.str2Base64(i.senderPk), i.encryptedKey, i.ciphertext], i.signature)) { throw new Error('Verifying RSA signature failed!'); } // decrypt symmetric item key for user diff --git a/src/js/crypto/crypto.js b/src/js/crypto/crypto.js index f5da833..499df2c 100644 --- a/src/js/crypto/crypto.js +++ b/src/js/crypto/crypto.js @@ -2,305 +2,322 @@ * High level crypto api that invokes native crypto (if available) and * gracefully degrades to JS crypto (if unavailable) */ -define(['cryptoLib/util', 'cryptoLib/aes-cbc', 'cryptoLib/rsa', 'cryptoLib/crypto-batch', - 'js/crypto/pbkdf2', 'js/app-config' -], function(util, aes, rsa, cryptoBatch, pbkdf2, app) { - 'use strict'; +define(function(require) { + 'use strict'; - var self = {}; + var util = require('cryptoLib/util'), + aes = require('cryptoLib/aes-cbc'), + rsa = require('cryptoLib/rsa'), + cryptoBatch = require('cryptoLib/crypto-batch'), + pbkdf2 = require('js/crypto/pbkdf2'), + app = require('js/app-config'); - var passBasedKey; + var self = {}, + passBasedKey; - /** - * Initializes the crypto modules by fetching the user's - * encrypted secret key from storage and storing it in memory. - */ - self.init = function(args, callback) { - // valdiate input - if (!args.emailAddress || !args.keySize || !args.rsaKeySize) { - callback({ - errMsg: 'Crypto init failed. Not all args set!' - }); - return; - } + /** + * Initializes the crypto modules by fetching the user's + * encrypted secret key from storage and storing it in memory. + */ + self.init = function(args, callback) { + // valdiate input + if (!args.emailAddress || !args.keySize || !args.rsaKeySize) { + callback({ + errMsg: 'Crypto init failed. Not all args set!' + }); + return; + } - self.emailAddress = args.emailAddress; - self.keySize = args.keySize; - self.ivSize = args.keySize; - self.rsaKeySize = args.rsaKeySize; + self.emailAddress = args.emailAddress; + self.keySize = args.keySize; + self.ivSize = args.keySize; + self.rsaKeySize = args.rsaKeySize; - // derive PBKDF2 from password in web worker thread - self.deriveKey(args.password, self.keySize, function(err, derivedKey) { - if (err) { - callback(err); - return; - } + // derive PBKDF2 from password in web worker thread + self.deriveKey(args.password, self.keySize, function(err, derivedKey) { + if (err) { + callback(err); + return; + } - // remember pbkdf2 for later use - passBasedKey = derivedKey; + // remember pbkdf2 for later use + passBasedKey = derivedKey; - // check if key exists - if (!args.storedKeypair) { - // generate keys, encrypt and persist if none exists - generateKeypair(derivedKey); - } else { - // decrypt key - decryptKeypair(args.storedKeypair, derivedKey); - } + // check if key exists + if (!args.storedKeypair) { + // generate keys, encrypt and persist if none exists + generateKeypair(derivedKey); + } else { + // decrypt key + decryptKeypair(args.storedKeypair, derivedKey); + } - }); + }); - function generateKeypair(derivedKey) { - // generate RSA keypair in web worker - rsa.generateKeypair(self.rsaKeySize, function(err, generatedKeypair) { - if (err) { - callback(err); - return; - } + function generateKeypair(derivedKey) { + // generate RSA keypair in web worker + rsa.generateKeypair(self.rsaKeySize, function(err, generatedKeypair) { + if (err) { + callback(err); + return; + } - // encrypt keypair - var iv = util.random(self.ivSize); - var encryptedPrivateKey = aes.encrypt(generatedKeypair.privkeyPem, derivedKey, iv); + // encrypt keypair + var iv = util.random(self.ivSize); + var encryptedPrivateKey = aes.encrypt(generatedKeypair.privkeyPem, derivedKey, iv); - // new encrypted keypair object - var newKeypair = { - publicKey: { - _id: generatedKeypair._id, - userId: self.emailAddress, - publicKey: generatedKeypair.pubkeyPem - }, - privateKey: { - _id: generatedKeypair._id, - userId: self.emailAddress, - encryptedKey: encryptedPrivateKey, - iv: iv - } - }; + // new encrypted keypair object + var newKeypair = { + publicKey: { + _id: generatedKeypair._id, + userId: self.emailAddress, + publicKey: generatedKeypair.pubkeyPem + }, + privateKey: { + _id: generatedKeypair._id, + userId: self.emailAddress, + encryptedKey: encryptedPrivateKey, + iv: iv + } + }; - // return generated keypair for storage in keychain dao - callback(null, newKeypair); - }); - } + // return generated keypair for storage in keychain dao + callback(null, newKeypair); + }); + } - function decryptKeypair(storedKeypair, derivedKey) { - var decryptedPrivateKey; + function decryptKeypair(storedKeypair, derivedKey) { + var decryptedPrivateKey; - // validate input - if (!storedKeypair || !storedKeypair.privateKey || !storedKeypair.privateKey.encryptedKey || !storedKeypair.privateKey.iv) { - callback({ - errMsg: 'Incomplete arguments for private key decryption!' - }); - return; - } + // validate input + if (!storedKeypair || !storedKeypair.privateKey || !storedKeypair.privateKey.encryptedKey || !storedKeypair.privateKey.iv) { + callback({ + errMsg: 'Incomplete arguments for private key decryption!' + }); + return; + } - // try to decrypt with derivedKey - try { - var prK = storedKeypair.privateKey; - decryptedPrivateKey = aes.decrypt(prK.encryptedKey, derivedKey, prK.iv); - } catch (ex) { - callback({ - errMsg: 'Wrong password!' - }); - return; - } - // set rsa keys - rsa.init(storedKeypair.publicKey.publicKey, decryptedPrivateKey, storedKeypair.publicKey._id); + // try to decrypt with derivedKey + try { + var prK = storedKeypair.privateKey; + decryptedPrivateKey = aes.decrypt(prK.encryptedKey, derivedKey, prK.iv); + } catch (ex) { + callback({ + errMsg: 'Wrong password!' + }); + return; + } + // set rsa keys + rsa.init(storedKeypair.publicKey.publicKey, decryptedPrivateKey, storedKeypair.publicKey._id); - callback(); - } - }; + callback(); + } + }; - /** - * Do PBKDF2 key derivation in a WebWorker thread - */ - self.deriveKey = function(password, keySize, callback) { - startWorker('/crypto/pbkdf2-worker.js', { - password: password, - keySize: keySize - }, callback, function() { - return pbkdf2.getKey(password, keySize); - }); - }; + /** + * Do PBKDF2 key derivation in a WebWorker thread + */ + self.deriveKey = function(password, keySize, callback) { + startWorker('/crypto/pbkdf2-worker.js', { + password: password, + keySize: keySize + }, callback, function() { + return pbkdf2.getKey(password, keySize); + }); + }; - // - // En/Decrypts single item - // + // + // En/Decrypts single item + // - self.aesEncrypt = function(plaintext, key, iv, callback) { - startWorker('/crypto/aes-worker.js', { - type: 'encrypt', - plaintext: plaintext, - key: key, - iv: iv - }, callback, function() { - return self.aesEncryptSync(plaintext, key, iv); - }); - }; + self.aesEncrypt = function(plaintext, key, iv, callback) { + startWorker('/crypto/aes-worker.js', { + type: 'encrypt', + plaintext: plaintext, + key: key, + iv: iv + }, callback, function() { + return self.aesEncryptSync(plaintext, key, iv); + }); + }; - self.aesDecrypt = function(ciphertext, key, iv, callback) { - startWorker('/crypto/aes-worker.js', { - type: 'decrypt', - ciphertext: ciphertext, - key: key, - iv: iv - }, callback, function() { - return self.aesDecryptSync(ciphertext, key, iv); - }); - }; + self.aesDecrypt = function(ciphertext, key, iv, callback) { + startWorker('/crypto/aes-worker.js', { + type: 'decrypt', + ciphertext: ciphertext, + key: key, + iv: iv + }, callback, function() { + return self.aesDecryptSync(ciphertext, key, iv); + }); + }; - self.aesEncryptSync = function(plaintext, key, iv) { - return aes.encrypt(plaintext, key, iv); - }; + self.aesEncryptSync = function(plaintext, key, iv) { + return aes.encrypt(plaintext, key, iv); + }; - self.aesDecryptSync = function(ciphertext, key, iv) { - return aes.decrypt(ciphertext, key, iv); - }; + self.aesDecryptSync = function(ciphertext, key, iv) { + return aes.decrypt(ciphertext, key, iv); + }; - // - // En/Decrypt a list of items with AES in a WebWorker thread - // + // + // En/Decrypt a list of items with AES in a WebWorker thread + // - self.aesEncryptList = function(list, callback) { - startWorker('/crypto/aes-batch-worker.js', { - type: 'encrypt', - list: list - }, callback, function() { - return cryptoBatch.encryptList(list); - }); - }; + self.aesEncryptList = function(list, callback) { + startWorker('/crypto/aes-batch-worker.js', { + type: 'encrypt', + list: list + }, callback, function() { + return cryptoBatch.encryptList(list); + }); + }; - self.aesDecryptList = function(list, callback) { - startWorker('/crypto/aes-batch-worker.js', { - type: 'decrypt', - list: list - }, callback, function() { - return cryptoBatch.decryptList(list); - }); - }; + self.aesDecryptList = function(list, callback) { + startWorker('/crypto/aes-batch-worker.js', { + type: 'decrypt', + list: list + }, callback, function() { + return cryptoBatch.decryptList(list); + }); + }; - // - // En/Decrypt something speficially using the user's secret key - // + // + // En/Decrypt something speficially using the user's secret key + // - self.encryptListForUser = function(list, receiverPubkeys, callback) { - var envelope, envelopes = []; + self.encryptListForUser = function(list, receiverPubkeys, callback) { + var envelope, envelopes = []; - if (!receiverPubkeys || receiverPubkeys.length !== 1) { - callback({ - errMsg: 'Encryption is currently implemented for only one receiver!' - }); - return; - } + if (!receiverPubkeys || receiverPubkeys.length !== 1) { + callback({ + errMsg: 'Encryption is currently implemented for only one receiver!' + }); + return; + } - var keypair = rsa.exportKeys(); - var senderPrivkey = { - _id: keypair._id, - privateKey: keypair.privkeyPem - }; + var keypair = rsa.exportKeys(); + var senderPrivkey = { + _id: keypair._id, + privateKey: keypair.privkeyPem + }; - // package objects into batchable envelope format - list.forEach(function(i) { - envelope = { - id: i.id, - plaintext: i, - key: util.random(self.keySize), - iv: util.random(self.ivSize), - receiverPk: receiverPubkeys[0]._id - }; - envelopes.push(envelope); - }); + // package objects into batchable envelope format + list.forEach(function(i) { + envelope = { + id: i.id, + plaintext: i, + key: util.random(self.keySize), + iv: util.random(self.ivSize), + receiverPk: receiverPubkeys[0]._id + }; + envelopes.push(envelope); + }); - startWorker('/crypto/crypto-batch-worker.js', { - type: 'encrypt', - list: envelopes, - senderPrivkey: senderPrivkey, - receiverPubkeys: receiverPubkeys - }, callback, function() { - return cryptoBatch.encryptListForUser(envelopes, receiverPubkeys, senderPrivkey); - }); - }; + startWorker('/crypto/crypto-batch-worker.js', { + type: 'encrypt', + list: envelopes, + senderPrivkey: senderPrivkey, + receiverPubkeys: receiverPubkeys + }, callback, function() { + return cryptoBatch.encryptListForUser(envelopes, receiverPubkeys, senderPrivkey); + }); + }; - self.decryptListForUser = function(list, senderPubkeys, callback) { - if (!senderPubkeys || senderPubkeys < 1) { - callback({ - errMsg: 'Sender public keys must be set!' - }); - return; - } + self.decryptListForUser = function(list, senderPubkeys, callback) { + if (!senderPubkeys || senderPubkeys < 1) { + callback({ + errMsg: 'Sender public keys must be set!' + }); + return; + } - var keypair = rsa.exportKeys(); - var receiverPrivkey = { - _id: keypair._id, - privateKey: keypair.privkeyPem - }; + var keypair = rsa.exportKeys(); + var receiverPrivkey = { + _id: keypair._id, + privateKey: keypair.privkeyPem + }; - startWorker('/crypto/crypto-batch-worker.js', { - type: 'decrypt', - list: list, - receiverPrivkey: receiverPrivkey, - senderPubkeys: senderPubkeys - }, callback, function() { - return cryptoBatch.decryptListForUser(list, senderPubkeys, receiverPrivkey); - }); - }; + startWorker('/crypto/crypto-batch-worker.js', { + type: 'decrypt', + list: list, + receiverPrivkey: receiverPrivkey, + senderPubkeys: senderPubkeys + }, callback, function() { + return cryptoBatch.decryptListForUser(list, senderPubkeys, receiverPrivkey); + }); + }; - // - // Re-encrypt keys item and items seperately - // + // + // Re-encrypt keys item and items seperately + // - self.reencryptListKeysForUser = function(list, senderPubkeys, callback) { - var keypair = rsa.exportKeys(); - var receiverPrivkey = { - _id: keypair._id, - privateKey: keypair.privkeyPem - }; + self.reencryptListKeysForUser = function(list, senderPubkeys, callback) { + var keypair = rsa.exportKeys(); + var receiverPrivkey = { + _id: keypair._id, + privateKey: keypair.privkeyPem + }; - startWorker('/crypto/crypto-batch-worker.js', { - type: 'reencrypt', - list: list, - receiverPrivkey: receiverPrivkey, - senderPubkeys: senderPubkeys, - symKey: passBasedKey - }, callback, function() { - return cryptoBatch.reencryptListKeysForUser(list, senderPubkeys, receiverPrivkey, passBasedKey); - }); - }; + startWorker('/crypto/crypto-batch-worker.js', { + type: 'reencrypt', + list: list, + receiverPrivkey: receiverPrivkey, + senderPubkeys: senderPubkeys, + symKey: passBasedKey + }, callback, function() { + return cryptoBatch.reencryptListKeysForUser(list, senderPubkeys, receiverPrivkey, passBasedKey); + }); + }; - self.decryptKeysAndList = function(list, callback) { - startWorker('/crypto/crypto-batch-worker.js', { - type: 'decryptItems', - list: list, - symKey: passBasedKey - }, callback, function() { - return cryptoBatch.decryptKeysAndList(list, passBasedKey); - }); - }; + self.decryptKeysAndList = function(list, callback) { + startWorker('/crypto/crypto-batch-worker.js', { + type: 'decryptItems', + list: list, + symKey: passBasedKey + }, callback, function() { + return cryptoBatch.decryptKeysAndList(list, passBasedKey); + }); + }; - // - // helper functions - // + // + // helper functions + // - function startWorker(script, args, callback, noWorker) { - // check for WebWorker support - if (window.Worker) { + function startWorker(script, args, callback, noWorker) { + // check for WebWorker support + if (window.Worker) { - // init webworker thread - var worker = new Worker(app.config.workerPath + script); + // init webworker thread + var worker = new Worker(app.config.workerPath + script); - worker.onmessage = function(e) { - // return derived key from the worker - callback(null, e.data); - }; + worker.onmessage = function(e) { + if (e.data.err) { + callback(e.data.err); + return; + } + // return result from the worker + callback(null, e.data); + }; - // send data to the worker - worker.postMessage(args); + // send data to the worker + worker.postMessage(args); - } else { - // no WebWorker support... do synchronous call - var result = noWorker(); - callback(null, result); - } - } + } else { + // no WebWorker support... do synchronous call + var result; + try { + result = noWorker(); + } catch (e) { + callback({ + errMsg: (e.message) ? e.message : e + }); + return; + } - return self; + callback(null, result); + } + } + + return self; }); \ No newline at end of file diff --git a/src/js/dao/email-dao.js b/src/js/dao/email-dao.js index b03beaf..579c1a7 100644 --- a/src/js/dao/email-dao.js +++ b/src/js/dao/email-dao.js @@ -298,7 +298,7 @@ define(function(require) { /* message was not found in cache... fetch from imap server */ - function messageReady(err, gottenMessage) { + function bodyReady(err, gottenMessage) { message = gottenMessage; itemCounter++; // remember how many items should be fetched before the callback fires @@ -311,10 +311,10 @@ define(function(require) { // decrypt Message body if (message.body.indexOf(PREFIX) !== -1 && message.body.indexOf(SUFFIX) !== -1) { - decryptMessageBody(message, function(err, ptMessage) { + decryptBody(message, function(err, ptMessage) { message = ptMessage; // return decrypted message - callback(null, message); + callback(err, message); }); return; } @@ -325,7 +325,7 @@ define(function(require) { //check(); } - function decryptMessageBody(email, callback) { + function decryptBody(email, callback) { var ctMessageBase64, ctMessage, pubkeyIds; // parse email body for encrypted message block @@ -390,7 +390,8 @@ define(function(require) { self._imapClient.getMessage({ path: options.folder, uid: options.uid, - onMessage: messageReady, + onBody: bodyReady, + onEnd: bodyReady /*onAttachment: attachmentReady*/ }); }; diff --git a/test/new-unit/email-dao-test.js b/test/new-unit/email-dao-test.js index 77199c8..1f2d944 100644 --- a/test/new-unit/email-dao-test.js +++ b/test/new-unit/email-dao-test.js @@ -272,7 +272,7 @@ define(function(require) { it('should parse message body without attachement', function(done) { var uid = 415; - imapClientStub.getMessage.yieldsTo('onMessage', null, { + imapClientStub.getMessage.yieldsTo('onBody', null, { uid: uid, body: '' });