mirror of
https://github.com/moparisthebest/mail
synced 2024-11-23 09:22:23 -05:00
Merge branch 'login' into outbox
Conflicts: src/js/app.js
This commit is contained in:
commit
2976e128ed
@ -41,7 +41,7 @@ define(function(require) {
|
|||||||
/**
|
/**
|
||||||
* Request an OAuth token from chrome for gmail users
|
* Request an OAuth token from chrome for gmail users
|
||||||
*/
|
*/
|
||||||
self.fetchOAuthToken = function(passphrase, callback) {
|
self.fetchOAuthToken = function(callback) {
|
||||||
// get OAuth Token from chrome
|
// get OAuth Token from chrome
|
||||||
chrome.identity.getAuthToken({
|
chrome.identity.getAuthToken({
|
||||||
'interactive': true
|
'interactive': true
|
||||||
@ -65,7 +65,10 @@ define(function(require) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// init the email dao
|
// init the email dao
|
||||||
self.init(emailAddress, passphrase, token, callback);
|
callback(null, {
|
||||||
|
emailAddress: emailAddress,
|
||||||
|
token: token
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -124,7 +127,7 @@ define(function(require) {
|
|||||||
/**
|
/**
|
||||||
* Instanciate the mail email data access object and its dependencies. Login to imap on init.
|
* Instanciate the mail email data access object and its dependencies. Login to imap on init.
|
||||||
*/
|
*/
|
||||||
self.init = function(userId, passphrase, token, callback) {
|
self.init = function(userId, token, callback) {
|
||||||
var auth, imapOptions, smtpOptions,
|
var auth, imapOptions, smtpOptions,
|
||||||
keychain, imapClient, smtpClient, pgp, userStorage;
|
keychain, imapClient, smtpClient, pgp, userStorage;
|
||||||
|
|
||||||
@ -162,7 +165,7 @@ define(function(require) {
|
|||||||
emailAddress: userId,
|
emailAddress: userId,
|
||||||
asymKeySize: config.asymKeySize
|
asymKeySize: config.asymKeySize
|
||||||
};
|
};
|
||||||
self._emailDao.init(account, passphrase, callback);
|
self._emailDao.init(account, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
|
@ -4,13 +4,16 @@ window.name = 'NG_DEFER_BOOTSTRAP!';
|
|||||||
require([
|
require([
|
||||||
'angular',
|
'angular',
|
||||||
'js/controller/login',
|
'js/controller/login',
|
||||||
|
'js/controller/login-initial',
|
||||||
|
'js/controller/login-new-device',
|
||||||
|
'js/controller/login-existing',
|
||||||
'js/controller/mail-list',
|
'js/controller/mail-list',
|
||||||
'js/controller/read',
|
'js/controller/read',
|
||||||
'js/controller/write',
|
'js/controller/write',
|
||||||
'js/controller/navigation',
|
'js/controller/navigation',
|
||||||
'angularRoute',
|
'angularRoute',
|
||||||
'angularTouch'
|
'angularTouch'
|
||||||
], function(angular, LoginCtrl, MailListCtrl, ReadCtrl, WriteCtrl, NavigationCtrl) {
|
], function(angular, LoginCtrl, LoginInitialCtrl, LoginNewDeviceCtrl, LoginExistingCtrl, MailListCtrl, ReadCtrl, WriteCtrl, NavigationCtrl) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var app = angular.module('mail', ['ngRoute', 'ngTouch', 'navigation', 'mail-list', 'write', 'read']);
|
var app = angular.module('mail', ['ngRoute', 'ngTouch', 'navigation', 'mail-list', 'write', 'read']);
|
||||||
@ -18,9 +21,21 @@ require([
|
|||||||
// set router paths
|
// set router paths
|
||||||
app.config(function($routeProvider) {
|
app.config(function($routeProvider) {
|
||||||
$routeProvider.when('/login', {
|
$routeProvider.when('/login', {
|
||||||
templateUrl: 'tpl/login.html',
|
templateUrl: 'tpl/loading.html',
|
||||||
controller: LoginCtrl
|
controller: LoginCtrl
|
||||||
});
|
});
|
||||||
|
$routeProvider.when('/login-existing', {
|
||||||
|
templateUrl: 'tpl/login-existing.html',
|
||||||
|
controller: LoginExistingCtrl
|
||||||
|
});
|
||||||
|
$routeProvider.when('/login-initial', {
|
||||||
|
templateUrl: 'tpl/login-initial.html',
|
||||||
|
controller: LoginInitialCtrl
|
||||||
|
});
|
||||||
|
$routeProvider.when('/login-new-device', {
|
||||||
|
templateUrl: 'tpl/login-new-device.html',
|
||||||
|
controller: LoginNewDeviceCtrl
|
||||||
|
});
|
||||||
$routeProvider.when('/desktop', {
|
$routeProvider.when('/desktop', {
|
||||||
templateUrl: 'tpl/desktop.html',
|
templateUrl: 'tpl/desktop.html',
|
||||||
controller: NavigationCtrl
|
controller: NavigationCtrl
|
||||||
|
53
src/js/controller/login-existing.js
Normal file
53
src/js/controller/login-existing.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var appController = require('js/app-controller');
|
||||||
|
|
||||||
|
var LoginExistingCtrl = function($scope, $location) {
|
||||||
|
|
||||||
|
$scope.confirmPassphrase = function() {
|
||||||
|
var passphrase = $scope.passphrase,
|
||||||
|
emailDao = appController._emailDao;
|
||||||
|
|
||||||
|
if (!passphrase) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlockCrypto(imapLogin);
|
||||||
|
|
||||||
|
function unlockCrypto(callback) {
|
||||||
|
var userId = emailDao._account.emailAddress;
|
||||||
|
emailDao._keychain.getUserKeyPair(userId, function(err, keypair) {
|
||||||
|
if (err) {
|
||||||
|
callback(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emailDao.unlock(keypair, passphrase, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function imapLogin(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// login to imap backend
|
||||||
|
appController._emailDao.imapLogin(function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onLogin();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function onLogin() {
|
||||||
|
$location.path('/desktop');
|
||||||
|
$scope.$apply();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return LoginExistingCtrl;
|
||||||
|
});
|
47
src/js/controller/login-initial.js
Normal file
47
src/js/controller/login-initial.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
define(function(require) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var appController = require('js/app-controller');
|
||||||
|
|
||||||
|
var LoginInitialCtrl = function($scope, $location) {
|
||||||
|
|
||||||
|
$scope.confirmPassphrase = function() {
|
||||||
|
var passphrase = $scope.passphrase,
|
||||||
|
confirmation = $scope.confirmation,
|
||||||
|
emailDao = appController._emailDao;
|
||||||
|
|
||||||
|
if (!passphrase || passphrase !== confirmation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlockCrypto(imapLogin);
|
||||||
|
|
||||||
|
function unlockCrypto(callback) {
|
||||||
|
emailDao.unlock({}, passphrase, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function imapLogin(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// login to imap backend
|
||||||
|
appController._emailDao.imapLogin(function(err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onLogin();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function onLogin() {
|
||||||
|
$location.path('/desktop');
|
||||||
|
$scope.$apply();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return LoginInitialCtrl;
|
||||||
|
});
|
13
src/js/controller/login-new-device.js
Normal file
13
src/js/controller/login-new-device.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
define(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var LoginExistingCtrl = function($scope) {
|
||||||
|
|
||||||
|
$scope.confirmPassphrase = function() {
|
||||||
|
window.alert('Not implemented yet!');
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return LoginExistingCtrl;
|
||||||
|
});
|
@ -4,45 +4,53 @@ define(function(require) {
|
|||||||
var appController = require('js/app-controller');
|
var appController = require('js/app-controller');
|
||||||
|
|
||||||
var LoginCtrl = function($scope, $location) {
|
var LoginCtrl = function($scope, $location) {
|
||||||
|
|
||||||
// start the main app controller
|
|
||||||
appController.start(function(err) {
|
appController.start(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.chrome && chrome.identity) {
|
if (!window.chrome || !chrome.identity) {
|
||||||
login('passphrase', onLogin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
onLogin();
|
|
||||||
});
|
|
||||||
|
|
||||||
function login(password, callback) {
|
|
||||||
// get OAuth token from chrome
|
|
||||||
appController.fetchOAuthToken(password, function(err) {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// login to imap backend
|
|
||||||
appController._emailDao.imapLogin(function(err) {
|
|
||||||
if (err) {
|
|
||||||
console.error(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function onLogin() {
|
|
||||||
$location.path('/desktop');
|
$location.path('/desktop');
|
||||||
$scope.$apply();
|
$scope.$apply();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initializeUser();
|
||||||
|
});
|
||||||
|
|
||||||
|
function initializeUser() {
|
||||||
|
// get OAuth token from chrome
|
||||||
|
appController.fetchOAuthToken(function(err, auth) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
appController.init(auth.emailAddress, auth.token, function(err, availableKeys) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
redirect(availableKeys);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function redirect(availableKeys) {
|
||||||
|
// redirect if needed
|
||||||
|
if (!availableKeys.publicKey) {
|
||||||
|
// no public key available, start onboarding process
|
||||||
|
$location.path('/login-initial');
|
||||||
|
} else if (!availableKeys.privateKey) {
|
||||||
|
// no private key, import key
|
||||||
|
$location.path('/login-new-device');
|
||||||
|
} else {
|
||||||
|
// public and private key available, just login
|
||||||
|
$location.path('/login-existing');
|
||||||
|
}
|
||||||
|
$scope.$apply();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ define(function(require) {
|
|||||||
/**
|
/**
|
||||||
* Inits all dependencies
|
* Inits all dependencies
|
||||||
*/
|
*/
|
||||||
EmailDAO.prototype.init = function(account, passphrase, callback) {
|
EmailDAO.prototype.init = function(account, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
self._account = account;
|
self._account = account;
|
||||||
@ -48,19 +48,21 @@ define(function(require) {
|
|||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// init crypto
|
callback(null, storedKeypair);
|
||||||
initCrypto(storedKeypair);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function initCrypto(storedKeypair) {
|
EmailDAO.prototype.unlock = function(keypair, passphrase, callback) {
|
||||||
if (storedKeypair && storedKeypair.privateKey && storedKeypair.publicKey) {
|
var self = this;
|
||||||
|
|
||||||
|
if (keypair && keypair.privateKey && keypair.publicKey) {
|
||||||
// import existing key pair into crypto module
|
// import existing key pair into crypto module
|
||||||
self._crypto.importKeys({
|
self._crypto.importKeys({
|
||||||
passphrase: passphrase,
|
passphrase: passphrase,
|
||||||
privateKeyArmored: storedKeypair.privateKey.encryptedKey,
|
privateKeyArmored: keypair.privateKey.encryptedKey,
|
||||||
publicKeyArmored: storedKeypair.publicKey.publicKey
|
publicKeyArmored: keypair.publicKey.publicKey
|
||||||
}, callback);
|
}, callback);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -103,7 +105,6 @@ define(function(require) {
|
|||||||
self._keychain.putUserKeyPair(newKeypair, callback);
|
self._keychain.putUserKeyPair(newKeypair, callback);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -155,24 +155,22 @@ define(['underscore', 'js/dao/lawnchair-dao'], function(_, jsonDao) {
|
|||||||
|
|
||||||
// persist private key in local storage
|
// persist private key in local storage
|
||||||
self.lookupPrivateKey(keypairId, function(err, savedPrivkey) {
|
self.lookupPrivateKey(keypairId, function(err, savedPrivkey) {
|
||||||
|
var keys = {};
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate fetched key
|
if (savedPubkey && savedPubkey.publicKey) {
|
||||||
if (savedPubkey && savedPubkey.publicKey && savedPrivkey && savedPrivkey.encryptedKey) {
|
keys.publicKey = savedPubkey;
|
||||||
callback(null, {
|
|
||||||
publicKey: savedPubkey,
|
|
||||||
privateKey: savedPrivkey
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// continue without keypair... generate in crypto.js
|
|
||||||
callback();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (savedPrivkey && savedPrivkey.encryptedKey) {
|
||||||
|
keys.privateKey = savedPrivkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, keys);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -250,33 +248,9 @@ define(['underscore', 'js/dao/lawnchair-dao'], function(_, jsonDao) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
KeychainDAO.prototype.lookupPrivateKey = function(id, callback) {
|
KeychainDAO.prototype.lookupPrivateKey = function(id, callback) {
|
||||||
var self = this;
|
|
||||||
|
|
||||||
// lookup in local storage
|
// lookup in local storage
|
||||||
jsonDao.read('privatekey_' + id, function(privkey) {
|
jsonDao.read('privatekey_' + id, function(privkey) {
|
||||||
if (!privkey) {
|
|
||||||
// fetch from cloud storage
|
|
||||||
self._cloudstorage.getPrivateKey(id, function(err, cloudPrivkey) {
|
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cache private key in cache
|
|
||||||
self.saveLocalPrivateKey(cloudPrivkey, function(err) {
|
|
||||||
if (err) {
|
|
||||||
callback(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
callback(null, cloudPrivkey);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
} else {
|
|
||||||
callback(null, privkey);
|
callback(null, privkey);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,3 +23,4 @@
|
|||||||
@import "views/mail-list";
|
@import "views/mail-list";
|
||||||
@import "views/read";
|
@import "views/read";
|
||||||
@import "views/write";
|
@import "views/write";
|
||||||
|
@import "views/login";
|
||||||
|
49
src/sass/views/_login.scss
Normal file
49
src/sass/views/_login.scss
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
.view-login {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #F9F9F9;
|
||||||
|
|
||||||
|
h1, a {
|
||||||
|
color: #fff;
|
||||||
|
text-decoration: none;
|
||||||
|
text-shadow: 0 -1px 1px $color-grey-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
padding: 0 $nav-padding;
|
||||||
|
height: 84px;
|
||||||
|
h1 {
|
||||||
|
font-family: 'Mensch';
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 5em;
|
||||||
|
height: 100px;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
padding-top: 10px;
|
||||||
|
color: #00C6FF;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-family: 'Mensch Thin';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 100px $nav-padding 0 $nav-padding;
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 0!important;
|
||||||
|
outline: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passphrase {}
|
||||||
|
|
||||||
|
.confirm-control {}
|
||||||
|
|
||||||
|
.info-text {
|
||||||
|
text-align:justify;
|
||||||
|
text-justify:inter-word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
src/tpl/loading.html
Normal file
1
src/tpl/loading.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<p>loading...</p>
|
15
src/tpl/login-existing.html
Normal file
15
src/tpl/login-existing.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<div class="view-login">
|
||||||
|
<header>
|
||||||
|
<h1>WHITEOUT<span>.IO</span></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<div class="passphrase">
|
||||||
|
<p><span>Please enter your passphrase: </span><input type="password" ng-model="passphrase" class="passphrase" placeholder="Passphrase" tabindex="1"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="confirm-control">
|
||||||
|
<button ng-click="confirmPassphrase()" class="btn" ng-disabled="!passphrase" tabindex="2">Confirm passphrase</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
23
src/tpl/login-initial.html
Normal file
23
src/tpl/login-initial.html
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<div class="view-login">
|
||||||
|
<header>
|
||||||
|
<h1>WHITEOUT<span>.IO</span></h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<div class="passphrase">
|
||||||
|
<p><span>Please enter your passphrase: </span><input type="password" ng-model="passphrase" class="passphrase" placeholder="Passphrase" tabindex="1"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info-text">
|
||||||
|
<p>Your passphrase protects the secrets that protect your privacy. You are the only person in charge of your privacy, which is a good thing and the way it should be. The passphrase will <b>never</b> be stored by this application. So you might want to write it down and put it into a <b>safe</b> place. You will need this passphrase when you re-open this application. If you lose the passphrase, your communication is irretrievably lost and <b>cannot be restored</b>.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="passphrase">
|
||||||
|
<p><span>Please confirm your passphrase: </span><input type="password" ng-model="confirmation" class="confirmation" placeholder="Confirmation" tabindex="2"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="confirm-control">
|
||||||
|
<button ng-click="confirmPassphrase()" class="btn" ng-disabled="!passphrase || passphrase!==confirmation" tabindex="3">Confirm passphrase</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
1
src/tpl/login-new-device.html
Normal file
1
src/tpl/login-new-device.html
Normal file
@ -0,0 +1 @@
|
|||||||
|
<p>not implemented yet...</p>
|
@ -1 +0,0 @@
|
|||||||
<div class="message">Logging in...</div>
|
|
@ -59,7 +59,7 @@ define(function(require) {
|
|||||||
controller._appConfigStore.listItems.yields(null, []);
|
controller._appConfigStore.listItems.yields(null, []);
|
||||||
controller._appConfigStore.storeList.yields();
|
controller._appConfigStore.storeList.yields();
|
||||||
|
|
||||||
controller.fetchOAuthToken(appControllerTest.passphrase, function(err) {
|
controller.fetchOAuthToken(function(err) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(controller._appConfigStore.listItems.calledOnce).to.be.true;
|
expect(controller._appConfigStore.listItems.calledOnce).to.be.true;
|
||||||
expect(controller._appConfigStore.storeList.calledOnce).to.be.true;
|
expect(controller._appConfigStore.storeList.calledOnce).to.be.true;
|
||||||
@ -72,7 +72,7 @@ define(function(require) {
|
|||||||
it('should work when the email address is cached', function(done) {
|
it('should work when the email address is cached', function(done) {
|
||||||
controller._appConfigStore.listItems.yields(null, ['asdf']);
|
controller._appConfigStore.listItems.yields(null, ['asdf']);
|
||||||
|
|
||||||
controller.fetchOAuthToken(appControllerTest.passphrase, function(err) {
|
controller.fetchOAuthToken(function(err) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
expect(controller._appConfigStore.listItems.calledOnce).to.be.true;
|
expect(controller._appConfigStore.listItems.calledOnce).to.be.true;
|
||||||
expect(window.chrome.identity.getAuthToken.calledOnce).to.be.true;
|
expect(window.chrome.identity.getAuthToken.calledOnce).to.be.true;
|
||||||
|
@ -53,61 +53,129 @@ define(function(require) {
|
|||||||
devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
|
devicestorageStub = sinon.createStubInstance(DeviceStorageDAO);
|
||||||
|
|
||||||
emailDao = new EmailDAO(keychainStub, imapClientStub, smtpClientStub, pgpStub, devicestorageStub);
|
emailDao = new EmailDAO(keychainStub, imapClientStub, smtpClientStub, pgpStub, devicestorageStub);
|
||||||
|
emailDao._account = account;
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {});
|
afterEach(function() {});
|
||||||
|
|
||||||
describe('init', function() {
|
describe('init', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
delete emailDao._account;
|
||||||
|
});
|
||||||
|
|
||||||
it('should fail due to error in getUserKeyPair', function(done) {
|
it('should fail due to error in getUserKeyPair', function(done) {
|
||||||
devicestorageStub.init.yields();
|
devicestorageStub.init.yields();
|
||||||
keychainStub.getUserKeyPair.yields(42);
|
keychainStub.getUserKeyPair.yields(42);
|
||||||
|
|
||||||
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
emailDao.init(account, function(err) {
|
||||||
expect(devicestorageStub.init.calledOnce).to.be.true;
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
expect(err).to.equal(42);
|
expect(err).to.equal(42);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should init with new keygen', function(done) {
|
it('should init', function(done) {
|
||||||
|
var mockKeyPair = {};
|
||||||
|
|
||||||
devicestorageStub.init.yields();
|
devicestorageStub.init.yields();
|
||||||
keychainStub.getUserKeyPair.yields();
|
keychainStub.getUserKeyPair.yields(null, mockKeyPair);
|
||||||
|
|
||||||
|
emailDao.init(account, function(err, keyPair) {
|
||||||
|
expect(err).to.not.exist;
|
||||||
|
|
||||||
|
expect(keyPair === mockKeyPair).to.be.true;
|
||||||
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('unlock', function() {
|
||||||
|
it('should unlock with new key', function(done) {
|
||||||
pgpStub.generateKeys.yields(null, {});
|
pgpStub.generateKeys.yields(null, {});
|
||||||
pgpStub.importKeys.yields();
|
pgpStub.importKeys.yields();
|
||||||
keychainStub.putUserKeyPair.yields();
|
keychainStub.putUserKeyPair.yields();
|
||||||
|
|
||||||
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
emailDao.unlock({}, emaildaoTest.passphrase, function(err) {
|
||||||
expect(devicestorageStub.init.calledOnce).to.be.true;
|
expect(err).to.not.exist;
|
||||||
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
|
||||||
expect(pgpStub.generateKeys.calledOnce).to.be.true;
|
expect(pgpStub.generateKeys.calledOnce).to.be.true;
|
||||||
expect(pgpStub.importKeys.calledOnce).to.be.true;
|
expect(pgpStub.importKeys.calledOnce).to.be.true;
|
||||||
expect(keychainStub.putUserKeyPair.calledOnce).to.be.true;
|
expect(keychainStub.putUserKeyPair.calledOnce).to.be.true;
|
||||||
expect(err).to.not.exist;
|
expect(pgpStub.generateKeys.calledWith({
|
||||||
|
emailAddress: account.emailAddress,
|
||||||
|
keySize: account.asymKeySize,
|
||||||
|
passphrase: emaildaoTest.passphrase
|
||||||
|
})).to.be.true;
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should init with stored keygen', function(done) {
|
it('should unlock with existing key pair', function(done) {
|
||||||
devicestorageStub.init.yields();
|
|
||||||
keychainStub.getUserKeyPair.yields(null, {
|
|
||||||
publicKey: {
|
|
||||||
_id: 'keyId',
|
|
||||||
userId: emaildaoTest.user,
|
|
||||||
publicKey: 'publicKeyArmored'
|
|
||||||
},
|
|
||||||
privateKey: {
|
|
||||||
_id: 'keyId',
|
|
||||||
userId: emaildaoTest.user,
|
|
||||||
encryptedKey: 'privateKeyArmored'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
pgpStub.importKeys.yields();
|
pgpStub.importKeys.yields();
|
||||||
|
|
||||||
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
emailDao.unlock({
|
||||||
expect(devicestorageStub.init.calledOnce).to.be.true;
|
privateKey: {
|
||||||
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
encryptedKey: 'cryptocrypto'
|
||||||
expect(pgpStub.importKeys.calledOnce).to.be.true;
|
},
|
||||||
|
publicKey: {
|
||||||
|
publicKey: 'omgsocrypto'
|
||||||
|
}
|
||||||
|
}, emaildaoTest.passphrase, function(err) {
|
||||||
expect(err).to.not.exist;
|
expect(err).to.not.exist;
|
||||||
|
|
||||||
|
expect(pgpStub.importKeys.calledOnce).to.be.true;
|
||||||
|
expect(pgpStub.importKeys.calledWith({
|
||||||
|
passphrase: emaildaoTest.passphrase,
|
||||||
|
privateKeyArmored: 'cryptocrypto',
|
||||||
|
publicKeyArmored: 'omgsocrypto'
|
||||||
|
})).to.be.true;
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not unlock with error during keygen', function(done) {
|
||||||
|
pgpStub.generateKeys.yields(new Error('fubar'));
|
||||||
|
|
||||||
|
emailDao.unlock({}, emaildaoTest.passphrase, function(err) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
|
||||||
|
expect(pgpStub.generateKeys.calledOnce).to.be.true;
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not unloch with error during key import', function(done) {
|
||||||
|
pgpStub.generateKeys.yields(null, {});
|
||||||
|
pgpStub.importKeys.yields(new Error('fubar'));
|
||||||
|
|
||||||
|
emailDao.unlock({}, emaildaoTest.passphrase, function(err) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
|
||||||
|
expect(pgpStub.generateKeys.calledOnce).to.be.true;
|
||||||
|
expect(pgpStub.importKeys.calledOnce).to.be.true;
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not unlock with error during key store', function(done) {
|
||||||
|
pgpStub.generateKeys.yields(null, {});
|
||||||
|
pgpStub.importKeys.yields();
|
||||||
|
keychainStub.putUserKeyPair.yields(new Error('omgwtf'));
|
||||||
|
|
||||||
|
emailDao.unlock({}, emaildaoTest.passphrase, function(err) {
|
||||||
|
expect(err).to.exist;
|
||||||
|
|
||||||
|
expect(pgpStub.generateKeys.calledOnce).to.be.true;
|
||||||
|
expect(pgpStub.importKeys.calledOnce).to.be.true;
|
||||||
|
expect(keychainStub.putUserKeyPair.calledOnce).to.be.true;
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -141,7 +209,8 @@ define(function(require) {
|
|||||||
pgpStub.importKeys.yields();
|
pgpStub.importKeys.yields();
|
||||||
keychainStub.putUserKeyPair.yields();
|
keychainStub.putUserKeyPair.yields();
|
||||||
|
|
||||||
emailDao.init(account, emaildaoTest.passphrase, function(err) {
|
emailDao.init(account, function(err, keyPair) {
|
||||||
|
emailDao.unlock(keyPair, emaildaoTest.passphrase, function(err) {
|
||||||
expect(devicestorageStub.init.calledOnce).to.be.true;
|
expect(devicestorageStub.init.calledOnce).to.be.true;
|
||||||
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
expect(keychainStub.getUserKeyPair.calledOnce).to.be.true;
|
||||||
expect(pgpStub.generateKeys.calledOnce).to.be.true;
|
expect(pgpStub.generateKeys.calledOnce).to.be.true;
|
||||||
@ -151,6 +220,7 @@ define(function(require) {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
afterEach(function(done) {
|
afterEach(function(done) {
|
||||||
imapClientStub.logout.yields();
|
imapClientStub.logout.yields();
|
||||||
|
Loading…
Reference in New Issue
Block a user