/** * Nextcloud - passman * * @copyright Copyright (c) 2016, Sander Brand (brantje@gmail.com) * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel (wolfi@wolfi.es) * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ (function () { 'use strict'; /** * @ngdoc function * @name passmanApp.controller:MainCtrl * @description * # MainCtrl * Controller of the passmanApp */ angular.module('passmanApp') .controller('CredentialCtrl', ['$scope', 'VaultService', 'SettingsService', '$location', 'CredentialService', '$rootScope', 'FileService', 'EncryptService', 'TagService', '$timeout', 'NotificationService', 'CacheService', 'ShareService', 'SharingACL', '$interval', '$filter', '$routeParams', '$sce', '$translate', function ($scope, VaultService, SettingsService, $location, CredentialService, $rootScope, FileService, EncryptService, TagService, $timeout, NotificationService, CacheService, ShareService, SharingACL, $interval, $filter, $routeParams, $sce, $translate) { $scope.active_vault = VaultService.getActiveVault(); if (!SettingsService.getSetting('defaultVault') || !SettingsService.getSetting('defaultVaultPass')) { if (!$scope.active_vault) { $location.path('/'); } } else { if (SettingsService.getSetting('defaultVault') && SettingsService.getSetting('defaultVaultPass')) { var _vault = angular.copy(SettingsService.getSetting('defaultVault')); _vault.vaultKey = angular.copy(SettingsService.getSetting('defaultVaultPass')); VaultService.setActiveVault(_vault); $scope.active_vault = _vault; //@TODO check if vault exists } } $scope.show_spinner = true; var fetchCredentials = function () { VaultService.getVault({guid: $routeParams.vault_id}).then(function (vault) { var vaultKey = angular.copy($scope.active_vault.vaultKey); var _credentials = angular.copy(vault.credentials); vault.credentials = []; $scope.active_vault = vault; $scope.active_vault.vaultKey = vaultKey; if(!$rootScope.vaultCache){ $rootScope.vaultCache = []; } VaultService.setActiveVault($scope.active_vault); for (var i = 0; i < _credentials.length; i++) { var _credential = _credentials[i]; try { if (!_credential.shared_key) { _credential = CredentialService.decryptCredential(angular.copy(_credential)); } else { var enc_key = EncryptService.decryptString(_credential.shared_key); _credential = ShareService.decryptSharedCredential(angular.copy(_credential), enc_key); } _credential.tags_raw = _credential.tags; } catch (e) { NotificationService.showNotification($translate.instant('error.decrypt'), 5000); //$rootScope.$broadcast('logout'); //SettingsService.setSetting('defaultVaultPass', null); //.setSetting('defaultVault', null); //$location.path('/') } _credentials[i] = _credential; } ShareService.getCredendialsSharedWithUs(vault.guid).then(function (shared_credentials) { for (var c = 0; c < shared_credentials.length; c++) { var _shared_credential = shared_credentials[c]; var decrypted_key = EncryptService.decryptString(_shared_credential.shared_key); var _shared_credential_data; try { _shared_credential_data = ShareService.decryptSharedCredential(_shared_credential.credential_data, decrypted_key); } catch (e) { } if (_shared_credential_data) { delete _shared_credential.credential_data; _shared_credential_data.acl = _shared_credential; _shared_credential_data.acl.permissions = new SharingACL(_shared_credential_data.acl.permissions); _shared_credential_data.tags_raw = _shared_credential_data.tags; _credentials.push(_shared_credential_data); } } angular.merge($scope.active_vault.credentials, _credentials); $scope.show_spinner = false; $rootScope.$broadcast('credentials_loaded'); $rootScope.vaultCache[$scope.active_vault.guid] = angular.copy($scope.active_vault); if(!vault.private_sharing_key){ var key_size = 1024; ShareService.generateRSAKeys(key_size).then(function (kp) { var pem = ShareService.rsaKeyPairToPEM(kp); $scope.creating_keys = false; $scope.active_vault.private_sharing_key = pem.privateKey; $scope.active_vault.public_sharing_key = pem.publicKey; $scope.$digest(); VaultService.updateSharingKeys($scope.active_vault); }); } $scope.checkURLAction(); }); }); }; var getPendingShareRequests = function () { ShareService.getPendingRequests().then(function (shareRequests) { if (shareRequests.length > 0) { $scope.incoming_share_requests = shareRequests; jQuery('.share_popup').dialog({ width: 800, modal: true, dialogClass: 'shareincoming-dialog' }); } }); }; var refresh_data_interval = null; if ($scope.active_vault) { $scope.$parent.selectedVault = true; if($rootScope.vaultCache && $rootScope.vaultCache[$scope.active_vault.guid]){ $scope.active_vault = $rootScope.vaultCache[$scope.active_vault.guid]; $rootScope.$broadcast('credentials_loaded'); $scope.show_spinner = false; } else { fetchCredentials(); } getPendingShareRequests(); refresh_data_interval = $interval(function () { fetchCredentials(); getPendingShareRequests(); }, 60000 * 5); } $scope.$on('$destroy', function () { $interval.cancel(refresh_data_interval); }); $scope.permissions = new SharingACL(0); $scope.hasPermission = function (acl, permission) { if (acl) { var tmp = new SharingACL(acl.permission); return tmp.hasPermission(permission); } else { return true; } }; $scope.acceptShareRequest = function (share_request) { var crypted_shared_key = share_request.shared_key; var private_key = EncryptService.decryptString(VaultService.getActiveVault().private_sharing_key); private_key = ShareService.rsaPrivateKeyFromPEM(private_key); /** global: forge */ crypted_shared_key = private_key.decrypt(forge.util.decode64(crypted_shared_key)); crypted_shared_key = EncryptService.encryptString(crypted_shared_key); ShareService.saveSharingRequest(share_request, crypted_shared_key).then(function () { var idx = $scope.incoming_share_requests.indexOf(share_request); $scope.incoming_share_requests.splice(idx, 1); var active_share_requests = false; for (var v = 0; v < $scope.incoming_share_requests.length; v++) { if ($scope.incoming_share_requests[v].target_vault_id === $scope.active_vault.vault_id) { active_share_requests = true; } } if (active_share_requests === false) { jQuery('.ui-dialog').remove(); fetchCredentials(); } }); }; $scope.declineShareRequest = function (share_request) { ShareService.declineSharingRequest(share_request).then(function () { var idx = $scope.incoming_share_requests.indexOf(share_request); $scope.incoming_share_requests.splice(idx, 1); var active_share_requests = false; for (var v = 0; v < $scope.incoming_share_requests.length; v++) { if ($scope.incoming_share_requests[v].target_vault_id === $scope.active_vault.vault_id) { active_share_requests = true; } } if (active_share_requests === false) { jQuery('.ui-dialog').remove(); fetchCredentials(); } }); }; var settingsLoaded = function () { $scope.settings = SettingsService.getSettings(); }; if(!SettingsService.getSetting('settings_loaded')){ $rootScope.$on('settings_loaded', function () { settingsLoaded(); }); } else { settingsLoaded(); } $scope.addCredential = function () { var new_credential = CredentialService.newCredential(); new_credential.icon = null; var enc_c = CredentialService.encryptCredential(new_credential); SettingsService.setSetting('edit_credential', enc_c); $location.path('/vault/' + $scope.active_vault.guid + '/new'); }; $scope.editCredential = function (credential) { var _credential = angular.copy(credential); $rootScope.$emit('app_menu', false); SettingsService.setSetting('edit_credential', CredentialService.encryptCredential(_credential)); $location.path('/vault/' + $scope.active_vault.guid + '/edit/' + _credential.guid); }; $scope.getRevisions = function (credential) { var _credential = angular.copy(credential); $rootScope.$emit('app_menu', false); SettingsService.setSetting('revision_credential', CredentialService.encryptCredential(_credential)); $location.path('/vault/' + $scope.active_vault.guid + '/' + _credential.guid + '/revisions'); }; $scope.shareCredential = function (credential) { var _credential = angular.copy(credential); $rootScope.$emit('app_menu', false); SettingsService.setSetting('share_credential', CredentialService.encryptCredential(_credential)); $location.path('/vault/' + $scope.active_vault.guid + '/' + _credential.guid + '/share'); }; var notification; $scope.deleteCredential = function (credential) { var _credential = angular.copy(credential); try { _credential = CredentialService.decryptCredential(_credential); } catch (e) { } _credential.delete_time = new Date().getTime() / 1000; for (var i = 0; i < $scope.active_vault.credentials.length; i++) { if ($scope.active_vault.credentials[i].credential_id === credential.credential_id) { $scope.active_vault.credentials[i].delete_time = _credential.delete_time; } } $scope.closeSelected(); if (notification) { NotificationService.hideNotification(notification); } var key = CredentialService.getSharedKeyFromCredential(_credential); CredentialService.updateCredential(_credential, false, key).then(function () { notification = NotificationService.showNotification($translate.instant('credential.deleted'), 5000); }); }; $scope.recoverCredential = function (credential) { var _credential = angular.copy(credential); try { _credential = CredentialService.decryptCredential(_credential); } catch (e) { } for (var i = 0; i < $scope.active_vault.credentials.length; i++) { if ($scope.active_vault.credentials[i].credential_id === credential.credential_id) { $scope.active_vault.credentials[i].delete_time = 0; } } _credential.delete_time = 0; $scope.closeSelected(); if (notification) { NotificationService.hideNotification(notification); } var key = CredentialService.getSharedKeyFromCredential(_credential); CredentialService.updateCredential(_credential, false, key).then(function () { NotificationService.showNotification($translate.instant('credential.recovered'), 5000); }); }; $scope.destroyCredential = function (credential) { var _credential = angular.copy(credential); CredentialService.destroyCredential(_credential.guid).then(function () { for (var i = 0; i < $scope.active_vault.credentials.length; i++) { if ($scope.active_vault.credentials[i].credential_id === credential.credential_id) { $scope.active_vault.credentials.splice(i, 1); NotificationService.showNotification($translate.instant('credential.destroyed'), 5000); break; } } }); }; $scope.view_mode = 'list'; //@TODO make this a setting $scope.switchViewMode = function (viewMode) { $scope.view_mode = viewMode; }; $rootScope.$on('push_decrypted_credential_to_list', function () { $rootScope.$broadcast('credentials_loaded'); }); $scope.filterOptions = { filterText: '', fields: ['label', 'username', 'email', 'custom_fields'] }; //searchboxfix $scope.$on('nc_searchbox', function(event, searchterm, fields) { $scope.filterOptions.filterText=searchterm; if(fields){ $scope.filterOptions.fields=fields; } }); $scope.filtered_credentials = []; $scope.$watch('[selectedtags, filterOptions, delete_time, active_vault.credentials]', function () { if (!$scope.active_vault) { return; } if ($scope.active_vault.credentials) { var credentials = angular.copy($scope.active_vault.credentials); var filtered_credentials = $filter('credentialSearch')(credentials, $scope.filterOptions); filtered_credentials = $filter('tagFilter')(filtered_credentials, $scope.selectedtags); filtered_credentials = $filter('filter')(filtered_credentials, {hidden: 0}); $scope.filtered_credentials = filtered_credentials; $scope.filterOptions.selectedtags = angular.copy($scope.selectedtags); for (var i = 0; i < $scope.active_vault.credentials.length; i++) { var _credential = $scope.active_vault.credentials[i]; if (_credential.tags) { TagService.addTags(_credential.tags); } } } }, true); $scope.no_credentials_label=[]; $scope.no_credentials_label.all=true; $scope.no_credentials_label.s_good=false; $scope.no_credentials_label.s_medium=false; $scope.no_credentials_label.s_low=false; $scope.no_credentials_label.expired=false; $scope.disableAllLabels = function(){ $scope.no_credentials_label.all=false; $scope.no_credentials_label.s_good=false; $scope.no_credentials_label.s_medium=false; $scope.no_credentials_label.s_low=false; $scope.no_credentials_label.expired=false; }; //watch for special tags $scope.$on('filterSpecial', function(event, args) { $scope.disableAllLabels(); switch (args) { case "strength_good": $scope.filterStrength(3,1000); $scope.no_credentials_label.s_good=true; break; case "strength_medium": $scope.filterStrength(2,3); $scope.no_credentials_label.s_medium=true; break; case "strength_low": $scope.filterStrength(0,1); $scope.no_credentials_label.s_low=true; break; case "expired": $scope.filterExpired(); $scope.no_credentials_label.expired=true; break; case "all": $scope.filterAll(); $scope.no_credentials_label.all=true; break; } }); $scope.getListSizes = function(){ var l = $scope.filtered_credentials; var deleted=0; for (var i = 0; i < l.length; i++) { if(l[i].delete_time>0){ deleted++; } } var result=[]; result.listsize=l.length; result.listsize_wout_deleted=l.length-deleted; result.listsize_deleted=deleted; return result; }; $scope.filterAll = function(){ $scope.selectedtags=[]; $scope.filterOptions.filterText=""; var creds_filtered=[]; for (var i = 0; i < $scope.active_vault.credentials.length; i++) { if($scope.active_vault.credentials[i].delete_time===0){ creds_filtered.push($scope.active_vault.credentials[i]); } } $scope.filtered_credentials=$scope.filterHidden(creds_filtered); }; $scope.filterStrength = function(strength_min, strength_max){ var initialCredentials=$scope.active_vault.credentials; var postFiltered=[]; for (var i = 0; i < initialCredentials.length; i++) { var _credential = initialCredentials[i]; var zxcvbn_result = zxcvbn(_credential.password); if(zxcvbn_result.score>=strength_min && zxcvbn_result.score<=strength_max){ postFiltered.push(initialCredentials[i]); } } $scope.filtered_credentials=$scope.filterHidden(postFiltered); }; $scope.filterExpired = function(){ var initialCredentials=$scope.active_vault.credentials; var now = Date.now(); var postFiltered=[]; for (var i = 0; i < initialCredentials.length; i++) { var _credential = initialCredentials[i]; if(_credential.expire_time!==0 && _credential.expire_time <= now){ postFiltered.push(initialCredentials[i]); } } $scope.filtered_credentials=$scope.filterHidden(postFiltered); }; $scope.filterHidden = function(list){ var list_without_hidden=[]; for (var i = 0; i < list.length; i++) { if(list[i].hidden!==1){ list_without_hidden.push(list[i]); } } return list_without_hidden; }; $scope.selectedtags = []; var to; $rootScope.$on('selected_tags_updated', function (evt, _sTags) { var _selectedTags = []; for (var x = 0; x < _sTags.length; x++) { _selectedTags.push(_sTags[x].text); } $scope.selectedtags = _selectedTags; $timeout.cancel(to); if (_selectedTags.length > 0) { to = $timeout(function () { if ($scope.filtered_credentials) { var _filtered_tags = []; for (var i = 0; i < $scope.filtered_credentials.length; i++) { var tags = $scope.filtered_credentials[i].tags_raw; for (var x = 0; x < tags.length; x++) { var tag = tags[x].text; if (_filtered_tags.indexOf(tag) === -1) { _filtered_tags.push(tag); } } } $rootScope.$emit('limit_tags_in_list', _filtered_tags); } }, 50); } }); $scope.delete_time = 0; $scope.showCredentialRow = function (credential) { if ($scope.delete_time === 0) { return credential.delete_time === 0; } else { return credential.delete_time > $scope.delete_time; } }; $rootScope.$on('set_delete_time', function (event, time) { $scope.delete_time = time; }); $scope.setDeleteTime = function (delete_time) { $scope.delete_time = delete_time; }; $scope.selectedCredential = false; $scope.selectCredential = function (credential) { if (credential.description) { credential.description_html = $sce.trustAsHtml(angular.copy(credential.description).replace("\n", '
')); } $scope.selectedCredential = angular.copy(credential); $rootScope.$emit('app_menu', true); }; $scope.closeSelected = function () { $rootScope.$emit('app_menu', false); $scope.selectedCredential = false; }; $rootScope.$on('logout', function () { if ($scope.active_vault) { $rootScope.vaultCache[$scope.active_vault.guid] = null; } $scope.active_vault = null; $scope.credentials = []; VaultService.clearVaultService(); }); $scope.$watch(function(){ return $location.search(); }, function(params){ $scope.checkURLAction(); }); $scope.checkURLAction = function () { var search = $location.search(); if (search.show !== undefined && $scope.active_vault.credentials !== undefined && $scope.active_vault.credentials.length > 0) { $scope.closeSelected(); $scope.active_vault.credentials.forEach(function(credential, index, myArray) { if (credential.guid === search.show) { $scope.selectCredential(credential); return true; } }); } }; $scope.clearState = function () { $scope.delete_time = 0; }; }]); }());