diff --git a/Gruntfile.js b/Gruntfile.js index dbc8002..30191b6 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -189,6 +189,7 @@ module.exports = function(grunt) { 'test/unit/controller/login/login-ctrl-test.js', 'test/unit/controller/app/dialog-ctrl-test.js', 'test/unit/controller/app/privatekey-upload-ctrl-test.js', + 'test/unit/controller/app/publickey-import-ctrl-test.js', 'test/unit/controller/app/account-ctrl-test.js', 'test/unit/controller/app/set-passphrase-ctrl-test.js', 'test/unit/controller/app/contacts-ctrl-test.js', diff --git a/src/js/app-config.js b/src/js/app-config.js index 6e2420f..8e8ec38 100644 --- a/src/js/app-config.js +++ b/src/js/app-config.js @@ -13,6 +13,7 @@ module.exports = appCfg; */ appCfg.config = { cloudUrl: 'https://keys.whiteout.io', + hkpUrl: 'https://pgp.mit.edu', privkeyServerUrl: 'https://keychain.whiteout.io', adminUrl: 'https://admin-node.whiteout.io', settingsUrl: 'https://settings.whiteout.io/autodiscovery/', diff --git a/src/js/app.js b/src/js/app.js index b53c852..2137932 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -111,6 +111,7 @@ app.controller('MailListCtrl', require('./controller/app/mail-list')); app.controller('AccountCtrl', require('./controller/app/account')); app.controller('SetPassphraseCtrl', require('./controller/app/set-passphrase')); app.controller('PrivateKeyUploadCtrl', require('./controller/app/privatekey-upload')); +app.controller('PublicKeyImportCtrl', require('./controller/app/publickey-import')); app.controller('ContactsCtrl', require('./controller/app/contacts')); app.controller('AboutCtrl', require('./controller/app/about')); app.controller('DialogCtrl', require('./controller/app/dialog')); diff --git a/src/js/controller/app/contacts.js b/src/js/controller/app/contacts.js index 716e272..169ff8d 100644 --- a/src/js/controller/app/contacts.js +++ b/src/js/controller/app/contacts.js @@ -4,7 +4,7 @@ // Controller // -var ContactsCtrl = function($scope, $q, keychain, pgp, dialog) { +var ContactsCtrl = function($scope, $q, keychain, pgp, dialog, appConfig) { // // scope state @@ -13,10 +13,13 @@ var ContactsCtrl = function($scope, $q, keychain, pgp, dialog) { $scope.state.contacts = { toggle: function(to) { $scope.state.lightbox = (to) ? 'contacts' : undefined; + $scope.searchText = undefined; return $scope.listKeys(); } }; + $scope.whiteoutKeyServer = appConfig.config.cloudUrl.replace(/http[s]?:\/\//, ''); // display key server hostname + // // scope functions // @@ -33,6 +36,7 @@ var ContactsCtrl = function($scope, $q, keychain, pgp, dialog) { keys.forEach(function(key) { var params = pgp.getKeyParams(key.publicKey); _.extend(key, params); + key.fullUserId = key.userIds[0].name + ' <' + key.userIds[0].emailAddress + '>'; }); $scope.keys = keys; @@ -46,39 +50,6 @@ var ContactsCtrl = function($scope, $q, keychain, pgp, dialog) { $scope.fingerprint = formatted; }; - $scope.importKey = function(publicKeyArmored) { - var keyParams, pubkey; - - // verifiy public key string - if (publicKeyArmored.indexOf('-----BEGIN PGP PUBLIC KEY BLOCK-----') < 0) { - dialog.error({ - showBugReporter: false, - message: 'Invalid public key!' - }); - return; - } - - try { - keyParams = pgp.getKeyParams(publicKeyArmored); - } catch (e) { - dialog.error(new Error('Error reading public key params!')); - return; - } - - pubkey = { - _id: keyParams._id, - userId: keyParams.userId, - userIds: keyParams.userIds, - publicKey: publicKeyArmored, - imported: true // mark manually imported keys - }; - - return keychain.saveLocalPublicKey(pubkey).then(function() { - // update displayed keys - return $scope.listKeys(); - }).catch(dialog.error); - }; - $scope.removeKey = function(key) { return keychain.removeLocalPublicKey(key._id).then(function() { // update displayed keys diff --git a/src/js/controller/app/dialog.js b/src/js/controller/app/dialog.js index 65ae0f4..6fdd11a 100644 --- a/src/js/controller/app/dialog.js +++ b/src/js/controller/app/dialog.js @@ -37,6 +37,7 @@ var DialogCtrl = function($scope, dialog) { $scope.title = options.title; $scope.message = options.errMsg || options.message; $scope.faqLink = options.faqLink; + $scope.faqLinkTitle = options.faqLinkTitle || 'Learn more'; $scope.positiveBtnStr = options.positiveBtnStr || 'Ok'; $scope.negativeBtnStr = options.negativeBtnStr || 'Cancel'; $scope.showNegativeBtn = options.showNegativeBtn || false; diff --git a/src/js/controller/app/publickey-import.js b/src/js/controller/app/publickey-import.js new file mode 100644 index 0000000..77a1488 --- /dev/null +++ b/src/js/controller/app/publickey-import.js @@ -0,0 +1,78 @@ +'use strict'; + +// +// Controller +// + +var PublickeyImportCtrl = function($scope, $q, keychain, pgp, hkp, dialog, appConfig) { + + // + // scope state + // + + $scope.state.publickeyImport = { + toggle: function(to) { + $scope.state.lightbox = (to) ? 'publickey-import' : undefined; + } + }; + + // + // scope variables + // + + $scope.hkpUrl = appConfig.config.hkpUrl.replace('https://', ''); + + // + // scope functions + // + + $scope.importKey = function(publicKeyArmored) { + var keyParams, pubkey; + + // verifiy public key string + if (publicKeyArmored.indexOf('-----BEGIN PGP PUBLIC KEY BLOCK-----') < 0) { + dialog.error({ + showBugReporter: false, + message: 'Invalid public key!' + }); + return; + } + + try { + keyParams = pgp.getKeyParams(publicKeyArmored); + } catch (e) { + dialog.error(new Error('Error reading public key params!')); + return; + } + + pubkey = { + _id: keyParams._id, + userId: keyParams.userId, + userIds: keyParams.userIds, + publicKey: publicKeyArmored, + imported: true // mark manually imported keys + }; + + return keychain.saveLocalPublicKey(pubkey).then(function() { + $scope.pastedKey = ''; + // display success message + return dialog.info({ + title: 'Success', + message: 'Public key ' + keyParams._id + ' for ' + keyParams.userId + ' imported successfully!' + }); + }).catch(dialog.error); + }; + + $scope.lookupKey = function(query) { + var keyUrl = hkp.getIndexUrl(query); + + return dialog.info({ + title: 'Link', + message: 'Follow this link and paste the PGP key block above...', + faqLink: keyUrl, + faqLinkTitle: keyUrl + }); + }; +}; + +module.exports = PublickeyImportCtrl; \ No newline at end of file diff --git a/src/js/controller/app/write.js b/src/js/controller/app/write.js index 636fb78..6b9dec1 100644 --- a/src/js/controller/app/write.js +++ b/src/js/controller/app/write.js @@ -206,6 +206,14 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain return; } + if (recipient.address) { + // display only email address after autocomplete + recipient.displayId = recipient.address; + } else { + // set address after manual input + recipient.address = recipient.displayId; + } + // set display to insecure while fetching keys recipient.key = undefined; recipient.secure = false; @@ -231,11 +239,12 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain }).then(function(key) { if (key) { // compare again since model could have changed during the roundtrip - var matchingUserId = _.findWhere(key.userIds, { + var userIds = pgp.getKeyParams(key.publicKey).userIds; + var matchingUserId = _.findWhere(userIds, { emailAddress: recipient.address }); // compare either primary userId or (if available) multiple IDs - if (key.userId === recipient.address || matchingUserId) { + if (matchingUserId) { recipient.key = key; recipient.secure = true; } @@ -264,7 +273,10 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain function check(recipient) { // validate address if (!util.validateEmailAddress(recipient.address)) { - return; + return dialog.info({ + title: 'Warning', + message: 'Invalid recipient address!' + }); } numReceivers++; if (!recipient.secure) { @@ -393,8 +405,10 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain // populate address book cache return keychain.listLocalPublicKeys().then(function(keys) { $scope.addressBookCache = keys.map(function(key) { + var name = pgp.getKeyParams(key.publicKey).userIds[0].name; return { - address: key.userId + address: key.userId, + displayId: name + ' - ' + key.userId }; }); }); @@ -402,7 +416,7 @@ var WriteCtrl = function($scope, $window, $filter, $q, appConfig, auth, keychain }).then(function() { // filter the address book cache return $scope.addressBookCache.filter(function(i) { - return i.address.indexOf(query) !== -1; + return i.displayId.toLowerCase().indexOf(query.toLowerCase()) !== -1; }); }).catch(dialog.error); diff --git a/src/js/service/hkp.js b/src/js/service/hkp.js new file mode 100644 index 0000000..aa3580b --- /dev/null +++ b/src/js/service/hkp.js @@ -0,0 +1,19 @@ +'use strict'; + +var ngModule = angular.module('woServices'); +ngModule.service('hkp', HKP); +module.exports = HKP; + +function HKP(appConfig) { + this._appConfig = appConfig; +} + +/** + * Return a url of the link to be opened in a new window + * @param {String} query Either the email address or name + * @return {String} The url of the hkp query + */ +HKP.prototype.getIndexUrl = function(query) { + var baseUrl = this._appConfig.config.hkpUrl + '/pks/lookup?op=index&search='; + return baseUrl + encodeURIComponent(query); +}; \ No newline at end of file diff --git a/src/js/service/index.js b/src/js/service/index.js index 62d1a59..18731d1 100644 --- a/src/js/service/index.js +++ b/src/js/service/index.js @@ -9,6 +9,7 @@ require('./newsletter'); require('./oauth'); require('./privatekey'); require('./publickey'); +require('./hkp'); require('./admin'); require('./lawnchair'); require('./devicestorage'); diff --git a/src/js/service/keychain.js b/src/js/service/keychain.js index a77c7a8..162a556 100644 --- a/src/js/service/keychain.js +++ b/src/js/service/keychain.js @@ -117,13 +117,13 @@ Keychain.prototype.refreshKeyForUserId = function(options) { // checks if the user's key has been revoked by looking up the key id function checkKeyExists(localKey) { - return self._publicKeyDao.get(localKey._id).then(function(cloudKey) { + return self._publicKeyDao.getByUserId(userId).then(function(cloudKey) { if (cloudKey && cloudKey._id === localKey._id) { // the key is present on the server, all is well return localKey; } // the key has changed, update the key - return updateKey(localKey); + return updateKey(localKey, cloudKey); }).catch(function(err) { if (err && err.code === 42) { @@ -134,24 +134,14 @@ Keychain.prototype.refreshKeyForUserId = function(options) { }); } - function updateKey(localKey) { - // look for an updated key for the user id - return self._publicKeyDao.getByUserId(userId).then(function(newKey) { - // the public key has changed, we need to ask for permission to update the key - if (overridePermission) { - // don't query the user, update the public key right away - return permissionGranted(localKey, newKey); - } else { - return requestPermission(localKey, newKey); - } - - }).catch(function(err) { - // offline? - if (err && err.code === 42) { - return localKey; - } - throw err; - }); + function updateKey(localKey, newKey) { + // the public key has changed, we need to ask for permission to update the key + if (overridePermission) { + // don't query the user, update the public key right away + return permissionGranted(localKey, newKey); + } else { + return requestPermission(localKey, newKey); + } } function requestPermission(localKey, newKey) { @@ -196,6 +186,7 @@ Keychain.prototype.getReceiverPublicKey = function(userId) { // search local keyring for public key return self._lawnchairDAO.list(DB_PUBLICKEY, 0, null).then(function(allPubkeys) { + var userIds; // query primary email address var pubkey = _.findWhere(allPubkeys, { userId: userId @@ -203,7 +194,8 @@ Keychain.prototype.getReceiverPublicKey = function(userId) { // query mutliple userIds (for imported public keys) if (!pubkey) { for (var i = 0, match; i < allPubkeys.length; i++) { - match = _.findWhere(allPubkeys[i].userIds, { + userIds = self._pgp.getKeyParams(allPubkeys[i].publicKey).userIds; + match = _.findWhere(userIds, { emailAddress: userId }); if (match) { diff --git a/src/js/service/rest.js b/src/js/service/rest.js index f2cfce5..e16f88f 100644 --- a/src/js/service/rest.js +++ b/src/js/service/rest.js @@ -62,11 +62,12 @@ RestDAO.prototype.get = function(options) { /** * POST (create) request */ -RestDAO.prototype.post = function(item, uri) { +RestDAO.prototype.post = function(item, uri, type) { return this._processRequest({ method: 'POST', payload: item, - uri: uri + uri: uri, + type: type }); }; @@ -98,27 +99,32 @@ RestDAO.prototype.remove = function(uri) { RestDAO.prototype._processRequest = function(options) { var self = this; return new Promise(function(resolve, reject) { - var xhr, format; + var xhr, format, accept, payload; if (typeof options.uri === 'undefined') { throw createError(400, 'Bad Request! URI is a mandatory parameter.'); } options.type = options.type || 'json'; + payload = options.payload; if (options.type === 'json') { format = 'application/json'; + payload = payload ? JSON.stringify(payload) : undefined; } else if (options.type === 'xml') { format = 'application/xml'; } else if (options.type === 'text') { format = 'text/plain'; + } else if (options.type === 'form') { + format = 'application/x-www-form-urlencoded; charset=UTF-8'; + accept = 'text/html; charset=UTF-8'; } else { throw createError(400, 'Bad Request! Unhandled data type.'); } xhr = new XMLHttpRequest(); xhr.open(options.method, self._baseUri + options.uri); - xhr.setRequestHeader('Accept', format); + xhr.setRequestHeader('Accept', accept || format); xhr.setRequestHeader('Content-Type', format); xhr.onload = function() { @@ -146,7 +152,7 @@ RestDAO.prototype._processRequest = function(options) { reject(createError(42, 'Error calling ' + options.method + ' on ' + options.uri)); }; - xhr.send(options.payload ? JSON.stringify(options.payload) : undefined); + xhr.send(payload); }); }; diff --git a/src/sass/blocks/basics/_form.scss b/src/sass/blocks/basics/_form.scss index f58c82d..5b1c1de 100644 --- a/src/sass/blocks/basics/_form.scss +++ b/src/sass/blocks/basics/_form.scss @@ -123,6 +123,14 @@ } } +.textarea { + width: 100%; + height: 100px; + border: 1px solid $color-border-light; + resize: none; + outline: none; +} + // Attention: Webkit support only! .input-select { position: relative; diff --git a/src/tpl/contacts.html b/src/tpl/contacts.html index 0932eb4..1be8f72 100644 --- a/src/tpl/contacts.html +++ b/src/tpl/contacts.html @@ -6,10 +6,9 @@ @@ -27,8 +26,7 @@ focus-input-on-click> @@ -37,8 +35,7 @@ focus-input-on-click> diff --git a/test/unit/controller/app/contacts-ctrl-test.js b/test/unit/controller/app/contacts-ctrl-test.js index 6ac94b5..03d4027 100644 --- a/test/unit/controller/app/contacts-ctrl-test.js +++ b/test/unit/controller/app/contacts-ctrl-test.js @@ -51,7 +51,11 @@ describe('Contacts Controller unit test', function() { _id: '12345' }])); pgpStub.getKeyParams.returns({ - fingerprint: 'asdf' + fingerprint: 'asdf', + userIds: [{ + name: 'Firstname Lastname', + emailAddress: 'first.last@example.com' + }] }); expect(scope.keys).to.not.exist; @@ -59,6 +63,7 @@ describe('Contacts Controller unit test', function() { expect(scope.keys.length).to.equal(1); expect(scope.keys[0]._id).to.equal('12345'); expect(scope.keys[0].fingerprint).to.equal('asdf'); + expect(scope.keys[0].fullUserId).to.equal('Firstname Lastname '); done(); }); }); @@ -76,65 +81,6 @@ describe('Contacts Controller unit test', function() { }); }); - describe('importKey', function() { - it('should work', function(done) { - var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; - - pgpStub.getKeyParams.returns({ - _id: '12345', - userId: 'max@example.com', - userIds: [] - }); - - keychainStub.saveLocalPublicKey.withArgs({ - _id: '12345', - userId: 'max@example.com', - userIds: [], - publicKey: '-----BEGIN PGP PUBLIC KEY BLOCK-----', - imported: true - }).returns(resolves()); - - scope.listKeys = function() {}; - - scope.importKey(keyArmored).then(function() { - done(); - }); - }); - - it('should fail due to invalid armored key', function() { - var keyArmored = '-----BEGIN PGP PRIVATE KEY BLOCK-----'; - - scope.importKey(keyArmored); - - expect(dialogStub.error.calledOnce).to.be.true; - }); - - it('should fail due to error in pgp.getKeyParams', function() { - var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; - pgpStub.getKeyParams.throws(new Error('WAT')); - - scope.importKey(keyArmored); - - expect(dialogStub.error.calledOnce).to.be.true; - }); - - it('should fail due to error in keychain.saveLocalPublicKey', function(done) { - var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; - - pgpStub.getKeyParams.returns({ - _id: '12345', - userId: 'max@example.com' - }); - - keychainStub.saveLocalPublicKey.returns(rejects(42)); - - scope.importKey(keyArmored).then(function() { - expect(dialogStub.error.calledOnce).to.be.true; - done(); - }); - }); - }); - describe('removeKey', function() { it('should work', function(done) { var key = { diff --git a/test/unit/controller/app/publickey-import-ctrl-test.js b/test/unit/controller/app/publickey-import-ctrl-test.js new file mode 100644 index 0000000..38847c0 --- /dev/null +++ b/test/unit/controller/app/publickey-import-ctrl-test.js @@ -0,0 +1,91 @@ +'use strict'; + +var PublicKeyImportCtrl = require('../../../../src/js/controller/app/publickey-import'), + Keychain = require('../../../../src/js/service/keychain'), + PGP = require('../../../../src/js/crypto/pgp'), + Dialog = require('../../../../src/js/util/dialog'); + +describe('Public Key Import Controller unit test', function() { + var scope, ctrl, keychainStub, pgpStub, dialogStub; + + beforeEach(function() { + pgpStub = sinon.createStubInstance(PGP); + keychainStub = sinon.createStubInstance(Keychain); + dialogStub = sinon.createStubInstance(Dialog); + + angular.module('publickey-import', ['woServices']); + angular.mock.module('publickey-import'); + angular.mock.inject(function($rootScope, $controller) { + scope = $rootScope.$new(); + scope.state = {}; + ctrl = $controller(PublicKeyImportCtrl, { + $scope: scope, + $q: window.qMock, + keychain: keychainStub, + pgp: pgpStub, + dialog: dialogStub + }); + }); + }); + + afterEach(function() {}); + + describe('importKey', function() { + it('should work', function(done) { + var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; + + pgpStub.getKeyParams.returns({ + _id: '12345', + userId: 'max@example.com', + userIds: [] + }); + + keychainStub.saveLocalPublicKey.withArgs({ + _id: '12345', + userId: 'max@example.com', + userIds: [], + publicKey: '-----BEGIN PGP PUBLIC KEY BLOCK-----', + imported: true + }).returns(resolves()); + + scope.listKeys = function() {}; + + scope.importKey(keyArmored).then(function() { + done(); + }); + }); + + it('should fail due to invalid armored key', function() { + var keyArmored = '-----BEGIN PGP PRIVATE KEY BLOCK-----'; + + scope.importKey(keyArmored); + + expect(dialogStub.error.calledOnce).to.be.true; + }); + + it('should fail due to error in pgp.getKeyParams', function() { + var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; + pgpStub.getKeyParams.throws(new Error('WAT')); + + scope.importKey(keyArmored); + + expect(dialogStub.error.calledOnce).to.be.true; + }); + + it('should fail due to error in keychain.saveLocalPublicKey', function(done) { + var keyArmored = '-----BEGIN PGP PUBLIC KEY BLOCK-----'; + + pgpStub.getKeyParams.returns({ + _id: '12345', + userId: 'max@example.com' + }); + + keychainStub.saveLocalPublicKey.returns(rejects(42)); + + scope.importKey(keyArmored).then(function() { + expect(dialogStub.error.calledOnce).to.be.true; + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/test/unit/controller/app/write-ctrl-test.js b/test/unit/controller/app/write-ctrl-test.js index 5c27987..23eb6bd 100644 --- a/test/unit/controller/app/write-ctrl-test.js +++ b/test/unit/controller/app/write-ctrl-test.js @@ -215,6 +215,11 @@ describe('Write controller unit test', function() { }).returns(resolves({ userId: 'asdf@example.com' })); + pgpMock.getKeyParams.returns({ + userIds: [{ + emailAddress: recipient.address + }] + }); scope.verify(recipient).then(function() { expect(recipient.key).to.deep.equal({ @@ -232,15 +237,17 @@ describe('Write controller unit test', function() { address: 'asdf@example.com' }; var key = { - userId: 'qwer@example.com', - userIds: [{ - emailAddress: 'asdf@example.com' - }] + userId: 'qwertz@example.com' }; keychainMock.refreshKeyForUserId.withArgs({ userId: recipient.address }).returns(resolves(key)); + pgpMock.getKeyParams.returns({ + userIds: [{ + emailAddress: recipient.address + }] + }); scope.verify(recipient).then(function() { expect(recipient.key).to.deep.equal(key); @@ -359,12 +366,18 @@ describe('Write controller unit test', function() { userId: 'test@asdf.com', publicKey: 'KEY' }])); + pgpMock.getKeyParams.returns({ + userIds: [{ + name: 'Bob' + }] + }); var result = scope.lookupAddressBook('test'); result.then(function(response) { expect(response).to.deep.equal([{ - address: 'test@asdf.com' + address: 'test@asdf.com', + displayId: 'Bob - test@asdf.com' }]); done(); }); @@ -372,17 +385,17 @@ describe('Write controller unit test', function() { it('should work with cache', function(done) { scope.addressBookCache = [{ - address: 'test@asdf.com' + address: 'test@asdf.com', + displayId: 'Bob - test@asdf.com' }, { - address: 'tes@asdf.com' + address: 'tes@asdf.com', + displayId: 'Bob - tes@asdf.com' }]; var result = scope.lookupAddressBook('test'); result.then(function(response) { - expect(response).to.deep.equal([{ - address: 'test@asdf.com' - }]); + expect(response).to.deep.equal([scope.addressBookCache[0]]); done(); }); }); diff --git a/test/unit/service/keychain-dao-test.js b/test/unit/service/keychain-dao-test.js index a43899b..ee4bb1d 100644 --- a/test/unit/service/keychain-dao-test.js +++ b/test/unit/service/keychain-dao-test.js @@ -112,7 +112,7 @@ describe('Keychain DAO unit tests', function() { it('should not update the key when up to date', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(resolves(oldKey)); + pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves(oldKey)); keychainDao.refreshKeyForUserId({ userId: testUser @@ -120,7 +120,7 @@ describe('Keychain DAO unit tests', function() { expect(key).to.to.equal(oldKey); expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; done(); }); @@ -128,7 +128,6 @@ describe('Keychain DAO unit tests', function() { it('should update key', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(resolves()); pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves(newKey)); keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { expect(opts.userId).to.equal(testUser); @@ -144,7 +143,6 @@ describe('Keychain DAO unit tests', function() { expect(key).to.equal(newKey); expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; expect(lawnchairDaoStub.remove.calledOnce).to.be.true; expect(lawnchairDaoStub.persist.calledOnce).to.be.true; @@ -155,7 +153,6 @@ describe('Keychain DAO unit tests', function() { it('should update key without approval', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(resolves()); pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves(newKey)); lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).returns(resolves()); lawnchairDaoStub.persist.withArgs('publickey_' + newKey._id, newKey).returns(resolves()); @@ -167,7 +164,6 @@ describe('Keychain DAO unit tests', function() { expect(key).to.equal(newKey); expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; expect(lawnchairDaoStub.remove.calledOnce).to.be.true; expect(lawnchairDaoStub.persist.calledOnce).to.be.true; @@ -178,7 +174,7 @@ describe('Keychain DAO unit tests', function() { it('should remove key', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(resolves()); + pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves()); pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves()); keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { expect(opts.userId).to.equal(testUser); @@ -193,7 +189,6 @@ describe('Keychain DAO unit tests', function() { expect(key).to.not.exist; expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; expect(lawnchairDaoStub.remove.calledOnce).to.be.true; expect(lawnchairDaoStub.persist.called).to.be.false; @@ -204,7 +199,7 @@ describe('Keychain DAO unit tests', function() { it('should go offline while fetching new key', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(resolves()); + pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves()); pubkeyDaoStub.getByUserId.withArgs(testUser).returns(rejects({ code: 42 })); @@ -215,7 +210,6 @@ describe('Keychain DAO unit tests', function() { expect(key).to.to.equal(oldKey); expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; expect(lawnchairDaoStub.remove.called).to.be.false; expect(lawnchairDaoStub.persist.called).to.be.false; @@ -226,7 +220,7 @@ describe('Keychain DAO unit tests', function() { it('should not remove old key on user rejection', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(resolves()); + pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves()); pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves(newKey)); keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { expect(opts.userId).to.equal(testUser); @@ -240,7 +234,6 @@ describe('Keychain DAO unit tests', function() { expect(key).to.equal(oldKey); expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; expect(lawnchairDaoStub.remove.called).to.be.false; expect(lawnchairDaoStub.persist.called).to.be.false; @@ -266,7 +259,7 @@ describe('Keychain DAO unit tests', function() { it('should update not the key when offline', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(rejects({ + pubkeyDaoStub.getByUserId.withArgs(testUser).returns(rejects({ code: 42 })); @@ -276,8 +269,7 @@ describe('Keychain DAO unit tests', function() { expect(key).to.to.equal(oldKey); expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; - expect(pubkeyDaoStub.getByUserId.called).to.be.false; + expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; expect(lawnchairDaoStub.remove.called).to.be.false; expect(lawnchairDaoStub.persist.called).to.be.false; @@ -287,7 +279,7 @@ describe('Keychain DAO unit tests', function() { it('should error while persisting new key', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(resolves()); + pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves()); pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves(newKey)); keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { expect(opts.userId).to.equal(testUser); @@ -303,7 +295,6 @@ describe('Keychain DAO unit tests', function() { expect(err).to.exist; expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; expect(lawnchairDaoStub.remove.calledOnce).to.be.true; expect(lawnchairDaoStub.persist.calledOnce).to.be.true; @@ -314,7 +305,7 @@ describe('Keychain DAO unit tests', function() { it('should error while deleting old key', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(resolves()); + pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves()); pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves()); keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { expect(opts.userId).to.equal(testUser); @@ -328,7 +319,6 @@ describe('Keychain DAO unit tests', function() { expect(err).to.exist; expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; expect(lawnchairDaoStub.remove.calledOnce).to.be.true; expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; expect(lawnchairDaoStub.persist.called).to.be.false; @@ -339,7 +329,7 @@ describe('Keychain DAO unit tests', function() { it('should error while persisting new key', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(resolves()); + pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves()); pubkeyDaoStub.getByUserId.withArgs(testUser).returns(resolves(newKey)); keychainDao.requestPermissionForKeyUpdate = function(opts, cb) { expect(opts.userId).to.equal(testUser); @@ -355,7 +345,6 @@ describe('Keychain DAO unit tests', function() { expect(err).to.exist; expect(getPubKeyStub.calledOnce).to.be.true; - expect(pubkeyDaoStub.get.calledOnce).to.be.true; expect(pubkeyDaoStub.getByUserId.calledOnce).to.be.true; expect(lawnchairDaoStub.remove.calledOnce).to.be.true; expect(lawnchairDaoStub.persist.calledOnce).to.be.true; @@ -366,7 +355,7 @@ describe('Keychain DAO unit tests', function() { it('should error when get failed', function(done) { getPubKeyStub.returns(resolves(oldKey)); - pubkeyDaoStub.get.withArgs(oldKey._id).returns(rejects({})); + pubkeyDaoStub.getByUserId.withArgs(testUser).returns(rejects({})); keychainDao.refreshKeyForUserId({ userId: testUser @@ -497,11 +486,13 @@ describe('Keychain DAO unit tests', function() { lawnchairDaoStub.list.returns(resolves([{ _id: '12345', userId: 'not testUser', - userIds: [{ - emailAddress: testUser - }], publicKey: 'asdf' }])); + pgpStub.getKeyParams.returns({ + userIds: [{ + emailAddress: testUser + }] + }); keychainDao.getReceiverPublicKey(testUser).then(function(key) { expect(key).to.exist;