From 776ffe6ea18b2f4e1673d4953cbefe58142c1dc5 Mon Sep 17 00:00:00 2001 From: binsky Date: Sun, 23 Apr 2023 18:31:50 +0200 Subject: [PATCH] implement re-encryption of the acl shared_key when changing vault password --- appinfo/routes.php | 2 ++ controller/sharecontroller.php | 28 ++++++++++++++++++++++++++++ js/app/controllers/credential.js | 3 +-- js/app/controllers/settings.js | 17 ++++++++++------- js/app/services/credentialservice.js | 2 +- js/app/services/vaultservice.js | 24 ++++++++++++++++++++++++ lib/Service/ShareService.php | 11 +++++++++++ 7 files changed, 77 insertions(+), 10 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index d72ada96..f3d3db75 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -58,6 +58,7 @@ return [ ['name' => 'share#getPendingRequests', 'url' => '/api/v2/sharing/pending', 'verb' => 'GET'], ['name' => 'share#deleteShareRequest', 'url' => '/api/v2/sharing/decline/{share_request_id}', 'verb' => 'DELETE'], ['name' => 'share#getVaultItems', 'url' => '/api/v2/sharing/vault/{vault_guid}/get', 'verb' => 'GET'], + ['name' => 'share#getVaultAclEntries', 'url' => '/api/v2/sharing/vault/{vault_guid}/acl', 'verb' => 'GET'], ['name' => 'share#createPublicShare', 'url' => '/api/v2/sharing/public', 'verb' => 'POST'], ['name' => 'share#getPublicCredentialData', 'url' => '/api/v2/sharing/credential/{credential_guid}/public', 'verb' => 'GET'], ['name' => 'share#unshareCredential', 'url' => '/api/v2/sharing/credential/{item_guid}', 'verb' => 'DELETE'], @@ -67,6 +68,7 @@ return [ ['name' => 'share#uploadFile', 'url' => '/api/v2/sharing/credential/{item_guid}/file', 'verb' => 'POST'], ['name' => 'share#getFile', 'url' => '/api/v2/sharing/credential/{item_guid}/file/{file_guid}', 'verb' => 'GET'], ['name' => 'share#updateSharedCredentialACL', 'url' => '/api/v2/sharing/credential/{item_guid}/acl', 'verb' => 'PATCH'], + ['name' => 'share#updateSharedCredentialACLSharedKey', 'url' => '/api/v2/sharing/credential/{item_guid}/acl/shared_key', 'verb' => 'PATCH'], ['name' => 'internal#getAppVersion', 'url' => '/api/v2/version', 'verb' => 'GET'], //Settings diff --git a/controller/sharecontroller.php b/controller/sharecontroller.php index 2e686cba..a8a97401 100644 --- a/controller/sharecontroller.php +++ b/controller/sharecontroller.php @@ -368,6 +368,20 @@ class ShareController extends ApiController { } } + /** + * Obtains the list of acl entries for credentials shared with this vault + * + * @NoAdminRequired + * @NoCSRFRequired + */ + public function getVaultAclEntries($vault_guid) { + try { + return new JSONResponse($this->shareService->getVaultAclList($this->userId->getUID(), $vault_guid)); + } catch (\Exception $ex) { + return new NotFoundResponse(); + } + } + /** * @param $share_request_id * @return JSONResponse @@ -557,4 +571,18 @@ class ShareController extends ApiController { } } + + /** + * @param $item_guid + * @param $shared_key + * @return JSONResponse + * @NoAdminRequired + * @NoCSRFRequired + */ + public function updateSharedCredentialACLSharedKey($item_guid, $shared_key) { + /** @var SharingACL $acl */ + $acl = $this->shareService->getACL($this->userId->getUID(), $item_guid); + $acl->setSharedKey($shared_key); + return new JSONResponse($this->shareService->updateCredentialACL($acl)->jsonSerialize()); + } } diff --git a/js/app/controllers/credential.js b/js/app/controllers/credential.js index 401dc6cd..a358081d 100644 --- a/js/app/controllers/credential.js +++ b/js/app/controllers/credential.js @@ -78,13 +78,12 @@ } _credential.tags_raw = _credential.tags; } catch (e) { - NotificationService.showNotification($translate.instant('error.decrypt'), 5000); + console.error(e); //$rootScope.$broadcast('logout'); //SettingsService.setSetting('defaultVaultPass', null); //.setSetting('defaultVault', null); //$location.path('/') - } _credentials[i] = _credential; } diff --git a/js/app/controllers/settings.js b/js/app/controllers/settings.js index 514866c4..66eddbf9 100644 --- a/js/app/controllers/settings.js +++ b/js/app/controllers/settings.js @@ -250,8 +250,10 @@ vault.private_sharing_key = EncryptService.decryptString(angular.copy(vault.private_sharing_key), oldVaultPass); vault.private_sharing_key = EncryptService.encryptString(vault.private_sharing_key, newVaultPass); VaultService.updateSharingKeys(vault).then(function () { - $rootScope.$broadcast('logout'); - NotificationService.showNotification($translate.instant('login.new.pass'), 5000); + VaultService.reEncryptACLSharingKeys(vault, oldVaultPass, newVaultPass, EncryptService).then(function () { + $rootScope.$broadcast('logout'); + NotificationService.showNotification($translate.instant('login.new.pass'), 5000); + }); }); } }; @@ -259,11 +261,12 @@ if (_selected_credentials[index].shared_key) { // only re-encrypt the shared key, if the credential is shared and not encrypted with the vault key like default credentials CredentialService.getCredential(_selected_credentials[index].guid).then((function (credential) { - let decrypted_shared_key = EncryptService.decryptString(angular.copy(credential.shared_key), oldVaultPass); - credential.set_share_key = true; - credential.skip_revision = true; - credential.shared_key = EncryptService.encryptString(decrypted_shared_key, newVaultPass); - CredentialService.updateCredential(credential, true).then(next_credential_callback); + const decrypted_shared_key = EncryptService.decryptString(angular.copy(credential.shared_key), oldVaultPass); + let _credential = angular.copy(credential); + _credential.set_share_key = true; + _credential.skip_revision = true; + _credential.shared_key = EncryptService.encryptString(decrypted_shared_key, newVaultPass); + CredentialService.updateCredential(_credential, true).then(next_credential_callback); })); } else { CredentialService.reencryptCredential(_selected_credentials[index].guid, oldVaultPass, newVaultPass).progress(function (data) { diff --git a/js/app/services/credentialservice.js b/js/app/services/credentialservice.js index ed4c85bd..9fc20a6b 100644 --- a/js/app/services/credentialservice.js +++ b/js/app/services/credentialservice.js @@ -141,13 +141,13 @@ } } catch (e) { console.error('Error decrypting credential:', credential); + console.error('Error decrypting credential field:', field); throw e; } try { credential[field] = JSON.parse(field_decrypted_value); } catch (e) { console.warn('Field' + field + ' in ' + credential.label + ' could not be parsed! Value:' + fieldValue); - } } diff --git a/js/app/services/vaultservice.js b/js/app/services/vaultservice.js index 188f7c06..da3eb992 100644 --- a/js/app/services/vaultservice.js +++ b/js/app/services/vaultservice.js @@ -122,6 +122,30 @@ } }); }, + reEncryptACLSharingKeys: function (vault, oldVaultPass, newVaultPass, EncryptService) { + const queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/vault/' + vault.guid + '/acl'); + return $http.get(queryUrl).then(function (response) { + if (response.data) { + const updateACLSharingKey = function (index) { + let acl = response.data[index]; + const decrypted_shared_key = EncryptService.decryptString(angular.copy(acl.shared_key), oldVaultPass); + acl.shared_key = EncryptService.encryptString(decrypted_shared_key, newVaultPass); + + const patchUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + acl.item_guid + '/acl/shared_key'); + $http.patch(patchUrl, { + shared_key: acl.shared_key + }).then(function () { + if (index < response.data.length - 1) { + return updateACLSharingKey(index + 1); + } + }); + }; + if (response.data[0]) { + return updateACLSharingKey(0); + } + } + }); + }, deleteVault: function (vault, file_ids) { var queryUrl = OC.generateUrl('apps/passman/api/v2/vaults/' + vault.guid); var deleteFilesUrl = OC.generateUrl('apps/passman/api/v2/files/delete'); diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php index 20a79e44..1827674c 100644 --- a/lib/Service/ShareService.php +++ b/lib/Service/ShareService.php @@ -273,6 +273,17 @@ class ShareService { return $this->sharingACL->getCredentialAclList($item_guid); } + /** + * Get the access control list by vault guid + * + * @param string $user_id + * @param string $vault_guid + * @return Entity[] + */ + public function getVaultAclList(string $user_id, string $vault_guid) { + return $this->sharingACL->getVaultEntries($user_id, $vault_guid); + } + /** * @param string $item_guid * @return Entity[]