From 34547f7bb6d09a7f6fd421f683e801d0b3a07a16 Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Mon, 21 Oct 2013 17:10:45 +0200 Subject: [PATCH 1/3] [WO-52] export encrypted key file --- src/js/app.js | 4 ++- src/js/controller/account.js | 52 +++++++++++++++++++++++++++++++++ src/js/controller/navigation.js | 5 ++++ src/tpl/account.html | 10 +++++++ src/tpl/desktop.html | 6 +++- src/tpl/navigation.html | 2 +- 6 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 src/js/controller/account.js create mode 100644 src/tpl/account.html diff --git a/src/js/app.js b/src/js/app.js index b76a10f..4623896 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -3,6 +3,7 @@ window.name = 'NG_DEFER_BOOTSTRAP!'; require([ 'angular', + 'js/controller/account', 'js/controller/login', 'js/controller/login-initial', 'js/controller/login-new-device', @@ -13,7 +14,7 @@ require([ 'js/controller/navigation', 'angularRoute', 'angularTouch' -], function(angular, LoginCtrl, LoginInitialCtrl, LoginNewDeviceCtrl, LoginExistingCtrl, MailListCtrl, ReadCtrl, WriteCtrl, NavigationCtrl) { +], function(angular, AccountCtrl, LoginCtrl, LoginInitialCtrl, LoginNewDeviceCtrl, LoginExistingCtrl, MailListCtrl, ReadCtrl, WriteCtrl, NavigationCtrl) { 'use strict'; var app = angular.module('mail', ['ngRoute', 'ngTouch', 'navigation', 'mail-list', 'write', 'read']); @@ -49,6 +50,7 @@ require([ app.controller('ReadCtrl', ReadCtrl); app.controller('WriteCtrl', WriteCtrl); app.controller('MailListCtrl', MailListCtrl); + app.controller('AccountCtrl', AccountCtrl); // manually bootstrap angular due to require.js angular.element().ready(function() { diff --git a/src/js/controller/account.js b/src/js/controller/account.js new file mode 100644 index 0000000..d155ad2 --- /dev/null +++ b/src/js/controller/account.js @@ -0,0 +1,52 @@ +define(function(require) { + 'use strict'; + + var appController = require('js/app-controller'), + emailDao; + + // + // Controller + // + + var AccountCtrl = function($scope) { + emailDao = appController._emailDao; + + // + // scope functions + // + + $scope.hideAccountView = function() { + $scope.$parent.$parent.accountOpen = false; + }; + + $scope.exportKeyFile = function() { + var userId = emailDao._account.emailAddress; + emailDao._keychain.getUserKeyPair(userId, function(err, keypair) { + if (err) { + console.error(err); + return; + } + + download(keypair.privateKey.encryptedKey, 'key_' + userId + '.asc', 'text/plain'); + }); + }; + + // + // helper functions + // + + function download(content, filename, contentType) { + contentType = contentType || 'application/octet-stream'; + var a = document.createElement('a'); + var blob = new Blob([content], { + 'type': contentType + }); + a.href = window.URL.createObjectURL(blob); + a.download = filename; + a.click(); + } + + }; + + return AccountCtrl; +}); \ No newline at end of file diff --git a/src/js/controller/navigation.js b/src/js/controller/navigation.js index 71d0e05..c38f91e 100644 --- a/src/js/controller/navigation.js +++ b/src/js/controller/navigation.js @@ -13,6 +13,7 @@ define(function(require) { var NavigationCtrl = function($scope) { $scope.navOpen = false; $scope.writerOpen = false; + $scope.accountOpen = false; emailDao = appController._emailDao; @@ -42,6 +43,10 @@ define(function(require) { $scope.closeNav(); }; + $scope.showAccountView = function() { + $scope.accountOpen = true; + }; + $scope.remove = function(email) { var trashFolder = _.findWhere($scope.folders, { type: 'Trash' diff --git a/src/tpl/account.html b/src/tpl/account.html new file mode 100644 index 0000000..6ed4d88 --- /dev/null +++ b/src/tpl/account.html @@ -0,0 +1,10 @@ + \ No newline at end of file diff --git a/src/tpl/desktop.html b/src/tpl/desktop.html index 02e4a2a..c0292df 100644 --- a/src/tpl/desktop.html +++ b/src/tpl/desktop.html @@ -21,4 +21,8 @@ \ No newline at end of file + + + \ No newline at end of file diff --git a/src/tpl/navigation.html b/src/tpl/navigation.html index 4fc557c..1b7ca5b 100644 --- a/src/tpl/navigation.html +++ b/src/tpl/navigation.html @@ -13,7 +13,7 @@ From 36c8d1e00380f8f42d8feb9c16e8291e413cdcfd Mon Sep 17 00:00:00 2001 From: Felix Hammerl Date: Tue, 22 Oct 2013 14:48:38 +0200 Subject: [PATCH 2/3] [WO-53] import key on new device --- src/js/app.js | 2 +- src/js/controller/account.js | 18 ++++-- src/js/controller/login-new-device.js | 82 +++++++++++++++++++++++++-- src/js/controller/login.js | 2 +- src/js/dao/cloudstorage-dao.js | 3 + src/manifest.json | 4 +- src/tpl/login-new-device.html | 19 ++++++- 7 files changed, 116 insertions(+), 14 deletions(-) diff --git a/src/js/app.js b/src/js/app.js index 4623896..edeb0ec 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -17,7 +17,7 @@ require([ ], function(angular, AccountCtrl, LoginCtrl, LoginInitialCtrl, LoginNewDeviceCtrl, LoginExistingCtrl, MailListCtrl, ReadCtrl, WriteCtrl, NavigationCtrl) { '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', 'login-new-device']); // set router paths app.config(function($routeProvider) { diff --git a/src/js/controller/account.js b/src/js/controller/account.js index d155ad2..ca2d2d3 100644 --- a/src/js/controller/account.js +++ b/src/js/controller/account.js @@ -37,13 +37,19 @@ define(function(require) { function download(content, filename, contentType) { contentType = contentType || 'application/octet-stream'; - var a = document.createElement('a'); - var blob = new Blob([content], { - 'type': contentType + chrome.fileSystem.chooseEntry({ + type: 'saveFile', + suggestedName: filename + }, function(file) { + if (!file) { + return; + } + file.createWriter(function(writer) { + writer.onerror = console.error; + writer.onwriteend = function() {}; + writer.write(new Blob([content], { type: contentType })); + }, console.error); }); - a.href = window.URL.createObjectURL(blob); - a.download = filename; - a.click(); } }; diff --git a/src/js/controller/login-new-device.js b/src/js/controller/login-new-device.js index 783b06c..cb4f6ce 100644 --- a/src/js/controller/login-new-device.js +++ b/src/js/controller/login-new-device.js @@ -1,13 +1,87 @@ -define(function() { +define(function(require) { 'use strict'; - var LoginExistingCtrl = function($scope) { - + var angular = require('angular'), + appController = require('js/app-controller'); + + var LoginExistingCtrl = function($scope, $location) { $scope.confirmPassphrase = function() { - window.alert('Not implemented yet!'); + 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; + } + + keypair.privateKey = { + _id: keypair.publicKey._id, + userId: userId, + encryptedKey: $scope.key + }; + emailDao.unlock(keypair, passphrase, function(err) { + if (err) { + callback(err); + return; + } + + emailDao._keychain.putUserKeyPair(keypair, 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(); + } }; + var ngModule = angular.module('login-new-device', []); + ngModule.directive('fileReader', function() { + return function(scope, elm) { + elm.bind('change', function(e) { + var files = e.target.files, + reader = new FileReader(); + + if (files.length === 0) { + return; + } + + reader.onload = (function(scope) { + return function(e) { + scope.key = e.target.result; + }; + })(scope); + reader.readAsText(files[0]); + }); + }; + }); + return LoginExistingCtrl; }); \ No newline at end of file diff --git a/src/js/controller/login.js b/src/js/controller/login.js index 0e0efb0..9ed17da 100644 --- a/src/js/controller/login.js +++ b/src/js/controller/login.js @@ -40,7 +40,7 @@ define(function(require) { function redirect(availableKeys) { // redirect if needed - if (!availableKeys.publicKey) { + if (typeof availableKeys === 'undefined') { // no public key available, start onboarding process $location.path('/login-initial'); } else if (!availableKeys.privateKey) { diff --git a/src/js/dao/cloudstorage-dao.js b/src/js/dao/cloudstorage-dao.js index a265d31..7ce4ed7 100644 --- a/src/js/dao/cloudstorage-dao.js +++ b/src/js/dao/cloudstorage-dao.js @@ -19,6 +19,9 @@ define(['jquery', 'js/app-config'], function($, app) { url: uri, type: 'GET', dataType: 'json', + headers: { + 'Accept': 'application/json', + }, success: function(res) { callback(null, res); }, diff --git a/src/manifest.json b/src/manifest.json index 0a39aa8..829b3ad 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -7,7 +7,9 @@ "icons": { "128": "img/icon.png" }, - "permissions": [ + "permissions": [{ + "fileSystem": ["write"] + }, "https://keys.whiteout.io/", "identity", { "socket": [ diff --git a/src/tpl/login-new-device.html b/src/tpl/login-new-device.html index 9b5ebcc..292f10c 100644 --- a/src/tpl/login-new-device.html +++ b/src/tpl/login-new-device.html @@ -1 +1,18 @@ -

not implemented yet...

+