diff --git a/package.json b/package.json index c22c0eb..12ef2c7 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "grunt-svgstore": "~0.3.4", "handlebars-helper-compose": "~0.2.12", "iframe-resizer": "^2.8.3", - "imap-client": "~0.14.1", + "imap-client": "https://github.com/whiteout-io/imap-client/tarball/dev/WO-978", "jquery": "~2.1.1", "mailbuild": "^0.3.7", "mailreader": "~0.4.0", diff --git a/src/js/service/privatekey.js b/src/js/service/privatekey.js index 3470aaa..0bb1cdd 100644 --- a/src/js/service/privatekey.js +++ b/src/js/service/privatekey.js @@ -97,7 +97,8 @@ PrivateKey.prototype.encrypt = function(code) { * @param {String} options.encryptedPrivateKey The base64 encoded encrypted private PGP key */ PrivateKey.prototype.upload = function(options) { - var self = this; + var self = this, + path; return new Promise(function(resolve) { if (!options._id || !options.userId || !options.encryptedPrivateKey || !options.salt || !options.iv) { @@ -109,8 +110,9 @@ PrivateKey.prototype.upload = function(options) { // create imap folder return self._imap.createFolder({ path: IMAP_KEYS_FOLDER - }).then(function() { - self._axe.debug('Successfully created imap folder ' + 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); @@ -119,7 +121,7 @@ PrivateKey.prototype.upload = function(options) { }).then(createMessage).then(function(message) { // upload to imap folder return self._imap.uploadMessage({ - path: IMAP_KEYS_FOLDER, + path: path, message: message }); }); @@ -290,8 +292,38 @@ PrivateKey.prototype._fetchMessage = function(options) { } // get the metadata for the message - return self._imap.listMessages({ - path: IMAP_KEYS_FOLDER, + + return self._imap.listWellKnownFolders().then(function(wellKnownFolders) { + var paths = []; // gathers paths + + // extract the paths from the folder arrays + for (var folderType in wellKnownFolders) { + if (wellKnownFolders.hasOwnProperty(folderType) && Array.isArray(wellKnownFolders[folderType])) { + paths = paths.concat(_.pluck(wellKnownFolders[folderType], 'path')); + } + } + + paths = paths.filter(function(path) { + // find a folder that ends with IMAP_KEYS_FOLDER + var lastIndex = path.lastIndexOf(IMAP_KEYS_FOLDER); + return (lastIndex !== -1) && (lastIndex + IMAP_KEYS_FOLDER.length === path.length); + }); + + if (paths.length > 1) { + self._axe.warn('Multiple folders matching path ' + IMAP_KEYS_FOLDER + ' found, PGP key target folder unclear. Picking first one: ' + paths.join(', ')); + } + + if (paths.length === 0) { + throw new Error('Imap folder ' + IMAP_KEYS_FOLDER + ' does not exist for key sync!'); + } + + return paths[0]; + + }).then(function(path) { + return self._imap.listMessages({ + path: path, + }); + }).then(function(messages) { if (!messages.length) { // message has been deleted in the meantime @@ -302,8 +334,8 @@ PrivateKey.prototype._fetchMessage = function(options) { return _.findWhere(messages, { subject: options.keyId }); - }).catch(function() { - throw new Error('Imap folder ' + IMAP_KEYS_FOLDER + ' does not exist for key sync!'); + }).catch(function(e) { + throw new Error('Failed to retrieve PGP key message from IMAP! Reason: ' + e.message); }); }; diff --git a/test/unit/service/privatekey-dao-test.js b/test/unit/service/privatekey-dao-test.js index 3ddaff6..95dbef3 100644 --- a/test/unit/service/privatekey-dao-test.js +++ b/test/unit/service/privatekey-dao-test.js @@ -76,8 +76,17 @@ describe('Private Key DAO unit tests', function() { }); it('should work', function(done) { - imapClientStub.createFolder.returns(resolves()); - imapClientStub.uploadMessage.returns(resolves()); + var IMAP_KEYS_FOLDER = 'openpgp_keys'; + var fullPath = 'INBOX.' + IMAP_KEYS_FOLDER; + + imapClientStub.createFolder.withArgs({ + path: IMAP_KEYS_FOLDER + }).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, @@ -86,6 +95,7 @@ describe('Private Key DAO unit tests', function() { salt: salt, iv: iv }).then(function() { + expect(imapClientStub.createFolder.calledOnce).to.be.true; expect(imapClientStub.uploadMessage.calledOnce).to.be.true; done(); }); @@ -252,6 +262,14 @@ describe('Private Key DAO unit tests', function() { }); it('should fail if imap folder does not exist', function(done) { + imapClientStub.listWellKnownFolders.returns(resolves({ + Inbox: [{ + path: 'INBOX' + }], + Other: [{ + path: 'foo' + }] + })); imapClientStub.listMessages.returns(rejects(new Error())); privkeyDao._fetchMessage({ @@ -264,6 +282,14 @@ describe('Private Key DAO unit tests', function() { }); it('should work', function(done) { + imapClientStub.listWellKnownFolders.returns(resolves({ + Inbox: [{ + path: 'INBOX' + }], + Other: [{ + path: 'openpgp_keys' + }] + })); imapClientStub.listMessages.returns(resolves([{ subject: keyId }])); @@ -273,11 +299,42 @@ describe('Private Key DAO unit tests', function() { keyId: keyId }).then(function(msg) { expect(msg.subject).to.equal(keyId); + expect(imapClientStub.listWellKnownFolders.calledOnce).to.be.true; + expect(imapClientStub.listMessages.calledOnce).to.be.true; + done(); + }); + }); + + it('should work with path prefix', function(done) { + imapClientStub.listWellKnownFolders.returns(resolves({ + Inbox: [{ + path: 'INBOX' + }], + Other: [{ + path: 'INBOX.openpgp_keys' + }] + })); + imapClientStub.listMessages.returns(resolves([{ + subject: keyId + }])); + + privkeyDao._fetchMessage({ + userId: emailAddress, + keyId: keyId + }).then(function(msg) { + expect(msg.subject).to.equal(keyId); + expect(imapClientStub.listWellKnownFolders.calledOnce).to.be.true; + expect(imapClientStub.listMessages.calledOnce).to.be.true; done(); }); }); it('should work for not matching message', function(done) { + imapClientStub.listWellKnownFolders.returns(resolves({ + Other: [{ + path: 'INBOX.openpgp_keys' + }] + })); imapClientStub.listMessages.returns(resolves([{ subject: '7890' }])); @@ -292,6 +349,11 @@ describe('Private Key DAO unit tests', function() { }); it('should work for no messages', function(done) { + imapClientStub.listWellKnownFolders.returns(resolves({ + Other: [{ + path: 'INBOX.openpgp_keys' + }] + })); imapClientStub.listMessages.returns(resolves([])); privkeyDao._fetchMessage({