Merge pull request #2 from whiteout-io/dev/multi-recipient

Dev/multi recipient
This commit is contained in:
Tankred Hase 2014-01-15 01:59:52 -08:00
commit 7b465d13a2
10 changed files with 395 additions and 223 deletions

View File

@ -54,7 +54,9 @@ define(function(require) {
cryptSuffix: '-----END PGP MESSAGE-----',
signature: 'Sent securely from Whiteout Mail',
webSite: 'http://whiteout.io',
verificationSubject: 'New public key uploaded'
verificationSubject: 'New public key uploaded',
sendBtnInvite: 'Invite & send securely',
sendBtnSecure: 'Send securely'
};
return app;

View File

@ -53,6 +53,8 @@ define(function(require) {
mail.from.forEach(checkPublicKey);
// display recipient security status
mail.to.forEach(checkPublicKey);
// display recipient security status
Array.isArray(mail.cc) && mail.cc.forEach(checkPublicKey);
});
function checkPublicKey(user) {

View File

@ -5,6 +5,7 @@ define(function(require) {
appController = require('js/app-controller'),
aes = require('cryptoLib/aes-cbc'),
util = require('cryptoLib/util'),
str = require('js/app-config').string,
emailDao;
//
@ -30,7 +31,7 @@ define(function(require) {
fillFields(replyTo);
$scope.updatePreview();
$scope.verifyTo();
$scope.verify($scope.to[0]);
},
close: function() {
this.open = false;
@ -39,7 +40,15 @@ define(function(require) {
function resetFields() {
$scope.writerTitle = 'New email';
$scope.to = '';
$scope.to = [{
address: ''
}];
$scope.cc = [{
address: ''
}];
$scope.bcc = [{
address: ''
}];
$scope.subject = '';
$scope.body = '';
$scope.ciphertextPreview = '';
@ -54,7 +63,9 @@ define(function(require) {
$scope.writerTitle = 'Reply';
// fill recipient field
$scope.to = re.from[0].address;
$scope.to.unshift({
address: re.from[0].address
});
// fill subject
$scope.subject = 'Re: ' + ((re.subject) ? re.subject.replace('Re: ', '') : '');
@ -73,45 +84,98 @@ define(function(require) {
// Editing headers
//
$scope.verifyTo = function() {
if (!$scope.to) {
resetDisplay();
/**
* This event is fired when editing the email address headers. It checks is space is pressed and if so, creates a new address field.
*/
$scope.onAddressUpdate = function(field, index) {
var recipient = field[index],
address = recipient.address;
// handle number of email inputs for multiple recipients
if (address.indexOf(' ') !== -1) {
recipient.address = address.replace(' ', '');
field.push({
address: ''
});
} else if (address.length === 0 && field.length > 1) {
field.splice(field.indexOf(recipient), 1);
}
$scope.verify(recipient);
};
/**
* Verify and email address and fetch its public key
*/
$scope.verify = function(recipient) {
// set display to insecure while fetching keys
recipient.key = undefined;
recipient.secure = false;
// verify email address
if (!util.validateEmailAddress(recipient.address)) {
recipient.secure = undefined;
$scope.checkSendStatus();
return;
}
// set display to insecure while fetching keys
$scope.toKey = undefined;
displayInsecure();
// check if to address is contained in known public keys
emailDao._keychain.getReceiverPublicKey($scope.to, function(err, key) {
emailDao._keychain.getReceiverPublicKey(recipient.address, function(err, key) {
if (err) {
$scope.onError(err);
return;
}
// compare again since model could have changed during the roundtrip
if (key && key.userId === $scope.to) {
$scope.toKey = key;
displaySecure();
$scope.$apply();
if (key && key.userId === recipient.address) {
recipient.key = key;
recipient.secure = true;
}
$scope.checkSendStatus();
$scope.$apply();
});
};
function resetDisplay() {
$scope.toSecure = undefined;
/**
* Check if it is ok to send an email depending on the invitation state of the addresses
*/
$scope.checkSendStatus = function() {
$scope.okToSend = false;
$scope.sendBtnText = undefined;
}
$scope.sendBtnSecure = undefined;
function displaySecure() {
$scope.toSecure = true;
$scope.sendBtnText = 'Send securely';
}
var allSecure = true;
var numReceivers = 0;
function displayInsecure() {
$scope.toSecure = false;
$scope.sendBtnText = 'Invite & send securely';
}
// count number of receivers and check security
$scope.to.forEach(check);
$scope.cc.forEach(check);
$scope.bcc.forEach(check);
function check(recipient) {
// validate address
if (!util.validateEmailAddress(recipient.address)) {
return;
}
numReceivers++;
if (!recipient.secure) {
allSecure = false;
}
}
// sender can invite only one use at a time
if (!allSecure && numReceivers === 1) {
$scope.sendBtnText = str.sendBtnInvite;
$scope.okToSend = true;
$scope.sendBtnSecure = false;
} else if (allSecure && numReceivers > 0) {
// all recipients are secure
$scope.sendBtnText = str.sendBtnSecure;
$scope.okToSend = true;
$scope.sendBtnSecure = true;
}
};
//
// Editing email body
@ -129,20 +193,13 @@ define(function(require) {
};
$scope.sendToOutbox = function() {
var to, email;
// validate recipients
to = $scope.to.replace(/\s/g, '').split(/[,;]/);
if (!to || to.length < 1) {
$scope.onError({
errMsg: 'Seperate recipients with a comma!',
sync: true
});
return;
}
var email;
// build email model for smtp-client
email = {
to: [], // list of receivers
to: [],
cc: [],
bcc: [],
subject: $scope.subject, // Subject line
body: $scope.body // use parsed plaintext body
};
@ -150,13 +207,34 @@ define(function(require) {
name: '',
address: emailDao._account.emailAddress
}];
to.forEach(function(address) {
email.to.push({
name: '',
address: address
});
});
// validate recipients and gather public keys
email.receiverKeys = []; // gather public keys for emailDao._encrypt
appendReceivers($scope.to, email.to);
appendReceivers($scope.cc, email.cc);
appendReceivers($scope.bcc, email.bcc);
function appendReceivers(srcField, destField) {
srcField.forEach(function(recipient) {
// validate address
if (!util.validateEmailAddress(recipient.address)) {
return;
}
// append address to email model
destField.push({
address: recipient.address
});
// add public key to list of recipient keys
if (recipient.key && recipient.key.publicKey) {
email.receiverKeys.push(recipient.key.publicKey);
}
});
}
// persist the email locally for later smtp transmission
emailDao.store(email, function(err) {
if (err) {
$scope.onError(err);
@ -254,16 +332,40 @@ define(function(require) {
link: function(scope, elm, attrs) {
var model = $parse(attrs.autoSize);
scope.$watch(model, function(value) {
if (!value) {
return;
var width;
if (value.length < 12) {
width = (14 * 8) + 'px';
} else {
width = ((value.length + 2) * 8) + 'px';
}
var width = ((value.length + 2) * 8) + 'px';
elm.css('width', width);
});
}
};
});
ngModule.directive('addressInput', function($timeout) {
return {
//scope: true, // optionally create a child scope
link: function(scope, element, attrs) {
// get prefix for id
var idPrefix = attrs.addressInput;
element.bind('keydown', function(e) {
if (e.keyCode === 32) {
// space -> go to next input
$timeout(function() {
// find next input and focus
var index = attrs.id.replace(idPrefix, '');
var nextId = idPrefix + (parseInt(index, 10) + 1);
document.getElementById(nextId).focus();
}, 100);
}
});
}
};
});
return WriteCtrl;
});

View File

@ -875,58 +875,24 @@ define(function(require) {
}
// validate the email input
if (!email.to || !email.from || !email.to[0].address || !email.from[0].address) {
if (!email.to || !email.from || !email.to[0].address || !email.from[0].address || !Array.isArray(email.receiverKeys)) {
callback({
errMsg: 'Invalid email object!'
});
return;
}
// validate email addresses
for (var i = email.to.length - 1; i >= 0; i--) {
if (!util.validateEmailAddress(email.to[i].address)) {
callback({
errMsg: 'Invalid recipient: ' + email.to[i].address
});
return;
}
}
if (!util.validateEmailAddress(email.from[0].address)) {
callback({
errMsg: 'Invalid sender: ' + email.from
});
return;
}
// only support single recipient for e-2-e encryption
// check if receiver has a public key
self._keychain.getReceiverPublicKey(email.to[0].address, function(err, receiverPubkey) {
// public key found... encrypt and send
self._encrypt({
email: email,
keys: email.receiverKeys // this Array is set in writer controller
}, function(err, email) {
if (err) {
callback(err);
return;
}
// validate public key
if (!receiverPubkey) {
callback({
errMsg: 'User has no public key yet!'
});
return;
}
// public key found... encrypt and send
self._encrypt({
email: email,
keys: [receiverPubkey.publicKey]
}, function(err, email) {
if (err) {
callback(err);
return;
}
self._smtpClient.send(email, callback);
});
self._smtpClient.send(email, callback);
});
};

View File

@ -7,7 +7,7 @@
.headers {
p {
margin: 0px;
padding: 0px;
padding: 0px;
}
.subject {

View File

@ -20,6 +20,12 @@
.headers {
margin-top: 10px;
p {
margin: 0.2em 0;
padding: 0.2em 0;
}
span {
color: $color-grey;
}

View File

@ -16,7 +16,7 @@
</p>
<div ng-switch="state.mailList.selected.cc !== undefined">
<p class="address" ng-switch-when="true">
CC: <span ng-repeat="u in state.mailList.selected.cc" class="label" ng-class="{'label-primary': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : (u.secure === true) ? '&#xe009;' : ''}}" ng-mouseover="getFingerprint(u.address)" popover="#fingerprint-info">{{u.name || u.address}}</span>
Cc: <span ng-repeat="u in state.mailList.selected.cc" class="label" ng-class="{'label-primary': u.secure === false}" data-icon-append="{{(u.secure === false) ? '&#xe001;' : (u.secure === true) ? '&#xe009;' : ''}}" ng-mouseover="getFingerprint(u.address)" popover="#fingerprint-info">{{u.name || u.address}}</span>
</p>
</div>
</div><!--/.headers-->

View File

@ -9,17 +9,21 @@
<div class="headers">
<p>
<span>To:</span>
<input type="email" ng-model="to" ng-change="verifyTo()" ng-class="{'label': toSecure === true, 'label label-primary': toSecure === false}" tabindex="1" focus-me="state.writer.open && writerTitle !== 'Reply'" auto-size="to" spellcheck="false">
<span ng-repeat="recipient in to track by $index">
<input id="to{{$index}}" value="{{recipient.address}}" ng-model="recipient.address" ng-trim="false" ng-class="{'label': recipient.secure === true, 'label label-primary': recipient.secure === false && recipient.valid !== true}" auto-size="recipient.address" spellcheck="false" ng-change="onAddressUpdate(to, $index)" address-input="to" tabindex="1" focus-me="state.writer.open && writerTitle !== 'Reply'">
</span>
</p>
<p>
<span>Cc:</span>
<!--<input type="email" ng-model="cc" tabindex="2">-->
<span ng-repeat="recipient in cc track by $index">
<input id="cc{{$index}}" value="{{recipient.address}}" ng-model="recipient.address" ng-trim="false" ng-class="{'label': recipient.secure === true, 'label label-primary': recipient.secure === false && recipient.valid !== true}" auto-size="recipient.address" spellcheck="false" ng-change="onAddressUpdate(cc, $index)" address-input="cc" tabindex="1">
</span>
</p>
</div><!--/.address-headers-->
<div class="subject-box">
<div class="subject-line">
<input ng-model="subject" class="subject" spellcheck="true" tabindex="3" placeholder="Subject" ng-change="updatePreview()">
<input ng-model="subject" class="subject" spellcheck="true" tabindex="2" placeholder="Subject" ng-change="updatePreview()">
</div>
<button class="btn-attachment">
<div data-icon="&#xe003;"></div>
@ -27,7 +31,7 @@
</div><!--/.subject-box-->
<div class="body" focus-child>
<p ng-model="body" contentEditable="true" spellcheck="false" ng-change="updatePreview()" tabindex="4" focus-me="state.writer.open && writerTitle === 'Reply'"></p>
<p ng-model="body" contentEditable="true" spellcheck="false" ng-change="updatePreview()" tabindex="3" focus-me="state.writer.open && writerTitle === 'Reply'"></p>
<div class="encrypt-preview" ng-class="{'invisible': !ciphertextPreview}">
<p>-----BEGIN ENCRYPTED PREVIEW-----<br>{{ciphertextPreview}}<br>-----END ENCRYPTED PREVIEW-----</p>
@ -35,7 +39,7 @@
</div><!--/.body-->
<div class="send-control">
<button ng-click="sendToOutbox()" class="btn" data-icon="{{(toSecure === false) ? '&#xe001;' : (toSecure === true) ? '&#xe009;' : ''}}" ng-disabled="!to" tabindex="5">{{sendBtnText || 'Send'}}</button>
<button ng-click="sendToOutbox()" class="btn" data-icon="{{(sendBtnSecure === false) ? '&#xe001;' : (sendBtnSecure === true) ? '&#xe009;' : ''}}" ng-disabled="!okToSend" tabindex="4">{{sendBtnText || 'Send'}}</button>
</div>
</div><!--/.write-view-->

View File

@ -75,7 +75,8 @@ define(function(require) {
subject: 'qweasd',
body: 'asd',
unread: false,
answered: false
answered: false,
receiverKeys: ['-----BEGIN PGP PUBLIC KEY-----\nasd\n-----END PGP PUBLIC KEY-----']
};
nonWhitelistedMail = {
uid: 1234,
@ -2409,11 +2410,7 @@ define(function(require) {
describe('sendEncrypted', function() {
it('should work', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt').yields(null, {});
keychainStub.getReceiverPublicKey.withArgs(dummyDecryptedMail.to[0].address).yields(null, {
_id: "fcf8b4aa-5d09-4089-8b4f-e3bc5091daf3",
userId: dummyDecryptedMail.to[0].address,
publicKey: publicKey
});
smtpClientStub.send.yields();
dao.sendEncrypted({
@ -2421,7 +2418,6 @@ define(function(require) {
}, function(err) {
expect(err).to.not.exist;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(encryptStub.calledOnce).to.be.true;
expect(smtpClientStub.send.calledOnce).to.be.true;
@ -2430,72 +2426,18 @@ define(function(require) {
});
it('should not work when encryption fails', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt').yields({});
keychainStub.getReceiverPublicKey.withArgs(dummyDecryptedMail.to[0].address).yields(null, {
_id: "fcf8b4aa-5d09-4089-8b4f-e3bc5091daf3",
userId: dummyDecryptedMail.to[0].address,
publicKey: publicKey
});
dao.sendEncrypted({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(encryptStub.calledOnce).to.be.true;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
it('should not work when key retrieval fails', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt');
keychainStub.getReceiverPublicKey.withArgs(dummyDecryptedMail.to[0].address).yields({});
dao.sendEncrypted({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.calledOnce).to.be.true;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
it('should not work invalid recipients', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt');
dummyDecryptedMail.to[0].address = 'asd@asd';
dao.sendEncrypted({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
it('should not work with without sender', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt');
dummyDecryptedMail.from[0].address = 'asd@asd';
dao.sendEncrypted({
email: dummyDecryptedMail
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;
done();
});
});
it('should not work without recipients', function(done) {
var encryptStub = sinon.stub(dao, '_encrypt');
delete dummyDecryptedMail.to;
@ -2505,7 +2447,6 @@ define(function(require) {
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;
@ -2521,7 +2462,6 @@ define(function(require) {
}, function(err) {
expect(err).to.exist;
expect(keychainStub.getReceiverPublicKey.called).to.be.false;
expect(encryptStub.called).to.be.false;
expect(smtpClientStub.send.called).to.be.false;

View File

@ -47,7 +47,9 @@ define(function(require) {
expect(scope.state.writer.open).to.be.false;
expect(scope.state.writer.write).to.exist;
expect(scope.state.writer.close).to.exist;
expect(scope.verifyTo).to.exist;
expect(scope.verify).to.exist;
expect(scope.onAddressUpdate).to.exist;
expect(scope.checkSendStatus).to.exist;
expect(scope.updatePreview).to.exist;
expect(scope.sendToOutbox).to.exist;
});
@ -65,22 +67,24 @@ define(function(require) {
describe('write', function() {
it('should prepare write view', function() {
var verifyToMock = sinon.stub(scope, 'verifyTo');
var verifyMock = sinon.stub(scope, 'verify');
scope.state.writer.write();
expect(scope.writerTitle).to.equal('New email');
expect(scope.to).to.equal('');
expect(scope.to).to.deep.equal([{
address: ''
}]);
expect(scope.subject).to.equal('');
expect(scope.body).to.equal('');
expect(scope.ciphertextPreview).to.equal('');
expect(verifyToMock.calledOnce).to.be.true;
expect(verifyMock.calledOnce).to.be.true;
scope.verifyTo.restore();
scope.verify.restore();
});
it('should prefill write view for response', function() {
var verifyToMock = sinon.stub(scope, 'verifyTo'),
var verifyMock = sinon.stub(scope, 'verify'),
address = 'pity@dafool',
subject = 'Ermahgerd!',
body = 'so much body!',
@ -96,61 +100,210 @@ define(function(require) {
scope.state.writer.write(re);
expect(scope.writerTitle).to.equal('Reply');
expect(scope.to).to.equal(address);
expect(scope.to).to.deep.equal([{
address: address,
}, {
address: ''
}]);
expect(scope.subject).to.equal('Re: ' + subject);
expect(scope.body).to.contain(body);
expect(scope.ciphertextPreview).to.not.be.empty;
expect(verifyToMock.calledOnce).to.be.true;
expect(verifyMock.calledOnce).to.be.true;
scope.verifyTo.restore();
scope.verify.restore();
});
});
describe('verifyTo', function() {
it('should verify the recipient as secure', function() {
var id = scope.to = 'pity@da.fool';
keychainMock.getReceiverPublicKey.withArgs(id).yields(null, {
userId: id
});
describe('onAddressUpdate', function() {
var verifyMock;
scope.verifyTo();
expect(scope.toSecure).to.be.true;
expect(scope.sendBtnText).to.equal('Send securely');
beforeEach(function() {
verifyMock = sinon.stub(scope, 'verify');
});
it('should verify the recipient as not secure', function(done) {
var id = scope.to = 'pity@da.fool';
keychainMock.getReceiverPublicKey.withArgs(id).yields({
afterEach(function() {
scope.verify.restore();
});
it('should add new field item if space is pressed', function() {
var to = [{
address: 'asdf@asdf.de '
}];
scope.onAddressUpdate(to, 0);
expect(to.length).to.equal(2);
expect(to[0].address).to.equal('asdf@asdf.de');
expect(to[1].address).to.equal('');
expect(verifyMock.calledOnce).to.be.true;
});
it('should remove field item if address is empty', function() {
var to = [{
address: 'asdf@asdf.de'
}, {
address: ''
}];
scope.onAddressUpdate(to, 1);
expect(to.length).to.equal(1);
expect(to[0].address).to.equal('asdf@asdf.de');
expect(verifyMock.calledOnce).to.be.true;
});
it('should not remove last field item if address is empty', function() {
var to = [{
address: ''
}];
scope.onAddressUpdate(to, 0);
expect(to.length).to.equal(1);
expect(to[0].address).to.equal('');
expect(verifyMock.calledOnce).to.be.true;
});
it('should do nothing for normal address', function() {
var to = [{
address: 'asdf@asdf.de'
}];
scope.onAddressUpdate(to, 0);
expect(to.length).to.equal(1);
expect(to[0].address).to.equal('asdf@asdf.de');
expect(verifyMock.calledOnce).to.be.true;
});
});
describe('verify', function() {
var checkSendStatusMock;
beforeEach(function() {
checkSendStatusMock = sinon.stub(scope, 'checkSendStatus');
});
afterEach(function() {
scope.checkSendStatus.restore();
});
it('should not work for invalid email addresses', function() {
var recipient = {
address: ''
};
scope.verify(recipient);
expect(recipient.key).to.be.undefined;
expect(recipient.secure).to.be.undefined;
expect(scope.checkSendStatus.calledOnce).to.be.true;
expect(keychainMock.getReceiverPublicKey.called).to.be.false;
});
it('should not work for error in keychain', function(done) {
var recipient = {
address: 'asds@example.com'
};
keychainMock.getReceiverPublicKey.withArgs(recipient.address).yields({
errMsg: '404 not found yadda yadda'
});
scope.onError = function() {
expect(scope.toSecure).to.be.false;
expect(scope.sendBtnText).to.equal('Invite & send securely');
expect(recipient.key).to.be.undefined;
expect(recipient.secure).to.be.false;
expect(scope.checkSendStatus.called).to.be.false;
expect(keychainMock.getReceiverPublicKey.calledOnce).to.be.true;
done();
};
scope.verifyTo();
scope.verify(recipient);
});
it('should reset display if there is no recipient', function() {
scope.to = undefined;
scope.verifyTo();
it('should work', function(done) {
var recipient = {
address: 'asdf@example.com'
};
keychainMock.getReceiverPublicKey.yields(null, {
userId: 'asdf@example.com'
});
scope.$apply = function() {
expect(recipient.key).to.deep.equal({
userId: 'asdf@example.com'
});
expect(recipient.secure).to.be.true;
expect(scope.checkSendStatus.calledOnce).to.be.true;
expect(keychainMock.getReceiverPublicKey.calledOnce).to.be.true;
done();
};
scope.verify(recipient);
});
});
describe('checkSendStatus', function() {
beforeEach(function() {
scope.state.writer.write();
});
afterEach(function() {});
it('should not be able to send with no recipients', function() {
scope.checkSendStatus();
expect(scope.okToSend).to.be.false;
expect(scope.sendBtnText).to.be.undefined;
expect(scope.sendBtnSecure).to.be.undefined;
});
it('should not be to invite 1 user', function() {
scope.to = [{
address: 'asdf@asdf.de'
}];
scope.checkSendStatus();
expect(scope.okToSend).to.be.true;
expect(scope.sendBtnText).to.equal('Invite & send securely');
expect(scope.sendBtnSecure).to.be.false;
});
it('should not be able to invite multiple recipients', function() {
scope.to = [{
address: 'asdf@asdf.de'
}, {
address: 'asdf@asdfg.de'
}];
scope.checkSendStatus();
expect(scope.okToSend).to.be.false;
expect(scope.sendBtnText).to.be.undefined;
expect(scope.sendBtnSecure).to.be.undefined;
});
it('should be able to send securely to multiple recipients', function() {
scope.to = [{
address: 'asdf@asdf.de',
secure: true
}, {
address: 'asdf@asdfg.de',
secure: true
}];
scope.checkSendStatus();
expect(scope.okToSend).to.be.true;
expect(scope.sendBtnText).to.equal('Send securely');
expect(scope.sendBtnSecure).to.be.true;
});
});
describe('send to outbox', function() {
it('should work when offline', function(done) {
var verifyToSpy = sinon.spy(scope, 'verifyTo'),
re = {
from: [{
address: 'pity@dafool'
}],
subject: 'Ermahgerd!',
sentDate: new Date(),
body: 'so much body!'
};
var re = {
from: [{
address: 'pity@dafool'
}],
subject: 'Ermahgerd!',
sentDate: new Date(),
body: 'so much body!'
};
scope.state.nav = {
currentFolder: 'currentFolder'
@ -160,11 +313,9 @@ define(function(require) {
scope.onError = function(err) {
expect(err).to.not.exist;
expect(scope.state.writer.open).to.be.false;
expect(verifyToSpy.calledOnce).to.be.true;
expect(emailDaoMock.store.calledOnce).to.be.true;
expect(emailDaoMock.sync.calledOnce).to.be.true;
scope.verifyTo.restore();
done();
};
@ -178,15 +329,14 @@ define(function(require) {
});
it('should work', function(done) {
var verifyToSpy = sinon.spy(scope, 'verifyTo'),
re = {
from: [{
address: 'pity@dafool'
}],
subject: 'Ermahgerd!',
sentDate: new Date(),
body: 'so much body!'
};
var re = {
from: [{
address: 'pity@dafool'
}],
subject: 'Ermahgerd!',
sentDate: new Date(),
body: 'so much body!'
};
scope.state.nav = {
currentFolder: 'currentFolder'
@ -196,11 +346,9 @@ define(function(require) {
scope.onError = function(err) {
expect(err).to.not.exist;
expect(scope.state.writer.open).to.be.false;
expect(verifyToSpy.calledOnce).to.be.true;
expect(emailDaoMock.store.calledOnce).to.be.true;
expect(emailDaoMock.sync.calledOnce).to.be.true;
scope.verifyTo.restore();
done();
};
@ -212,15 +360,14 @@ define(function(require) {
});
it('should fail', function(done) {
var verifyToSpy = sinon.spy(scope, 'verifyTo'),
re = {
from: [{
address: 'pity@dafool'
}],
subject: 'Ermahgerd!',
sentDate: new Date(),
body: 'so much body!'
};
var re = {
from: [{
address: 'pity@dafool'
}],
subject: 'Ermahgerd!',
sentDate: new Date(),
body: 'so much body!'
};
scope.state.nav = {
currentFolder: 'currentFolder'
@ -230,11 +377,9 @@ define(function(require) {
scope.onError = function(err) {
expect(err).to.exist;
expect(scope.state.writer.open).to.be.false;
expect(verifyToSpy.calledOnce).to.be.true;
expect(emailDaoMock.store.calledOnce).to.be.true;
expect(emailDaoMock.sync.calledOnce).to.be.true;
scope.verifyTo.restore();
done();
};
@ -246,14 +391,20 @@ define(function(require) {
});
it('should not work and not close the write view', function(done) {
scope.state.writer.open = true;
scope.to = 'a, b, c';
scope.state.writer.write();
scope.to = [{
address: 'pity@dafool.de',
key: {
publicKey: '----- PGP Stuff -----'
}
}];
scope.body = 'asd';
scope.subject = 'yaddablabla';
scope.toKey = 'Public Key';
emailDaoMock.store.withArgs(sinon.match(function(mail) {
return mail.from[0].address === emailAddress && mail.to.length === 3;
return mail.from[0].address === emailAddress && mail.to.length === 1 && mail.receiverKeys.length === 1;
})).yields({
errMsg: 'snafu'
});
@ -264,7 +415,6 @@ define(function(require) {
expect(emailDaoMock.store.calledOnce).to.be.true;
done();
};
scope.sendToOutbox();
});
});