[AC-1623] Introduce Clone option to individual vault for organization items (#8608)

* [AC-1623] Remove cloneableOrganizationCiphers property
and update canClone to reflect new clone permission logic

* [AC-1623] Remove allowOwnershipAssignment override in orgVault as the same restrictions apply to both vaults

* [AC-1623] Ensure ownershipOptions are restricted for non-admins when cloning an org cipher item
This commit is contained in:
Shane Melton 2024-05-01 08:40:12 -07:00 committed by GitHub
parent 8ae71fabaf
commit 89df0e4fad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 31 additions and 23 deletions

View File

@ -32,7 +32,6 @@ export class VaultItemsComponent {
@Input() showCollections: boolean;
@Input() showGroups: boolean;
@Input() useEvents: boolean;
@Input() cloneableOrganizationCiphers: boolean;
@Input() showPremiumFeatures: boolean;
@Input() showBulkMove: boolean;
@Input() showBulkTrashOptions: boolean;
@ -160,10 +159,27 @@ export class VaultItemsComponent {
}
protected canClone(vaultItem: VaultItem) {
return (
(vaultItem.cipher.organizationId && this.cloneableOrganizationCiphers) ||
vaultItem.cipher.organizationId == null
);
if (vaultItem.cipher.organizationId == null) {
return true;
}
const org = this.allOrganizations.find((o) => o.id === vaultItem.cipher.organizationId);
// Admins and custom users can always clone in the Org Vault
if (this.viewingOrgVault && (org.isAdmin || org.permissions.editAnyCollection)) {
return true;
}
// Check if the cipher belongs to a collection with canManage permission
const orgCollections = this.allCollections.filter((c) => c.organizationId === org.id);
for (const collection of orgCollections) {
if (vaultItem.cipher.collectionIds.includes(collection.id) && collection.manage) {
return true;
}
}
return false;
}
private refreshItems() {

View File

@ -47,7 +47,6 @@
[showBulkMove]="showBulkMove"
[showBulkTrashOptions]="filter.type === 'trash'"
[useEvents]="false"
[cloneableOrganizationCiphers]="false"
[showAdminActions]="false"
(onEvent)="onVaultItemsEvent($event)"
[flexibleCollectionsV1Enabled]="flexibleCollectionsV1Enabled$ | async"

View File

@ -81,22 +81,6 @@ export class AddEditComponent extends BaseAddEditComponent {
);
}
protected allowOwnershipAssignment() {
if (
this.ownershipOptions != null &&
(this.ownershipOptions.length > 1 || !this.allowPersonal)
) {
if (this.organization != null) {
return (
this.cloneMode && this.organization.canEditAllCiphers(this.flexibleCollectionsV1Enabled)
);
} else {
return !this.editMode || this.cloneMode;
}
}
return false;
}
protected loadCollections() {
if (!this.organization.canEditAllCiphers(this.flexibleCollectionsV1Enabled)) {
return super.loadCollections();

View File

@ -48,7 +48,6 @@
[showBulkMove]="false"
[showBulkTrashOptions]="filter.type === 'trash'"
[useEvents]="organization?.useEvents"
[cloneableOrganizationCiphers]="true"
[showAdminActions]="true"
(onEvent)="onVaultItemsEvent($event)"
[showBulkEditCollectionAccess]="organization?.flexibleCollections"

View File

@ -289,6 +289,16 @@ export class AddEditComponent implements OnInit, OnDestroy {
});
}
}
// Only Admins can clone a cipher to different owner
if (this.cloneMode && this.cipher.organizationId != null) {
const cipherOrg = (await firstValueFrom(this.organizationService.memberOrganizations$)).find(
(o) => o.id === this.cipher.organizationId,
);
if (cipherOrg != null && !cipherOrg.isAdmin && !cipherOrg.permissions.editAnyCollection) {
this.ownershipOptions = [{ name: cipherOrg.name, value: cipherOrg.id }];
}
}
// We don't want to copy passkeys when we clone a cipher
if (this.cloneMode && this.cipher?.login?.hasFido2Credentials) {