Commit e65c632f authored by Sascha Pfeiffer's avatar Sascha Pfeiffer

added offline cache encryption

Signed-off-by: default avatarSascha Pfeiffer <sascha.pfeiffer@psono.com>
parent cafe6556
......@@ -184,6 +184,7 @@ var build = function(build_path, type) {
"src/common/data/js/controller/modal/ShareEntryCtrl.js",
"src/common/data/js/controller/modal/ShareNewEntryCtrl.js",
"src/common/data/js/controller/modal/ShowRecoverycodeCtrl.js",
"src/common/data/js/controller/modal/UnlockOfflineCacheCtrl.js",
"src/common/data/js/controller/modal/DeleteAccountCtrl.js",
"src/common/data/js/controller/EditEntryBigCtrl.js",
"src/common/data/js/controller/OpenSecretCtrl.js",
......
......@@ -24,7 +24,32 @@
* @param url
*/
var open_tab = function(url) {
window.open(url, '_blank');
return $q(function (resolve) {
var new_window = window.open(url, '_blank');
resolve(new_window);
});
};
/**
* Opens the URL in a new browser tab (from the background page)
*
* @param url
* @param callback_function
*/
var open_tab_bg = function(url, callback_function) {
chrome.tabs.create({
url: url
}, function(tab) {
if (!callback_function) {
return;
}
chrome.tabs.onUpdated.addListener(function listener (tabId, info) {
if (info.status === 'complete' && tabId === tab.id) {
chrome.tabs.onUpdated.removeListener(listener);
callback_function(tab);
}
});
});
};
/**
......@@ -279,9 +304,27 @@
document.removeEventListener('copy', copy);
}
/**
* @ngdoc
* @name psonocli.browserClient#getOfflineCacheEncryptionKey
* @methodOf psonocli.browserClient
*
* @description
* Asks the background page for the offline cache encryption key
*
* @param {function} fnc The callback function
*/
function getOfflineCacheEncryptionKey(fnc) {
chrome.runtime.getBackgroundPage(function (bg) {
fnc(bg.psono_offline_cache_encryption_key)
});
}
return {
get_client_type: get_client_type,
open_tab: open_tab,
open_tab_bg: open_tab_bg,
open_popup: open_popup,
close_opened_popup: close_opened_popup,
get_base_url: get_base_url,
......@@ -296,7 +339,8 @@
get_config:get_config,
close_popup:close_popup,
disable_browser_password_saving:disable_browser_password_saving,
copy_to_clipboard: copy_to_clipboard
copy_to_clipboard: copy_to_clipboard,
getOfflineCacheEncryptionKey: getOfflineCacheEncryptionKey,
};
};
......
......@@ -180,6 +180,7 @@
<script src="js/controller/modal/ShareEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShareNewEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShowRecoverycodeCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/UnlockOfflineCacheCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/DeleteAccountCtrl.js" type="application/javascript"></script>
<script src="js/controller/EditEntryBigCtrl.js" type="application/javascript"></script>
<script src="js/controller/OpenSecretCtrl.js" type="application/javascript"></script>
......
......@@ -107,6 +107,7 @@
<script src="js/controller/modal/ShareEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShareNewEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShowRecoverycodeCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/UnlockOfflineCacheCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/DeleteAccountCtrl.js" type="application/javascript"></script>
<script src="js/controller/EditEntryBigCtrl.js" type="application/javascript"></script>
<script src="js/controller/OpenSecretCtrl.js" type="application/javascript"></script>
......
......@@ -398,6 +398,7 @@
<script src="js/controller/modal/ShareEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShareNewEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShowRecoverycodeCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/UnlockOfflineCacheCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/DeleteAccountCtrl.js" type="application/javascript"></script>
<script src="js/controller/EditEntryBigCtrl.js" type="application/javascript"></script>
<script src="js/controller/OpenSecretCtrl.js" type="application/javascript"></script>
......
......@@ -180,6 +180,7 @@
<script src="js/controller/modal/ShareEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShareNewEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShowRecoverycodeCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/UnlockOfflineCacheCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/DeleteAccountCtrl.js" type="application/javascript"></script>
<script src="js/controller/EditEntryBigCtrl.js" type="application/javascript"></script>
<script src="js/controller/OpenSecretCtrl.js" type="application/javascript"></script>
......
......@@ -477,6 +477,7 @@
<script src="js/controller/modal/ShareEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShareNewEntryCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/ShowRecoverycodeCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/UnlockOfflineCacheCtrl.js" type="application/javascript"></script>
<script src="js/controller/modal/DeleteAccountCtrl.js" type="application/javascript"></script>
<script src="js/controller/EditEntryBigCtrl.js" type="application/javascript"></script>
<script src="js/controller/OpenSecretCtrl.js" type="application/javascript"></script>
......
......@@ -21,10 +21,10 @@
* @description
* Main Controller for the datastore widget
*/
angular.module('psonocli').controller('DatastoreCtrl', ["$rootScope", "$scope", "$uibModal", "$routeParams", "$timeout",
angular.module('psonocli').controller('DatastoreCtrl', ["$q", "$rootScope", "$scope", "$uibModal", "$routeParams", "$timeout",
"manager", "managerDatastorePassword", 'managerDatastore', 'offlineCache',
"itemBlueprint", "managerWidget", "managerSecret", "dropDownMenuWatcher",
function($rootScope, $scope, $uibModal, $routeParams, $timeout,
function($q, $rootScope, $scope, $uibModal, $routeParams, $timeout,
manager, managerDatastorePassword, managerDatastore, offlineCache,
itemBlueprint, managerWidget, managerSecret, dropDownMenuWatcher){
var contextMenusOpen = 0;
......@@ -199,6 +199,7 @@
$rootScope.$on('offline_mode_disabled', function() {
$scope.offline = false;
load_datastore();
});
load_datastore().then(function(){
......@@ -230,18 +231,46 @@
* Loads the datastore
*/
function load_datastore() {
$scope.structure.data = {};
$scope.structure.loaded = false;
return managerDatastorePassword.get_password_datastore()
.then(function(data) {
$scope.structure.data = data;
$scope.structure.loaded = true;
autoupload_edit_item();
managerDatastorePassword.modifyTreeForSearch($scope.tosearchTreeFilter, $scope.structure.data);
});
return $q(function (resolve) {
if (offlineCache.is_active() && offlineCache.is_locked()) {
var modalInstance = $uibModal.open({
templateUrl: 'view/modal-unlock-offline-cache.html',
controller: 'ModalUnlockOfflineCacheCtrl',
backdrop: 'static',
resolve: {
}
});
modalInstance.result.then(function () {
// pass, will be catched later with the on_set_encryption_key event
}, function () {
$rootScope.$broadcast('force_logout', '');
});
offlineCache.on_set_encryption_key(function() {
resolve(load());
modalInstance.close();
})
} else {
resolve(load());
}
function load() {
$scope.structure.data = {};
$scope.structure.loaded = false;
return managerDatastorePassword.get_password_datastore()
.then(function(data) {
$scope.structure.data = data;
$scope.structure.loaded = true;
autoupload_edit_item();
managerDatastorePassword.modifyTreeForSearch($scope.tosearchTreeFilter, $scope.structure.data);
});
}
});
}
/**
......
......@@ -4,6 +4,7 @@
/**
* @ngdoc controller
* @name psonocli.controller:GPGDecryptMessageCtrl
* @requires $rootScope
* @requires $scope
* @requires $routeParams
* @requires $uibModal
......@@ -14,8 +15,10 @@
* @description
* Controller for the Group view
*/
angular.module('psonocli').controller('GPGDecryptMessageCtrl', ["$scope", "$timeout", "$routeParams", "$uibModal", "cryptoLibrary", "managerDatastorePassword", "browserClient",
function ($scope, $timeout, $routeParams, $uibModal, cryptoLibrary, managerDatastorePassword, browserClient) {
angular.module('psonocli').controller('GPGDecryptMessageCtrl', ["$rootScope", "$scope", "$timeout", "$routeParams",
"$uibModal", "cryptoLibrary", "managerDatastorePassword", "browserClient", "offlineCache",
function ($rootScope, $scope, $timeout, $routeParams,
$uibModal, cryptoLibrary, managerDatastorePassword, browserClient, offlineCache) {
$scope.data = {
decrypting: true,
......@@ -27,6 +30,36 @@
activate();
function activate() {
if (!offlineCache.is_active() || !offlineCache.is_locked()) {
read_gpg()
} else {
var modalInstance = $uibModal.open({
templateUrl: 'view/modal-unlock-offline-cache.html',
controller: 'ModalUnlockOfflineCacheCtrl',
backdrop: 'static',
resolve: {
}
});
modalInstance.result.then(function () {
// pass, will be catched later with the on_set_encryption_key event
}, function () {
$rootScope.$broadcast('force_logout', '');
});
offlineCache.on_set_encryption_key(function() {
modalInstance.close();
$timeout(function() {
read_gpg();
}, 500);
});
}
}
function read_gpg() {
browserClient.emit_sec("read-gpg", $routeParams.gpg_message_id, function(data) {
if (data.hasOwnProperty('plaintext')) {
$scope.$evalAsync(function() {
......
......@@ -60,6 +60,35 @@
$scope.offline = false;
});
if (!offlineCache.is_active() || !offlineCache.is_locked()) {
write_pgp()
} else {
var modalInstance = $uibModal.open({
templateUrl: 'view/modal-unlock-offline-cache.html',
controller: 'ModalUnlockOfflineCacheCtrl',
backdrop: 'static',
resolve: {
}
});
modalInstance.result.then(function () {
// pass, will be catched later with the on_set_encryption_key event
}, function () {
$rootScope.$broadcast('force_logout', '');
});
offlineCache.on_set_encryption_key(function() {
modalInstance.close();
$timeout(function() {
write_pgp();
}, 500);
});
}
}
function write_pgp() {
browserClient.emit_sec("write-gpg", $routeParams.gpg_message_id, function(data) {
$scope.$evalAsync(function() {
load_receiver(data.receiver);
......
......@@ -142,6 +142,7 @@
offlineCache.disable();
offlineCache.clear();
$scope.offline = false;
}
/**
......
......@@ -13,8 +13,10 @@
* @requires psonocli.managerDatastoreUser
* @requires psonocli.managerSecret
* @requires psonocli.browserClient
* @requires psonocli.offlineCache
* @requires psonocli.helper
* @requires $window
* @requires $uibModal
* @requires $route
* @requires $routeParams
* @requires $location
......@@ -23,11 +25,11 @@
* Controller for the panel
*/
angular.module('psonocli').controller('PanelCtrl', ['$scope', '$rootScope', '$filter', '$timeout', 'manager',
'managerDatastorePassword', 'managerDatastoreUser', 'managerSecret', 'browserClient',
'helper', '$window', '$route', '$routeParams', '$location',
'managerDatastorePassword', 'managerDatastoreUser', 'managerSecret', 'browserClient', 'offlineCache',
'helper', '$window', '$uibModal', '$route', '$routeParams', '$location',
function ($scope, $rootScope, $filter, $timeout, manager,
managerDatastorePassword, managerDatastoreUser, managerSecret, browserClient,
helper, $window, $route, $routeParams, $location) {
managerDatastorePassword, managerDatastoreUser, managerSecret, browserClient, offlineCache,
helper, $window, $uibModal, $route, $routeParams, $location) {
var password_filter;
......@@ -76,7 +78,29 @@
}
});
managerDatastorePassword.get_password_datastore();
if (offlineCache.is_active() && offlineCache.is_locked()) {
var modalInstance = $uibModal.open({
templateUrl: 'view/modal-unlock-offline-cache.html',
controller: 'ModalUnlockOfflineCacheCtrl',
backdrop: 'static',
resolve: {
}
});
modalInstance.result.then(function () {
// pass, will be catched later with the on_set_encryption_key event
}, function () {
$rootScope.$broadcast('force_logout', '');
});
offlineCache.on_set_encryption_key(function() {
managerDatastorePassword.get_password_datastore();
modalInstance.close();
})
} else {
managerDatastorePassword.get_password_datastore();
}
$scope.$watch('datastore.search', function (value) {
password_filter = helper.get_password_filter(value);
......
......@@ -33,7 +33,7 @@
function activate(){
scope.offline = offlineCache.is_active();
$scope.offline = offlineCache.is_active();
$rootScope.$on('offline_mode_enabled', function() {
scope.offline = true;
});
......
......@@ -14,9 +14,9 @@
* Controller for the "AcceptShare" modal
*/
angular.module('psonocli').controller('ModalGoOfflineCtrl', ['$scope', '$rootScope', '$uibModalInstance', '$uibModal',
'offlineCache', 'managerDatastore', 'managerDatastorePassword', 'managerExport',
'offlineCache', 'managerDatastore', 'managerDatastorePassword', 'managerExport', 'helper',
function ($scope, $rootScope, $uibModalInstance, $uibModal,
offlineCache, managerDatastore, managerDatastorePassword, managerExport) {
offlineCache, managerDatastore, managerDatastorePassword, managerExport, helper) {
$scope.cancel = cancel;
$scope.approve = approve;
......@@ -25,7 +25,9 @@
started_load_all_datastores: false,
open_requests: 0,
closed_requests: 0,
finished_load_all_datastores: false
finished_load_all_datastores: false,
password: '',
password_repeat: ''
};
activate();
......@@ -43,8 +45,17 @@
*
*/
function approve() {
var test_result = helper.is_valid_password($scope.state.password, $scope.state.password_repeat);
if (test_result !== true) {
$scope.state.errors = [
test_result
];
return;
}
$scope.state.started_load_all_datastores = true;
offlineCache.set_encryption_password($scope.state.password);
offlineCache.enable();
managerExport.on('get-secret-started', function(){
......
(function(angular) {
'use strict';
/**
* @ngdoc controller
* @name psonocli.controller:ModalUnlockOfflineCacheCtrl
* @requires $scope
* @requires $uibModalInstance
* @requires psonocli.offlineCache
*
* @description
* Controller for the "delete verification" modal
*/
angular.module('psonocli').controller('ModalUnlockOfflineCacheCtrl', ['$scope', '$uibModalInstance', 'offlineCache',
function ($scope, $uibModalInstance, offlineCache) {
$scope.save = save;
$scope.cancel = cancel;
$scope.password = '';
$scope.errors = [];
/**
* @ngdoc
* @name psonocli.controller:ModalUnlockOfflineCacheCtrl#save
* @methodOf psonocli.controller:ModalUnlockOfflineCacheCtrl
*
* @description
* Triggered once someone clicks the confirm button in the modal
*/
function save() {
if (offlineCache.unlock($scope.password)) {
$uibModalInstance.close();
} else {
$scope.errors = ['Incorrect passphrase'];
}
}
/**
* @ngdoc
* @name psonocli.controller:ModalUnlockOfflineCacheCtrl#cancel
* @methodOf psonocli.controller:ModalUnlockOfflineCacheCtrl
*
* @description
* Triggered once someone clicks the cancel button in the modal
*/
function cancel() {
$uibModalInstance.dismiss('cancel');
}
}]);
}(angular));
......@@ -170,7 +170,7 @@
'view/index-security-report.html'
];
if ( offlineCache.is_active() && next.templateUrl && offline_redirect_urls.indexOf(next.templateUrl.toLowerCase() !== -1) ) {
if ( offlineCache.is_active() && next.templateUrl && offline_redirect_urls.indexOf(next.templateUrl.toLowerCase()) !== -1 ) {
$location.path( "/" )
}
});
......
......@@ -40,7 +40,20 @@
* @param {string} url The url to open
*/
var open_tab = function(url) {
$window.open(url, '_blank');
return $q(function (resolve) {
var new_window = $window.open(url, '_blank');
resolve(new_window);
});
};
/**
* Opens the URL in a new browser tab (from the background page)
*
* @param url
* @param callback_function
*/
var open_tab_bg = function(url, callback_function) {
// pass, websites have no background page
};
/**
......@@ -329,9 +342,25 @@
input.remove();
}
/**
* @ngdoc
* @name psonocli.browserClient#getOfflineCacheEncryptionKey
* @methodOf psonocli.browserClient
*
* @description
* Asks the background page for the offline cache encryption key
*
* @param {function} fnc The callback function
*/
function getOfflineCacheEncryptionKey(fnc) {
//pass, no background page on the website
}
return {
get_client_type: get_client_type,
open_tab: open_tab,
open_tab_bg: open_tab_bg,
open_popup: open_popup,
close_opened_popup: close_opened_popup,
close_popup: close_popup,
......@@ -346,7 +375,8 @@
on: on,
get_config:get_config,
disable_browser_password_saving: disable_browser_password_saving,
copy_to_clipboard: copy_to_clipboard
copy_to_clipboard: copy_to_clipboard,
getOfflineCacheEncryptionKey: getOfflineCacheEncryptionKey
};
};
......
......@@ -489,6 +489,7 @@
sha1: sha1,
sha256: sha256,
sha512: sha512,
password_scrypt: password_scrypt,
generate_authkey: generate_authkey,
generate_secret_key: generate_secret_key,
generate_public_private_keypair: generate_public_private_keypair,
......
......@@ -20,13 +20,14 @@
* @requires psonocli.browserClient
* @requires psonocli.settings
* @requires psonocli.openpgp
* @requires psonocli.offlineCache
*
* @description
* Service that handles the complete background process
*/
var managerBackground = function($q, $timeout, managerBase, managerSecret, storage, managerDatastorePassword,
managerDatastore, managerDatastoreUser, helper, cryptoLibrary, apiClient, device,
browser, chrome, browserClient, settings, openpgp) {
browser, chrome, browserClient, settings, openpgp, offlineCache) {
var last_login_credentials;
var activeTabId;
......@@ -155,7 +156,8 @@
'encrypt-gpg': encrypt_pgp,
'read-gpg': read_gpg,
'write-gpg': write_gpg,
'write-gpg-complete': write_gpg_complete
'write-gpg-complete': write_gpg_complete,
'set-offline-cache-encryption-key': set_offline_cache_encryption_key
};
if (event_functions.hasOwnProperty(request.event)){
......@@ -722,6 +724,24 @@
}
}
/**
* @ngdoc
* @name psonocli.managerBackground#set_offline_cache_encryption_key
* @methodOf psonocli.managerBackground
*
* @description
* Triggered once the user goes into offline mode
*
* @param {object} request The message sent by the calling script.
* @param {object} sender The sender of the message
* @param {function} sendResponse Function to call (at most once) when you have a response.
*/
function set_offline_cache_encryption_key(request, sender, sendResponse) {
var encryption_key = request.data.encryption_key;
offlineCache.set_encryption_key(encryption_key);
}
/**
* @ngdoc
* @name psonocli.managerBackground#login_form_submit
......@@ -828,13 +848,9 @@
}
if (/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(to_open)) {
browser.tabs.create({
url: '/data/open-secret.html#!/secret/' + entry_extra_info[to_open]['type'] + '/' + to_open
});
browserClient.open_tab_bg('/data/open-secret.html#!/secret/' + entry_extra_info[to_open]['type'] + '/' + to_open);
} else {
browser.tabs.create({
url: '/data/index.html#!/datastore/search/' + encodeURIComponent(to_open)
});
browserClient.open_tab_bg('/data/index.html#!/datastore/search/' + encodeURIComponent(to_open));
}
}
......@@ -987,6 +1003,6 @@
var app = angular.module('psonocli');
app.factory("managerBackground", ['$q', '$timeout', 'managerBase', 'managerSecret', 'storage', 'managerDatastorePassword','managerDatastore',
'managerDatastoreUser', 'helper', 'cryptoLibrary', 'apiClient', 'device', 'browser', 'chrome',
'browserClient', 'settings', 'openpgp', managerBackground]);
'browserClient', 'settings', 'openpgp', 'offlineCache', managerBackground]);
}(angular));
......@@ -4,18 +4,21 @@
/**
* @ngdoc service
* @name psonocli.managerSecret
* @requires $rootScope
* @requires $uibModal
* @requires psonocli.managerBase
* @requires psonocli.apiClient
* @requires psonocli.cryptoLibrary
* @requires psonocli.itemBlueprint
* @requires psonocli.browserClient
* @requires psonocli.offlineCache
*
* @description
* Service to handle all secret related tasks
*/
var managerSecret = function(managerBase, apiClient, cryptoLibrary,
itemBlueprint, browserClient) {
var managerSecret = function($rootScope, $uibModal, managerBase, apiClient, cryptoLibrary,
itemBlueprint, browserClient, offlineCache) {
/**
* @ngdoc
......@@ -133,24 +136,52 @@
* @param {uuid} secret_id The id of the secret to read
*/
var redirect_secret = function(type, secret_id) {
var secret_key = managerBase.find_key_nolimit('datastore-password-leafs', secret_id);
var onError = function(result) {
// pass
};
function redirect() {
var secret_key = managerBase.find_key_nolimit('datastore-password-leafs', secret_id);
var onSuccess = function(decrypted_secret) {
var onError = function(result) {
// pass
};
var msg = itemBlueprint.blueprint_msg_before_open_secret(type, decrypted_secret);
if (typeof(msg) !== 'undefined') {
browserClient.emit_sec(msg.key, msg.content);
}
var onSuccess = function(decrypted_secret) {
itemBlueprint.blueprint_on_open_secret(type, decrypted_secret);
};
var msg = itemBlueprint.blueprint_msg_before_open_secret(type, decrypted_secret);
if (typeof(msg) !== 'undefined') {
browserClient.emit_sec(msg.key, msg.content);
}
read_secret(secret_id, secret_key)
.then(onSuccess, onError);
itemBlueprint.blueprint_on_open_secret(type, decrypted_secret);
};
read_secret(secret_id, secret_key)
.then(onSuccess, onError);
}
if (!offlineCache.is_active() || !offlineCache.is_locked()) {
redirect()
} else {
var modalInstance = $uibModal.open({
templateUrl: 'view/modal-unlock-offline-cache.html',