mirror of
https://github.com/moparisthebest/mail
synced 2024-12-23 07:48:48 -05:00
Merge pull request #66 from whiteout-io/dev/WO-398
[WO-398] update revoked public keys
This commit is contained in:
commit
f33febaa88
@ -60,13 +60,16 @@ define(function(require) {
|
||||
invitationSubject: 'Invitation to a private conversation',
|
||||
invitationMessage: 'Hi,\n\nI use Whiteout Mail to send and receive encrypted email. I would like to exchange encrypted messages with you as well.\n\nPlease install the Whiteout Mail application. This application makes it easy to read and write messages securely with PGP encryption applied.\n\nGo to the Whiteout Networks homepage to learn more and to download the application: https://whiteout.io\n\n',
|
||||
message: 'Hi,\n\nthis is a private conversation. To read my encrypted message below, simply open it in Whiteout Mail.\nOpen Whiteout Mail: https://chrome.google.com/webstore/detail/jjgghafhamholjigjoghcfcekhkonijg',
|
||||
cryptPrefix: '-----BEGIN PGP MESSAGE-----',
|
||||
cryptSuffix: '-----END PGP MESSAGE-----',
|
||||
signature: '\n\n\n--\nSent from Whiteout Mail - Email encryption for the rest of us\nhttps://whiteout.io\n\n',
|
||||
webSite: 'http://whiteout.io',
|
||||
verificationSubject: '[whiteout] New public key uploaded',
|
||||
sendBtnClear: 'Send',
|
||||
sendBtnSecure: 'Send securely'
|
||||
sendBtnSecure: 'Send securely',
|
||||
updatePublicKeyTitle: 'Public Key Updated',
|
||||
updatePublicKeyMsgNewKey: '{0} updated his key and may not be able to read encrypted messages sent with his old key. Update the key?',
|
||||
updatePublicKeyMsgRemovedKey: '{0} revoked his key and may no longer be able to read encrypted messages. Remove the key?',
|
||||
updatePublicKeyPosBtn: 'Yes',
|
||||
updatePublicKeyNegBtn: 'No'
|
||||
};
|
||||
|
||||
return app;
|
||||
|
@ -14,7 +14,9 @@ define(function(require) {
|
||||
ImapClient = require('imap-client'),
|
||||
RestDAO = require('js/dao/rest-dao'),
|
||||
EmailDAO = require('js/dao/email-dao'),
|
||||
config = require('js/app-config').config,
|
||||
appConfig = require('js/app-config'),
|
||||
config = appConfig.config,
|
||||
str = appConfig.string,
|
||||
KeychainDAO = require('js/dao/keychain-dao'),
|
||||
PublicKeyDAO = require('js/dao/publickey-dao'),
|
||||
LawnchairDAO = require('js/dao/lawnchair-dao'),
|
||||
@ -64,11 +66,25 @@ define(function(require) {
|
||||
pubkeyDao = new PublicKeyDAO(restDao);
|
||||
oauth = new OAuth(new RestDAO('https://www.googleapis.com'));
|
||||
|
||||
self._keychain = keychain = new KeychainDAO(lawnchairDao, pubkeyDao);
|
||||
keychain.requestPermissionForKeyUpdate = function(params, callback) {
|
||||
var message = params.newKey ? str.updatePublicKeyMsgNewKey : str.updatePublicKeyMsgRemovedKey;
|
||||
message = message.replace('{0}', params.userId);
|
||||
|
||||
options.onError({
|
||||
title: str.updatePublicKeyTitle,
|
||||
message: message,
|
||||
positiveBtnStr: str.updatePublicKeyPosBtn,
|
||||
negativeBtnStr: str.updatePublicKeyNegBtn,
|
||||
showNegativeBtn: true,
|
||||
callback: callback
|
||||
});
|
||||
};
|
||||
|
||||
self._appConfigStore = appConfigStore = new DeviceStorageDAO(new LawnchairDAO());
|
||||
self._auth = new Auth(appConfigStore, oauth, new RestDAO('/ca'));
|
||||
self._userStorage = userStorage = new DeviceStorageDAO(lawnchairDao);
|
||||
self._invitationDao = new InvitationDAO(restDao);
|
||||
self._keychain = keychain = new KeychainDAO(lawnchairDao, pubkeyDao);
|
||||
self._crypto = pgp = new PGP();
|
||||
self._pgpbuilder = pgpbuilder = new PgpBuilder();
|
||||
self._emailDao = emailDao = new EmailDAO(keychain, pgp, userStorage, pgpbuilder, mailreader);
|
||||
|
@ -6,7 +6,7 @@ define(function(require) {
|
||||
appController = require('js/app-controller'),
|
||||
IScroll = require('iscroll'),
|
||||
notification = require('js/util/notification'),
|
||||
emailDao, outboxBo;
|
||||
emailDao, outboxBo, keychainDao;
|
||||
|
||||
var MailListCtrl = function($scope, $timeout) {
|
||||
//
|
||||
@ -15,6 +15,7 @@ define(function(require) {
|
||||
|
||||
emailDao = appController._emailDao;
|
||||
outboxBo = appController._outboxBo;
|
||||
keychainDao = appController._keychain;
|
||||
|
||||
//
|
||||
// scope functions
|
||||
@ -55,17 +56,25 @@ define(function(require) {
|
||||
$scope.state.mailList.selected = email;
|
||||
$scope.state.read.toggle(true);
|
||||
|
||||
emailDao.decryptBody({
|
||||
message: email
|
||||
}, $scope.onError);
|
||||
keychainDao.refreshKeyForUserId(email.from[0].address, onKeyRefreshed);
|
||||
|
||||
// if the email is unread, please sync the new state.
|
||||
// otherweise forget about it.
|
||||
if (!email.unread) {
|
||||
return;
|
||||
function onKeyRefreshed(err) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
}
|
||||
|
||||
emailDao.decryptBody({
|
||||
message: email
|
||||
}, $scope.onError);
|
||||
|
||||
// if the email is unread, please sync the new state.
|
||||
// otherweise forget about it.
|
||||
if (!email.unread) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.toggleUnread(email);
|
||||
}
|
||||
|
||||
$scope.toggleUnread(email);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -7,7 +7,7 @@ define(function(require) {
|
||||
aes = require('cryptoLib/aes-cbc'),
|
||||
util = require('cryptoLib/util'),
|
||||
str = require('js/app-config').string,
|
||||
crypto, emailDao, outbox;
|
||||
crypto, emailDao, outbox, keychainDao;
|
||||
|
||||
//
|
||||
// Controller
|
||||
@ -17,6 +17,8 @@ define(function(require) {
|
||||
crypto = appController._crypto;
|
||||
emailDao = appController._emailDao,
|
||||
outbox = appController._outboxBo;
|
||||
keychainDao = appController._keychain;
|
||||
|
||||
|
||||
// set default value so that the popover height is correct on init
|
||||
$scope.keyId = 'XXXXXXXX';
|
||||
@ -185,7 +187,8 @@ define(function(require) {
|
||||
}
|
||||
|
||||
// check if to address is contained in known public keys
|
||||
emailDao._keychain.getReceiverPublicKey(recipient.address, function(err, key) {
|
||||
// when we write an email, we always need to work with the latest keys available
|
||||
keychainDao.refreshKeyForUserId(recipient.address, function(err, key) {
|
||||
if (err) {
|
||||
$scope.onError(err);
|
||||
return;
|
||||
|
@ -66,6 +66,96 @@ define(function(require) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks for public key updates of a given user id
|
||||
* @param {String} userId The user id (email address) for which to check the key
|
||||
* @param {Function} callback(error, key) Invoked when the key has been updated or an error occurred
|
||||
*/
|
||||
KeychainDAO.prototype.refreshKeyForUserId = function(userId, callback) {
|
||||
var self = this;
|
||||
|
||||
// get the public key corresponding to the userId
|
||||
self.getReceiverPublicKey(userId, function(err, localKey) {
|
||||
if (!localKey || !localKey._id) {
|
||||
// there is no key available, no need to refresh
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// check if the key id still exists on the key server
|
||||
checkKeyExists(localKey);
|
||||
});
|
||||
|
||||
// checks if the user's key has been revoked by looking up the key id
|
||||
function checkKeyExists(localKey) {
|
||||
self._publicKeyDao.get(localKey._id, function(err, cloudKey) {
|
||||
if (err && err.code === 42) {
|
||||
// we're offline, we're done checking the key
|
||||
callback(null, localKey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
// there was an error, exit and inform
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cloudKey && cloudKey._id === localKey._id) {
|
||||
// the key is present on the server, all is well
|
||||
callback(null, localKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// the key has changed, update the key
|
||||
updateKey(localKey);
|
||||
});
|
||||
}
|
||||
|
||||
function updateKey(localKey) {
|
||||
// look for an updated key for the user id
|
||||
self._publicKeyDao.getByUserId(userId, function(err, newKey) {
|
||||
// offline?
|
||||
if (err && err.code === 42) {
|
||||
callback(null, localKey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// the public key has changed, we need to ask for permission to update the key
|
||||
self.requestPermissionForKeyUpdate({
|
||||
userId: userId,
|
||||
newKey: newKey
|
||||
}, function(granted) {
|
||||
if (!granted) {
|
||||
// permission was not given to update the key, so don't overwrite the old one!
|
||||
callback(null, localKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// permission to update the key was given, so delete the old one and persist the new one
|
||||
self.removeLocalPublicKey(localKey._id, function(err) {
|
||||
if (err || !newKey) {
|
||||
// error or no new key to save
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// persist the new key and return it
|
||||
self.saveLocalPublicKey(newKey, function(err) {
|
||||
callback(err, err ? undefined : newKey);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Look up a reveiver's public key by user id
|
||||
* @param userId [String] the receiver's email address
|
||||
@ -92,23 +182,27 @@ define(function(require) {
|
||||
|
||||
// no public key by that user id in storage
|
||||
// find from cloud by email address
|
||||
self._publicKeyDao.getByUserId(userId, onKeyGotten);
|
||||
self._publicKeyDao.getByUserId(userId, onKeyReceived);
|
||||
});
|
||||
|
||||
function onKeyGotten(err, cloudPubkey) {
|
||||
function onKeyReceived(err, cloudPubkey) {
|
||||
if (err && err.code === 42) {
|
||||
// offline
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cloudPubkey) {
|
||||
// no public key for that user
|
||||
// public key has been deleted without replacement
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// there is a public key for that user already in the cloud...
|
||||
// save to local storage
|
||||
self.saveLocalPublicKey(cloudPubkey, function(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
|
@ -34,19 +34,17 @@ define(function() {
|
||||
this._restDao.get({
|
||||
uri: uri
|
||||
}, function(err, key) {
|
||||
if (err && err.code === 404) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!key || !key._id) {
|
||||
callback({
|
||||
errMsg: 'No public key for that user!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, key);
|
||||
callback(null, (key && key._id) ? key : undefined);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -68,7 +68,7 @@ define(function(require) {
|
||||
|
||||
xhr.onerror = function() {
|
||||
callback({
|
||||
code: 404,
|
||||
code: 42,
|
||||
errMsg: 'Error calling GET on ' + options.uri
|
||||
});
|
||||
};
|
||||
|
@ -2,7 +2,6 @@ define(function() {
|
||||
'use strict';
|
||||
|
||||
var er = {};
|
||||
|
||||
er.attachHandler = function(scope) {
|
||||
scope.onError = function(options) {
|
||||
if (!options) {
|
||||
@ -19,7 +18,11 @@ define(function() {
|
||||
scope.state.dialog = {
|
||||
open: true,
|
||||
title: options.title || 'Error',
|
||||
message: options.errMsg || options.message
|
||||
message: options.errMsg || options.message,
|
||||
positiveBtnStr: options.positiveBtnStr || 'Ok',
|
||||
negativeBtnStr: options.negativeBtnStr || 'Cancel',
|
||||
showNegativeBtn: options.showNegativeBtn || false,
|
||||
callback: options.callback
|
||||
};
|
||||
// don't call apply for synchronous calls
|
||||
if (!options.sync) {
|
||||
|
@ -7,7 +7,8 @@
|
||||
<div class="content">
|
||||
<p>{{state.dialog.message}}</p>
|
||||
<div class="control">
|
||||
<button ng-click="confirm(true)" class="btn">Ok</button>
|
||||
<button ng-click="confirm(false)" class="btn btn-alt" ng-show="state.dialog.showNegativeBtn">{{state.dialog.negativeBtnStr}}</button>
|
||||
<button ng-click="confirm(true)" class="btn">{{state.dialog.positiveBtnStr}}</button>
|
||||
</div>
|
||||
</div><!-- /.content -->
|
||||
</div><!-- /.lightbox-body -->
|
@ -56,6 +56,255 @@ define(function(require) {
|
||||
});
|
||||
});
|
||||
|
||||
describe('refreshKeyForUserId', function() {
|
||||
var getPubKeyStub,
|
||||
oldKey = {
|
||||
_id: 123
|
||||
}, newKey = {
|
||||
_id: 456
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
getPubKeyStub = sinon.stub(keychainDao, 'getReceiverPublicKey');
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
keychainDao.getReceiverPublicKey.restore();
|
||||
delete keychainDao.requestPermissionForKeyUpdate;
|
||||
});
|
||||
|
||||
it('should not find a key', function(done) {
|
||||
getPubKeyStub.yields();
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.not.exist;
|
||||
expect(key).to.not.exist;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not update the key when up to date', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields(null, oldKey);
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.not.exist;
|
||||
expect(key).to.to.equal(oldKey);
|
||||
|
||||
expect(getPubKeyStub.calledOnce).to.be.true;
|
||||
expect(pubkeyDaoStub.get.calledOnce).to.be.true;
|
||||
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should update key', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields();
|
||||
pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey);
|
||||
keychainDao.requestPermissionForKeyUpdate = function(opts, cb) {
|
||||
expect(opts.userId).to.equal(testUser);
|
||||
expect(opts.newKey).to.equal(newKey);
|
||||
cb(true);
|
||||
};
|
||||
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
||||
lawnchairDaoStub.persist.withArgs('publickey_' + newKey._id, newKey).yields();
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.not.exist;
|
||||
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;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should remove key', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields();
|
||||
pubkeyDaoStub.getByUserId.withArgs(testUser).yields();
|
||||
keychainDao.requestPermissionForKeyUpdate = function(opts, cb) {
|
||||
expect(opts.userId).to.equal(testUser);
|
||||
expect(opts.newKey).to.not.exist;
|
||||
cb(true);
|
||||
};
|
||||
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.not.exist;
|
||||
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;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should go offline while fetching new key', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields();
|
||||
pubkeyDaoStub.getByUserId.withArgs(testUser).yields({
|
||||
code: 42
|
||||
});
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.not.exist;
|
||||
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;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not remove old key on user rejection', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields();
|
||||
pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey);
|
||||
keychainDao.requestPermissionForKeyUpdate = function(opts, cb) {
|
||||
expect(opts.userId).to.equal(testUser);
|
||||
expect(opts.newKey).to.exist;
|
||||
cb(false);
|
||||
};
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.not.exist;
|
||||
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;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should update not the key when offline', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields({
|
||||
code: 42
|
||||
});
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.not.exist;
|
||||
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(lawnchairDaoStub.remove.called).to.be.false;
|
||||
expect(lawnchairDaoStub.persist.called).to.be.false;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error while persisting new key', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields();
|
||||
pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey);
|
||||
keychainDao.requestPermissionForKeyUpdate = function(opts, cb) {
|
||||
expect(opts.userId).to.equal(testUser);
|
||||
expect(opts.newKey).to.equal(newKey);
|
||||
cb(true);
|
||||
};
|
||||
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
||||
lawnchairDaoStub.persist.yields({});
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.exist;
|
||||
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.calledOnce).to.be.true;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error while deleting old key', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields();
|
||||
pubkeyDaoStub.getByUserId.withArgs(testUser).yields();
|
||||
keychainDao.requestPermissionForKeyUpdate = function(opts, cb) {
|
||||
expect(opts.userId).to.equal(testUser);
|
||||
cb(true);
|
||||
};
|
||||
lawnchairDaoStub.remove.yields({});
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.exist;
|
||||
expect(key).to.not.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;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error while persisting new key', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields();
|
||||
pubkeyDaoStub.getByUserId.withArgs(testUser).yields(null, newKey);
|
||||
keychainDao.requestPermissionForKeyUpdate = function(opts, cb) {
|
||||
expect(opts.userId).to.equal(testUser);
|
||||
expect(opts.newKey).to.equal(newKey);
|
||||
cb(true);
|
||||
};
|
||||
lawnchairDaoStub.remove.withArgs('publickey_' + oldKey._id).yields();
|
||||
lawnchairDaoStub.persist.yields({});
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.exist;
|
||||
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.calledOnce).to.be.true;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should error when get failed', function(done) {
|
||||
getPubKeyStub.yields(null, oldKey);
|
||||
pubkeyDaoStub.get.withArgs(oldKey._id).yields({});
|
||||
|
||||
keychainDao.refreshKeyForUserId(testUser, function(err, key) {
|
||||
expect(err).to.exist;
|
||||
expect(key).to.not.exist;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('lookup public key', function() {
|
||||
it('should fail', function(done) {
|
||||
keychainDao.lookupPublicKey(undefined, function(err, key) {
|
||||
@ -182,7 +431,7 @@ define(function(require) {
|
||||
|
||||
it('should fail due to error in pubkey dao', function(done) {
|
||||
lawnchairDaoStub.list.yields();
|
||||
pubkeyDaoStub.getByUserId.yields(42);
|
||||
pubkeyDaoStub.getByUserId.yields({});
|
||||
|
||||
keychainDao.getReceiverPublicKey(testUser, function(err, key) {
|
||||
expect(err).to.exist;
|
||||
|
@ -19,9 +19,9 @@ define(function(require) {
|
||||
hasChrome, hasSocket, hasRuntime, hasIdentity;
|
||||
|
||||
beforeEach(function() {
|
||||
hasChrome = !! window.chrome;
|
||||
hasSocket = !! window.chrome.socket;
|
||||
hasIdentity = !! window.chrome.identity;
|
||||
hasChrome = !!window.chrome;
|
||||
hasSocket = !!window.chrome.socket;
|
||||
hasIdentity = !!window.chrome.identity;
|
||||
if (!hasChrome) {
|
||||
window.chrome = {};
|
||||
}
|
||||
@ -62,7 +62,7 @@ define(function(require) {
|
||||
|
||||
|
||||
keychainMock = sinon.createStubInstance(KeychainDAO);
|
||||
emailDaoMock._keychain = keychainMock;
|
||||
appController._keychain = keychainMock;
|
||||
|
||||
deviceStorageMock = sinon.createStubInstance(DeviceStorageDAO);
|
||||
emailDaoMock._devicestorage = deviceStorageMock;
|
||||
@ -224,9 +224,12 @@ define(function(require) {
|
||||
});
|
||||
|
||||
describe('select', function() {
|
||||
it('should decrypt, focus, and mark an unread mail as read', function() {
|
||||
it('should decrypt, focus mark an unread mail as read', function() {
|
||||
var mail = {
|
||||
unread: true
|
||||
from: [{
|
||||
address: 'asd'
|
||||
}],
|
||||
unread: true,
|
||||
};
|
||||
scope.state = {
|
||||
nav: {
|
||||
@ -240,16 +243,23 @@ define(function(require) {
|
||||
}
|
||||
};
|
||||
|
||||
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
|
||||
|
||||
scope.select(mail);
|
||||
|
||||
expect(emailDaoMock.decryptBody.calledOnce).to.be.true;
|
||||
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
|
||||
expect(scope.state.mailList.selected).to.equal(mail);
|
||||
});
|
||||
|
||||
it('should decrypt and focus a read mail', function() {
|
||||
var mail = {
|
||||
from: [{
|
||||
address: 'asd'
|
||||
}],
|
||||
unread: false
|
||||
};
|
||||
|
||||
scope.state = {
|
||||
mailList: {},
|
||||
read: {
|
||||
@ -262,9 +272,12 @@ define(function(require) {
|
||||
}
|
||||
};
|
||||
|
||||
keychainMock.refreshKeyForUserId.withArgs(mail.from[0].address).yields();
|
||||
|
||||
scope.select(mail);
|
||||
|
||||
expect(emailDaoMock.decryptBody.calledOnce).to.be.true;
|
||||
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
|
||||
expect(scope.state.mailList.selected).to.equal(mail);
|
||||
});
|
||||
});
|
||||
|
@ -12,7 +12,7 @@ define(function(require) {
|
||||
|
||||
describe('Write controller unit test', function() {
|
||||
var ctrl, scope,
|
||||
origEmailDao, origOutbox,
|
||||
origEmailDao, origOutbox, origKeychain,
|
||||
emailDaoMock, keychainMock, outboxMock, emailAddress;
|
||||
|
||||
beforeEach(function() {
|
||||
@ -20,6 +20,7 @@ define(function(require) {
|
||||
// outbox and email dao to restore it after the tests
|
||||
origEmailDao = appController._emailDao;
|
||||
origOutbox = appController._outboxBo;
|
||||
origKeychain = appController._keychain;
|
||||
|
||||
outboxMock = sinon.createStubInstance(OutboxBO);
|
||||
appController._outboxBo = outboxMock;
|
||||
@ -33,7 +34,7 @@ define(function(require) {
|
||||
};
|
||||
|
||||
keychainMock = sinon.createStubInstance(KeychainDAO);
|
||||
emailDaoMock._keychain = keychainMock;
|
||||
appController._keychain = keychainMock;
|
||||
|
||||
angular.module('writetest', []);
|
||||
mocks.module('writetest');
|
||||
@ -50,6 +51,7 @@ define(function(require) {
|
||||
// restore the app controller
|
||||
appController._emailDao = origEmailDao;
|
||||
appController._outboxBo = origOutbox;
|
||||
appController._keychain = origKeychain;
|
||||
});
|
||||
|
||||
describe('scope variables', function() {
|
||||
@ -215,14 +217,15 @@ define(function(require) {
|
||||
address: 'asds@example.com'
|
||||
};
|
||||
|
||||
keychainMock.getReceiverPublicKey.withArgs(recipient.address).yields({
|
||||
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields({
|
||||
errMsg: '404 not found yadda yadda'
|
||||
});
|
||||
|
||||
scope.onError = function() {
|
||||
expect(recipient.key).to.be.undefined;
|
||||
expect(recipient.secure).to.be.false;
|
||||
expect(scope.checkSendStatus.callCount).to.equal(1);
|
||||
expect(keychainMock.getReceiverPublicKey.calledOnce).to.be.true;
|
||||
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
|
||||
done();
|
||||
};
|
||||
|
||||
@ -234,16 +237,17 @@ define(function(require) {
|
||||
address: 'asdf@example.com'
|
||||
};
|
||||
|
||||
keychainMock.getReceiverPublicKey.yields(null, {
|
||||
keychainMock.refreshKeyForUserId.withArgs(recipient.address).yields(null, {
|
||||
userId: 'asdf@example.com'
|
||||
});
|
||||
|
||||
scope.$digest = function() {
|
||||
expect(recipient.key).to.deep.equal({
|
||||
userId: 'asdf@example.com'
|
||||
});
|
||||
expect(recipient.secure).to.be.true;
|
||||
expect(scope.checkSendStatus.callCount).to.equal(2);
|
||||
expect(keychainMock.getReceiverPublicKey.calledOnce).to.be.true;
|
||||
expect(keychainMock.refreshKeyForUserId.calledOnce).to.be.true;
|
||||
done();
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user