From ad3691fae92cb644086f9e5766605223d2f2f70f Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Mon, 27 Jul 2015 17:45:23 +0200 Subject: [PATCH] [WO-1026] Fix broken key upload after mail server error --- src/js/service/privatekey.js | 37 +++++++++++++++++------- test/unit/service/privatekey-dao-test.js | 37 +++++++++++++++++++++++- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/js/service/privatekey.js b/src/js/service/privatekey.js index 8f2f8bc..13abc2d 100644 --- a/src/js/service/privatekey.js +++ b/src/js/service/privatekey.js @@ -102,24 +102,39 @@ PrivateKey.prototype.upload = function(options) { return new Promise(function(resolve) { if (!options._id || !options.userId || !options.encryptedPrivateKey || !options.salt || !options.iv) { - throw new Error('Incomplete arguments!'); + throw new Error('Incomplete arguments for key upload!'); } resolve(); }).then(function() { - // create imap folder - return self._imap.createFolder({ - path: IMAP_KEYS_FOLDER - }).then(function(fullPath) { + + // Some servers (Exchange, Cyrus) error when creating an existing IMAP mailbox instead of + // responding with ALREADYEXISTS. Hence we search for the folder before uploading. + + self._axe.debug('Searching imap folder for key upload...'); + + return self._getFolder().then(function(fullPath) { path = fullPath; - self._axe.debug('Successfully created imap folder ' + path); - }).catch(function(err) { - var prettyErr = new Error('Creating imap folder ' + IMAP_KEYS_FOLDER + ' failed: ' + err.message); - self._axe.error(prettyErr); - throw prettyErr; + }).catch(function() { + + // create imap folder + self._axe.debug('Folder not found, creating imap folder.'); + return self._imap.createFolder({ + path: IMAP_KEYS_FOLDER + }).then(function(fullPath) { + path = fullPath; + self._axe.debug('Successfully created imap folder ' + path); + }).catch(function(err) { + var prettyErr = new Error('Creating imap folder ' + IMAP_KEYS_FOLDER + ' failed: ' + err.message); + self._axe.error(prettyErr); + throw prettyErr; + }); }); + }).then(createMessage).then(function(message) { + // upload to imap folder + self._axe.debug('Uploading key...'); return self._imap.uploadMessage({ path: path, message: message @@ -380,4 +395,4 @@ function filterBodyParts(bodyParts, type, result) { } }); return result; -} +} \ No newline at end of file diff --git a/test/unit/service/privatekey-dao-test.js b/test/unit/service/privatekey-dao-test.js index 1fa5641..1f943d3 100644 --- a/test/unit/service/privatekey-dao-test.js +++ b/test/unit/service/privatekey-dao-test.js @@ -68,6 +68,14 @@ describe('Private Key DAO unit tests', function() { }); describe('upload', function() { + beforeEach(function() { + sinon.stub(privkeyDao, '_getFolder'); + }); + + afterEach(function() { + privkeyDao._getFolder.restore(); + }); + it('should fail due to invalid args', function(done) { privkeyDao.upload({}).catch(function(err) { expect(err.message).to.match(/Incomplete/); @@ -75,10 +83,11 @@ describe('Private Key DAO unit tests', function() { }); }); - it('should work', function(done) { + it('should work without existing folder', function(done) { var IMAP_KEYS_FOLDER = 'openpgp_keys'; var fullPath = 'INBOX.' + IMAP_KEYS_FOLDER; + privkeyDao._getFolder.returns(rejects(new Error())); imapClientStub.createFolder.withArgs({ path: IMAP_KEYS_FOLDER }).returns(resolves(fullPath)); @@ -95,11 +104,37 @@ describe('Private Key DAO unit tests', function() { salt: salt, iv: iv }).then(function() { + expect(privkeyDao._getFolder.calledOnce).to.be.true; expect(imapClientStub.createFolder.calledOnce).to.be.true; expect(imapClientStub.uploadMessage.calledOnce).to.be.true; done(); }); }); + + it('should work with existing folder', function(done) { + var IMAP_KEYS_FOLDER = 'openpgp_keys'; + var fullPath = 'INBOX.' + IMAP_KEYS_FOLDER; + + privkeyDao._getFolder.returns(resolves(fullPath)); + imapClientStub.uploadMessage.withArgs(sinon.match(function(arg) { + expect(arg.path).to.equal(fullPath); + expect(arg.message).to.exist; + return true; + })).returns(resolves()); + + privkeyDao.upload({ + _id: keyId, + userId: emailAddress, + encryptedPrivateKey: encryptedPrivateKey, + salt: salt, + iv: iv + }).then(function() { + expect(privkeyDao._getFolder.calledOnce).to.be.true; + expect(imapClientStub.createFolder.called).to.be.false; + expect(imapClientStub.uploadMessage.calledOnce).to.be.true; + done(); + }); + }); }); describe('isSynced', function() {