mirror of
https://github.com/nextcloud/passman.git
synced 2025-11-09 13:44:40 +08:00
Merge branch 'master' into fix-docx-file-handling
This commit is contained in:
commit
c28afd1b0b
13 changed files with 401 additions and 172 deletions
|
|
@ -58,14 +58,17 @@ 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'],
|
||||
['name' => 'share#unshareCredentialFromUser', 'url' => '/api/v2/sharing/credential/{item_guid}/{user_id}', 'verb' => 'DELETE'],
|
||||
['name' => 'share#getRevisions', 'url' => '/api/v2/sharing/credential/{item_guid}/revisions', 'verb' => 'GET'],
|
||||
['name' => 'share#getItemAcl', 'url' => '/api/v2/sharing/credential/{item_guid}/acl', 'verb' => 'GET'],
|
||||
['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
|
||||
|
|
|
|||
|
|
@ -93,6 +93,10 @@ class FileController extends ApiController {
|
|||
return new JSONResponse(array('ok' => empty($failed_file_ids), 'failed' => $failed_file_ids));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
*/
|
||||
public function updateFile($file_id, $file_data, $filename) {
|
||||
try {
|
||||
$file = $this->fileService->getFile($file_id, $this->userId);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -476,13 +490,55 @@ class ShareController extends ApiController {
|
|||
} catch (\Exception $e) {
|
||||
return new NotFoundJSONResponse();
|
||||
}
|
||||
|
||||
// $this->userId does not exist for anonymous share link downloads
|
||||
$userId = ($this->userId) ? $this->userId->getUID() : null;
|
||||
$acl = $this->shareService->getACL($userId, $credential->getGuid());
|
||||
if (!$acl->hasPermission(SharingACL::FILES)) {
|
||||
return new NotFoundJSONResponse();
|
||||
} else {
|
||||
return $this->fileService->getFileByGuid($file_guid);
|
||||
|
||||
if ($acl->hasPermission(SharingACL::FILES)) {
|
||||
// get file by guid and check if it is owned by the owner of the shared credential
|
||||
return $this->fileService->getFileByGuid($file_guid, $credential->getUserId());
|
||||
}
|
||||
|
||||
return new NotFoundJSONResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $item_guid
|
||||
* @param $data
|
||||
* @param $filename
|
||||
* @param $mimetype
|
||||
* @param $size
|
||||
* @return DataResponse|NotFoundJSONResponse|JSONResponse
|
||||
* @throws \Exception
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
*/
|
||||
public function uploadFile($item_guid, $data, $filename, $mimetype, $size) {
|
||||
try {
|
||||
$credential = $this->credentialService->getCredentialByGUID($item_guid);
|
||||
} catch (\Exception $e) {
|
||||
return new NotFoundJSONResponse();
|
||||
}
|
||||
|
||||
// only check acl, if the uploading user is not the credential owner
|
||||
if ($credential->getUserId() != $this->userId->getUID()) {
|
||||
$acl = $this->shareService->getACL($this->userId->getUID(), $credential->getGuid());
|
||||
if (!$acl->hasPermission(SharingACL::FILES)) {
|
||||
return new DataResponse(['msg' => 'Not authorized'], Http::STATUS_UNAUTHORIZED);
|
||||
}
|
||||
}
|
||||
|
||||
$file = array(
|
||||
'filename' => $filename,
|
||||
'size' => $size,
|
||||
'mimetype' => $mimetype,
|
||||
'file_data' => $data,
|
||||
'user_id' => $credential->getUserId()
|
||||
);
|
||||
|
||||
// save the file with the id of the user that owns the credential
|
||||
return new JSONResponse($this->fileService->createFile($file, $credential->getUserId()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -515,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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ class TranslationController extends ApiController {
|
|||
'credential.recovered' => $this->trans->t('Credential recovered'),
|
||||
'credential.destroyed' => $this->trans->t('Credential destroyed'),
|
||||
'error.loading.file.perm' => $this->trans->t('Error downloading file, you probably have insufficient permissions'),
|
||||
'error.general' => $this->trans->t('An error occurred'),
|
||||
|
||||
// js/app/controllers/edit_credential.js
|
||||
'invalid.qr' => $this->trans->t('Invalid QR code'),
|
||||
|
|
|
|||
|
|
@ -72,20 +72,18 @@
|
|||
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);
|
||||
console.error(e);
|
||||
//$rootScope.$broadcast('logout');
|
||||
//SettingsService.setSetting('defaultVaultPass', null);
|
||||
//.setSetting('defaultVault', null);
|
||||
//$location.path('/')
|
||||
|
||||
}
|
||||
_credentials[i] = _credential;
|
||||
}
|
||||
|
|
@ -181,10 +179,10 @@
|
|||
|
||||
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);
|
||||
const decrypted_shared_key = private_key.decrypt(forge.util.decode64(crypted_shared_key));
|
||||
const vault_key_encrypted_shared_key = EncryptService.encryptString(decrypted_shared_key);
|
||||
|
||||
ShareService.saveSharingRequest(share_request, crypted_shared_key).then(function () {
|
||||
ShareService.saveSharingRequest(share_request, vault_key_encrypted_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;
|
||||
|
|
@ -261,54 +259,62 @@
|
|||
};
|
||||
|
||||
var notification;
|
||||
$scope.deleteCredential = function (credential) {
|
||||
var _credential = angular.copy(credential);
|
||||
try {
|
||||
_credential = CredentialService.decryptCredential(_credential);
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
$scope.deleteCredential = function (decrypted_credential) {
|
||||
let _credential = angular.copy(decrypted_credential);
|
||||
_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.closeSelected();
|
||||
if (notification) {
|
||||
NotificationService.hideNotification(notification);
|
||||
}
|
||||
|
||||
const key = CredentialService.getSharedKeyFromCredential(_credential);
|
||||
CredentialService.updateCredential(_credential, false, key).then(function (response) {
|
||||
decrypted_credential.delete_time = _credential.delete_time;
|
||||
for (let 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);
|
||||
}, function (error) {
|
||||
if (error.data.msg) {
|
||||
NotificationService.showNotification(error.data.msg, 5000);
|
||||
} else {
|
||||
NotificationService.showNotification($translate.instant('error.general'), 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;
|
||||
}
|
||||
}
|
||||
$scope.recoverCredential = function (decrypted_credential) {
|
||||
let _credential = angular.copy(decrypted_credential);
|
||||
_credential.delete_time = 0;
|
||||
|
||||
$scope.closeSelected();
|
||||
if (notification) {
|
||||
NotificationService.hideNotification(notification);
|
||||
}
|
||||
var key = CredentialService.getSharedKeyFromCredential(_credential);
|
||||
CredentialService.updateCredential(_credential, false, key).then(function () {
|
||||
|
||||
const key = CredentialService.getSharedKeyFromCredential(_credential);
|
||||
CredentialService.updateCredential(_credential, false, key).then(function (response) {
|
||||
decrypted_credential.delete_time = 0;
|
||||
for (let 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;
|
||||
}
|
||||
}
|
||||
NotificationService.showNotification($translate.instant('credential.recovered'), 5000);
|
||||
}, function (error) {
|
||||
if (error.data.msg) {
|
||||
NotificationService.showNotification(error.data.msg, 5000);
|
||||
} else {
|
||||
NotificationService.showNotification($translate.instant('error.general'), 5000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.destroyCredential = function (credential) {
|
||||
var _credential = angular.copy(credential);
|
||||
const _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) {
|
||||
|
|
@ -317,6 +323,12 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
}, function (error) {
|
||||
if (error.data.msg) {
|
||||
NotificationService.showNotification(error.data.msg, 5000);
|
||||
} else {
|
||||
NotificationService.showNotification($translate.instant('error.general'), 5000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -161,26 +161,22 @@
|
|||
$scope.selected_field_type = 'text';
|
||||
_field.secret = (_field.field_type === 'password');
|
||||
if(_field.field_type === 'file'){
|
||||
var key = false;
|
||||
var _file = $scope.new_custom_field.value;
|
||||
if (!$scope.storedCredential.hasOwnProperty('acl') && $scope.storedCredential.hasOwnProperty('shared_key')) {
|
||||
const key = CredentialService.getSharedKeyFromCredential($scope.storedCredential);
|
||||
const file = $scope.new_custom_field.value;
|
||||
|
||||
if ($scope.storedCredential.shared_key) {
|
||||
key = EncryptService.decryptString(angular.copy($scope.storedCredential.shared_key));
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.storedCredential.hasOwnProperty('acl')) {
|
||||
key = EncryptService.decryptString(angular.copy($scope.storedCredential.acl.shared_key));
|
||||
}
|
||||
|
||||
FileService.uploadFile(_file, key).then(function (result) {
|
||||
const callback = function (result) {
|
||||
delete result.file_data;
|
||||
result.filename = EncryptService.decryptString(result.filename, key);
|
||||
_field.value = result;
|
||||
$scope.storedCredential.custom_fields.push(_field);
|
||||
$scope.new_custom_field = angular.copy(_customField);
|
||||
});
|
||||
};
|
||||
|
||||
if (key) {
|
||||
ShareService.uploadSharedFile($scope.storedCredential, file, key).then(callback);
|
||||
} else {
|
||||
FileService.uploadFile(file).then(callback);
|
||||
}
|
||||
} else {
|
||||
$scope.storedCredential.custom_fields.push(_field);
|
||||
$scope.new_custom_field = angular.copy(_customField);
|
||||
|
|
@ -229,11 +225,17 @@
|
|||
data: file.data
|
||||
};
|
||||
|
||||
FileService.uploadFile(_file, key).then(function (result) {
|
||||
const callback = function (result) {
|
||||
delete result.file_data;
|
||||
result.filename = EncryptService.decryptString(result.filename, key);
|
||||
$scope.storedCredential.files.push(result);
|
||||
});
|
||||
};
|
||||
|
||||
if (key) {
|
||||
ShareService.uploadSharedFile($scope.storedCredential, _file, key).then(callback);
|
||||
} else {
|
||||
FileService.uploadFile(_file).then(callback);
|
||||
}
|
||||
|
||||
$scope.$digest();
|
||||
};
|
||||
|
|
@ -329,31 +331,17 @@
|
|||
|
||||
$scope.updateExistingListWithCredential(new_cred);
|
||||
});
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
var key, _credential;
|
||||
if (!$scope.storedCredential.hasOwnProperty('acl') && $scope.storedCredential.hasOwnProperty('shared_key')) {
|
||||
|
||||
if ($scope.storedCredential.shared_key) {
|
||||
key = EncryptService.decryptString(angular.copy($scope.storedCredential.shared_key));
|
||||
}
|
||||
}
|
||||
|
||||
if ($scope.storedCredential.hasOwnProperty('acl')) {
|
||||
key = EncryptService.decryptString(angular.copy($scope.storedCredential.acl.shared_key));
|
||||
}
|
||||
let _credential = angular.copy($scope.storedCredential);
|
||||
const key = CredentialService.getSharedKeyFromCredential($scope.storedCredential);
|
||||
|
||||
if (key) {
|
||||
_credential = ShareService.encryptSharedCredential($scope.storedCredential, key);
|
||||
} else {
|
||||
_credential = angular.copy($scope.storedCredential);
|
||||
}
|
||||
|
||||
delete _credential.shared_key;
|
||||
var _useKey = (key != null);
|
||||
var regex = /(<([^>]+)>)/ig;
|
||||
const _useKey = (key != null);
|
||||
const regex = /(<([^>]+)>)/ig;
|
||||
if(_credential.description && _credential.description !== "") {
|
||||
_credential.description = _credential.description.replace(regex, "");
|
||||
}
|
||||
|
|
@ -373,17 +361,17 @@
|
|||
if (!credential.shared_key) {
|
||||
credential = CredentialService.decryptCredential(credential);
|
||||
} else {
|
||||
var enc_key = EncryptService.decryptString(credential.shared_key);
|
||||
const enc_key = CredentialService.getSharedKeyFromCredential($scope.storedCredential);
|
||||
credential = ShareService.decryptSharedCredential(credential, enc_key);
|
||||
}
|
||||
credential.tags_raw = credential.tags;
|
||||
|
||||
var found=false;
|
||||
var credList=$rootScope.vaultCache[$scope.active_vault.guid].credentials;
|
||||
for (var i = 0; i < credList.length; i++) {
|
||||
let found = false;
|
||||
let credList = $rootScope.vaultCache[$scope.active_vault.guid].credentials;
|
||||
for (let i = 0; i < credList.length; i++) {
|
||||
if (credList[i].credential_id === credential.credential_id) {
|
||||
$rootScope.vaultCache[$scope.active_vault.guid].credentials[i]=credential;
|
||||
found=true;
|
||||
$rootScope.vaultCache[$scope.active_vault.guid].credentials[i] = credential;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -391,7 +379,6 @@
|
|||
$rootScope.vaultCache[$scope.active_vault.guid].credentials.push(credential);
|
||||
}
|
||||
$rootScope.$broadcast('push_decrypted_credential_to_list', credential);
|
||||
|
||||
} catch (e) {
|
||||
NotificationService.showNotification($translate.instant('error.decrypt'), 5000);
|
||||
console.log(e);
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@
|
|||
}
|
||||
});
|
||||
|
||||
var key_strengths = [
|
||||
const key_strengths = [
|
||||
'password.poor',
|
||||
'password.poor',
|
||||
'password.weak',
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
$scope.required_score = {'strength': translation};
|
||||
});
|
||||
|
||||
var btn_txt = $translate.instant('bookmarklet.text');
|
||||
const btn_txt = $translate.instant('bookmarklet.text');
|
||||
var http = location.protocol, slashes = http.concat("//"),
|
||||
host = slashes.concat(window.location.hostname + ":" + window.location.port),
|
||||
complete = host + location.pathname;
|
||||
|
|
@ -94,7 +94,7 @@
|
|||
|
||||
|
||||
$scope.saveVaultSettings = function () {
|
||||
var _vault = $scope.active_vault;
|
||||
let _vault = $scope.active_vault;
|
||||
_vault.name = $scope.new_vault_name;
|
||||
_vault.vault_settings = angular.copy($scope.vault_settings);
|
||||
VaultService.updateVault(_vault).then(function () {
|
||||
|
|
@ -236,19 +236,9 @@
|
|||
done: 0,
|
||||
total: _selected_credentials.length
|
||||
};
|
||||
var changeCredential = function (index, oldVaultPass, newVaultPass) {
|
||||
var usedKey = oldVaultPass;
|
||||
|
||||
if (_selected_credentials[index].hasOwnProperty('shared_key')) {
|
||||
if (_selected_credentials[index].shared_key) {
|
||||
usedKey = EncryptService.decryptString(angular.copy(_selected_credentials[index].shared_key), oldVaultPass);
|
||||
}
|
||||
}
|
||||
|
||||
CredentialService.reencryptCredential(_selected_credentials[index].guid, usedKey, newVaultPass).progress(function (data) {
|
||||
$scope.cur_state = data;
|
||||
}).then(function () {
|
||||
var percent = index / _selected_credentials.length * 100;
|
||||
const changeCredential = function (index, oldVaultPass, newVaultPass) {
|
||||
const next_credential_callback = function () {
|
||||
const percent = index / _selected_credentials.length * 100;
|
||||
$scope.change_pw = {
|
||||
percent: percent,
|
||||
done: index + 1,
|
||||
|
|
@ -260,14 +250,31 @@
|
|||
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 () {
|
||||
VaultService.reEncryptACLSharingKeys(vault, oldVaultPass, newVaultPass, EncryptService).then(function () {
|
||||
$rootScope.$broadcast('logout');
|
||||
NotificationService.showNotification($translate.instant('login.new.pass'), 5000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
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) {
|
||||
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) {
|
||||
$scope.cur_state = data;
|
||||
}).then(next_credential_callback);
|
||||
}
|
||||
};
|
||||
changeCredential(0, VaultService.getActiveVault().vaultKey, newVaultPass);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -276,19 +283,24 @@
|
|||
$scope.delete_vault = function () {
|
||||
if ($scope.confirm_vault_delete && $scope.delete_vault_password === VaultService.getActiveVault().vaultKey) {
|
||||
getCurrentVaultCredentials(function (vault) {
|
||||
var credentials = vault.credentials;
|
||||
const credentials = vault.credentials;
|
||||
$scope.remove_pw = {
|
||||
percent: 0,
|
||||
done: 0,
|
||||
total: vault.credentials.length,
|
||||
};
|
||||
|
||||
var file_ids = [];
|
||||
const file_ids = [];
|
||||
for (const credential of credentials) {
|
||||
var decryptedFiles = JSON.parse(EncryptService.decryptString(angular.copy(credential.files), VaultService.getActiveVault().vaultKey));
|
||||
try {
|
||||
const enc_key = CredentialService.getSharedKeyFromCredential(credential);
|
||||
const decryptedFiles = JSON.parse(EncryptService.decryptString(angular.copy(credential.files), enc_key));
|
||||
for (const file of decryptedFiles) {
|
||||
file_ids.push(file.file_id);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
VaultService.deleteVault(vault, file_ids).then(function () {
|
||||
|
|
|
|||
|
|
@ -355,17 +355,20 @@
|
|||
$scope.sharing_complete = true;
|
||||
} else {
|
||||
|
||||
ShareService.generateSharedKey(20).then(function (key) {
|
||||
ShareService.generateSharedKey(20).then(function (generated_shared_key) {
|
||||
|
||||
// copy complete credential to encryptedSharedCredential where it can be safely re-encrypted
|
||||
var encryptedSharedCredential = angular.copy($scope.storedCredential);
|
||||
var old_key = VaultService.getActiveVault().vaultKey;
|
||||
var vault_key = VaultService.getActiveVault().vaultKey;
|
||||
|
||||
CredentialService.reencryptCredential(encryptedSharedCredential.guid, old_key, key).progress(function () {
|
||||
}).then(function (data) {
|
||||
CredentialService
|
||||
.reencryptCredential(encryptedSharedCredential.guid, vault_key, generated_shared_key)
|
||||
.progress(function () {})
|
||||
.then(function (data) {
|
||||
var _credential = data.cryptogram;
|
||||
_credential.set_share_key = true;
|
||||
_credential.skip_revision = true;
|
||||
_credential.shared_key = EncryptService.encryptString(key);
|
||||
_credential.shared_key = EncryptService.encryptString(generated_shared_key);
|
||||
CredentialService.updateCredential(_credential, true).then(function () {
|
||||
$scope.storedCredential.shared_key = _credential.shared_key;
|
||||
NotificationService.showNotification($translate.instant('credential.shared'), 4000);
|
||||
|
|
@ -376,7 +379,7 @@
|
|||
var list = $scope.share_settings.credentialSharedWithUserAndGroup;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i].type === "user") {
|
||||
$scope.applyShareToUser(list[i], key);
|
||||
$scope.applyShareToUser(list[i], generated_shared_key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -390,7 +393,7 @@
|
|||
expire_views: $scope.share_settings.linkSharing.settings.expire_views
|
||||
};
|
||||
ShareService.createPublicSharedCredential(shareObj).then(function () {
|
||||
var hash = window.btoa($scope.storedCredential.guid + '<::>' + key);
|
||||
var hash = window.btoa($scope.storedCredential.guid + '<::>' + generated_shared_key);
|
||||
$scope.share_link = getShareLink(hash);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,17 +85,13 @@
|
|||
return _encryptedFields;
|
||||
},
|
||||
updateCredential: function (credential, skipEncryption, key) {
|
||||
var _credential = angular.copy(credential);
|
||||
let _credential = angular.copy(credential);
|
||||
if (!skipEncryption) {
|
||||
for (var i = 0; i < _encryptedFields.length; i++) {
|
||||
var field = _encryptedFields[i];
|
||||
var fieldValue = angular.copy(credential[field]);
|
||||
_credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue), key);
|
||||
}
|
||||
_credential = this.encryptCredential(credential, key);
|
||||
}
|
||||
_credential.expire_time = new Date(angular.copy(credential.expire_time)).getTime() / 1000;
|
||||
|
||||
var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + credential.guid);
|
||||
const queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + credential.guid);
|
||||
return $http.patch(queryUrl, _credential).then(function (response) {
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
|
|
@ -145,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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -215,23 +211,39 @@
|
|||
var promise_credential_update = function () {
|
||||
service.getCredential(credential_guid).then((function (credential) {
|
||||
this.parent.plain_credential = service.decryptCredential(credential, this.parent.old_password);
|
||||
var tmp = angular.copy(this.parent.plain_credential);
|
||||
var plain_credential = angular.copy(this.parent.plain_credential);
|
||||
|
||||
if (tmp.hasOwnProperty('shared_key') && tmp.shared_key !== null && tmp.shared_key !== '' && !skipSharingKey) {
|
||||
var shared_key = EncryptService.decryptString(angular.copy(tmp.shared_key)).trim();
|
||||
tmp.shared_key = EncryptService.encryptString(angular.copy(shared_key), this.parent.new_password);
|
||||
tmp.set_share_key = true;
|
||||
tmp.skip_revision = true;
|
||||
this.parent.new_password = shared_key;
|
||||
if (
|
||||
plain_credential.hasOwnProperty('shared_key') &&
|
||||
plain_credential.shared_key !== null &&
|
||||
plain_credential.shared_key !== '' &&
|
||||
!skipSharingKey
|
||||
) {
|
||||
// re-encrypt the credential.shared_key with the new password
|
||||
// (e.g. re-encrypt from vault_key to generated_shared_key)
|
||||
const decrypted_credential_shared_key = EncryptService.decryptString(angular.copy(plain_credential.shared_key)).trim();
|
||||
plain_credential.shared_key = EncryptService.encryptString(
|
||||
angular.copy(decrypted_credential_shared_key),
|
||||
this.parent.new_password
|
||||
);
|
||||
plain_credential.set_share_key = true;
|
||||
plain_credential.skip_revision = true;
|
||||
|
||||
// todo: temporary comment out this Brantje code line as is looks pointless to set the
|
||||
// new encryption key to the decrypted_credential_shared_key
|
||||
// this.parent.new_password = decrypted_credential_shared_key;
|
||||
}
|
||||
|
||||
this.parent.new_credential_cryptogram = service.encryptCredential(tmp, this.parent.new_password);
|
||||
// before: re-encryption with the now out-commented decrypted_credential_shared_key if the credential has one
|
||||
// now: re-encryption with the original parent.new_password (e.g. generated_shared_key)
|
||||
this.parent.new_credential_cryptogram = service.encryptCredential(plain_credential, this.parent.new_password);
|
||||
this.call_progress(new progress_datatype(1, 2, 'credential'));
|
||||
|
||||
// Save data
|
||||
this.parent.new_credential_cryptogram.skip_revision = true;
|
||||
service.updateCredential(this.parent.new_credential_cryptogram, true).then((function () {
|
||||
this.call_progress(new progress_datatype(2, 2, 'credential'));
|
||||
// transfer plain and encrypted credential to the next promise in the complete re-encryption task
|
||||
this.call_then({
|
||||
plain_text: this.parent.plain_credential,
|
||||
cryptogram: this.parent.new_credential_cryptogram
|
||||
|
|
@ -241,38 +253,99 @@
|
|||
};
|
||||
|
||||
var promise_files_update = function () {
|
||||
// Add the double of the files so we take encryption phase and upload to the server into the math
|
||||
this.total = this.parent.plain_credential.files.length * 2; // Binded on credential finish upload
|
||||
if (this.parent.plain_credential.files.length === 0) {
|
||||
this.call_progress(new progress_datatype(0, 0, 'files'));
|
||||
this.call_then("No files to update");
|
||||
return;
|
||||
}
|
||||
|
||||
this.total = this.parent.plain_credential.files.length;
|
||||
this.current = 0;
|
||||
|
||||
for (var i = 0; i < this.parent.plain_credential.files.length; i++) {
|
||||
var _file = this.parent.plain_credential.files[i];
|
||||
const files_workload = function () {
|
||||
const check_next_callback = function () {
|
||||
this.current++;
|
||||
this.call_progress(new progress_datatype(this.current, this.total, 'files'));
|
||||
|
||||
if (this.current === this.total) {
|
||||
this.call_then('All files has been updated');
|
||||
} else {
|
||||
setTimeout(files_workload.bind(this), 1);
|
||||
}
|
||||
};
|
||||
|
||||
const _file = this.parent.plain_credential.files[this.current];
|
||||
/* jshint ignore:start */
|
||||
FileService.getFile(_file).then((function (fileData) {
|
||||
try {
|
||||
//Decrypt with old key
|
||||
fileData.filename = EncryptService.decryptString(fileData.filename, this.parent.old_password);
|
||||
fileData.file_data = EncryptService.decryptString(fileData.file_data, this.parent.old_password);
|
||||
|
||||
this.current++;
|
||||
|
||||
this.call_progress(new progress_datatype(this.current, this.total, 'files'));
|
||||
|
||||
FileService.updateFile(fileData, this.parent.new_password).then((function () {
|
||||
this.current++;
|
||||
this.call_progress(new progress_datatype(this.current, this.total, 'files'));
|
||||
if (this.current === this.total) {
|
||||
this.call_then('All files has been updated');
|
||||
}
|
||||
check_next_callback.bind(this)();
|
||||
}).bind(this));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
console.error('Failed to re-encrypt file. It seems to be corrupt.', _file);
|
||||
check_next_callback.bind(this)();
|
||||
}
|
||||
}).bind(this));
|
||||
/* jshint ignore:end */
|
||||
};
|
||||
setTimeout(files_workload.bind(this), 1);
|
||||
};
|
||||
|
||||
var promise_custom_field_files_update = function () {
|
||||
if (this.parent.plain_credential.custom_fields.length === 0) {
|
||||
this.call_progress(new progress_datatype(0, 0, 'custom_field_files'));
|
||||
this.call_then("No custom field files to update");
|
||||
return;
|
||||
}
|
||||
if (this.parent.plain_credential.files.length === 0) {
|
||||
this.call_progress(new progress_datatype(0, 0, 'files'));
|
||||
this.call_then("No files to update");
|
||||
|
||||
this.total = this.parent.plain_credential.custom_fields.length;
|
||||
console.log("total custom_field_files_update = " + this.total);
|
||||
this.current = 0;
|
||||
|
||||
const custom_field_workload = function () {
|
||||
const check_next_callback = function () {
|
||||
this.current++;
|
||||
this.call_progress(new progress_datatype(this.current, this.total, 'custom_field_files'));
|
||||
|
||||
if (this.current === this.total) {
|
||||
this.call_then('All custom field files has been updated');
|
||||
} else {
|
||||
setTimeout(custom_field_workload.bind(this), 1);
|
||||
}
|
||||
};
|
||||
|
||||
if (this.parent.plain_credential.custom_fields[this.current].field_type !== 'file') {
|
||||
check_next_callback.bind(this)();
|
||||
return;
|
||||
}
|
||||
|
||||
const _file = this.parent.plain_credential.custom_fields[this.current].value;
|
||||
/* jshint ignore:start */
|
||||
FileService.getFile(_file).then((function (fileData) {
|
||||
try {
|
||||
//Decrypt with old key
|
||||
fileData.filename = EncryptService.decryptString(fileData.filename, this.parent.old_password);
|
||||
fileData.file_data = EncryptService.decryptString(fileData.file_data, this.parent.old_password);
|
||||
|
||||
FileService.updateFile(fileData, this.parent.new_password).then((function () {
|
||||
check_next_callback.bind(this)();
|
||||
}).bind(this));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
console.error('Failed to re-encrypt custom field file. It seems to be corrupt.', _file);
|
||||
check_next_callback.bind(this)();
|
||||
}
|
||||
}).bind(this));
|
||||
/* jshint ignore:end */
|
||||
};
|
||||
setTimeout(custom_field_workload.bind(this), 1);
|
||||
};
|
||||
|
||||
var promise_revisions_update = function () {
|
||||
service.getRevisions(this.parent.plain_credential.guid).then((function (revisions) {
|
||||
// Double, so we include the actual upload of the data back to the server
|
||||
|
|
@ -287,12 +360,13 @@
|
|||
this.call_then("No history to update");
|
||||
return;
|
||||
}
|
||||
var _revision = revisions[this.current];
|
||||
//Decrypt!
|
||||
_revision.credential_data = service.decryptCredential(_revision.credential_data, this.parent.old_password);
|
||||
_revision.credential_data = service.encryptCredential(_revision.credential_data, this.parent.new_password);
|
||||
this.current++;
|
||||
|
||||
var _revision = revisions[this.current];
|
||||
|
||||
const decrypted_revision_credential_data = service.decryptCredential(_revision.credential_data, this.parent.old_password);
|
||||
_revision.credential_data = service.encryptCredential(decrypted_revision_credential_data, this.parent.new_password);
|
||||
|
||||
this.current++;
|
||||
this.call_progress(new progress_datatype(this.current + this.upload, this.total, 'revisions'));
|
||||
|
||||
service.updateRevision(_revision).then((function () {
|
||||
|
|
@ -344,6 +418,18 @@
|
|||
}
|
||||
});
|
||||
|
||||
master_promise.promises++;
|
||||
/** global: C_Promise */
|
||||
(new C_Promise(promise_custom_field_files_update, new password_data())).progress(function (data) {
|
||||
master_promise.call_progress(data);
|
||||
}).then(function () {
|
||||
console.warn("End custom field files update");
|
||||
master_promise.promises--;
|
||||
if (master_promise.promises === 0) {
|
||||
master_promise.call_then(master_promise.credential_data);
|
||||
}
|
||||
});
|
||||
|
||||
master_promise.promises++;
|
||||
/** global: C_Promise */
|
||||
(new C_Promise(promise_revisions_update, new password_data())).progress(function (data) {
|
||||
|
|
|
|||
|
|
@ -160,13 +160,27 @@
|
|||
});
|
||||
},
|
||||
downloadSharedFile: function (credential, file) {
|
||||
var queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/file/' + file.guid);
|
||||
const queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/file/' + file.guid);
|
||||
return $http.get(queryUrl).then(function (response) {
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
}
|
||||
});
|
||||
},
|
||||
uploadSharedFile: function (credential, file, key) {
|
||||
const queryUrl = OC.generateUrl('apps/passman/api/v2/sharing/credential/' + credential.guid + '/file');
|
||||
let _file = angular.copy(file);
|
||||
_file.filename = EncryptService.encryptString(_file.filename, key);
|
||||
const data = EncryptService.encryptString(angular.copy(file.data), key);
|
||||
_file.data = data;
|
||||
return $http.post(queryUrl, _file).then(function (response) {
|
||||
if (response.data) {
|
||||
return response.data;
|
||||
} else {
|
||||
return response;
|
||||
}
|
||||
});
|
||||
},
|
||||
encryptSharedCredential: function (credential, sharedKey) {
|
||||
var _credential = angular.copy(credential);
|
||||
_credential.shared_key = EncryptService.encryptString(sharedKey);
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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[]
|
||||
|
|
|
|||
|
|
@ -55,12 +55,13 @@ class Admin implements ISettings {
|
|||
* @return TemplateResponse
|
||||
*/
|
||||
public function getForm(): TemplateResponse {
|
||||
$hasInternetConnection = $this->config->getSystemValue('has_internet_connection', true);
|
||||
$checkVersion = $this->config->getAppValue('passman', 'check_version', '1') === '1';
|
||||
$localVersion = $this->appManager->getAppInfo('passman')["version"];
|
||||
$githubVersion = $this->l->t('Unable to get version info');
|
||||
$githubReleaseUrl = null;
|
||||
|
||||
if ($checkVersion) {
|
||||
if ($checkVersion && $hasInternetConnection) {
|
||||
// get latest GitHub release version
|
||||
|
||||
$url = 'https://api.github.com/repos/nextcloud/passman/releases/latest';
|
||||
|
|
@ -90,6 +91,7 @@ class Admin implements ISettings {
|
|||
'githubVersion' => $githubVersion,
|
||||
'githubReleaseUrl' => $githubReleaseUrl,
|
||||
'checkVersion' => $checkVersion,
|
||||
'hasInternetConnection' => $hasInternetConnection,
|
||||
], 'blank');
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue