1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-06 02:23:44 +00:00

[PM-11162] Assign To Collections Permission Update (#11367)

Only users with Manage/Edit permissions will be allowed to Assign To Collections. If the user has Can Edit Except Password the collections dropdown will be disabled.
---------

Co-authored-by: Matt Bishop <mbishop@bitwarden.com>
Co-authored-by: kejaeger <138028972+kejaeger@users.noreply.github.com>
This commit is contained in:
Jason Ng
2025-02-04 15:44:59 -05:00
committed by GitHub
parent 1b3bc71e50
commit 327aed9763
15 changed files with 143 additions and 142 deletions

View File

@@ -4155,15 +4155,6 @@
"itemName": {
"message": "Item name"
},
"cannotRemoveViewOnlyCollections": {
"message": "You cannot remove collections with View only permissions: $COLLECTIONS$",
"placeholders": {
"collections": {
"content": "$1",
"example": "Work, Personal"
}
}
},
"organizationIsDeactivated": {
"message": "Organization is deactivated"
},
@@ -4896,6 +4887,15 @@
"extraWide": {
"message": "Extra wide"
},
"cannotRemoveViewOnlyCollections": {
"message": "You cannot remove collections with View only permissions: $COLLECTIONS$",
"placeholders": {
"collections": {
"content": "$1",
"example": "Work, Personal"
}
}
},
"updateDesktopAppOrDisableFingerprintDialogTitle": {
"message": "Please update your desktop application"
},

View File

@@ -27,7 +27,7 @@
<button type="button" bitMenuItem (click)="toggleFavorite()">
{{ favoriteText | i18n }}
</button>
<ng-container *ngIf="canEdit">
<ng-container *ngIf="canEdit && canViewPassword">
<a bitMenuItem (click)="clone()" *ngIf="canClone$ | async">
{{ "clone" | i18n }}
</a>

View File

@@ -97,6 +97,9 @@ export class ItemMoreOptionsComponent implements OnInit {
return this.cipher.edit;
}
get canViewPassword() {
return this.cipher.viewPassword;
}
/**
* Determines if the cipher can be autofilled.
*/

View File

@@ -123,6 +123,9 @@ export class EditCommand {
"Item does not belong to an organization. Consider moving it first.",
);
}
if (!cipher.viewPassword) {
return Response.noEditPermission();
}
cipher.collectionIds = req;
try {

View File

@@ -39,6 +39,10 @@ export class Response {
return Response.error("Not found.");
}
static noEditPermission(): Response {
return Response.error("You do not have permission to edit this item");
}
static badRequest(message: string): Response {
return Response.error(message);
}

View File

@@ -21,6 +21,7 @@
type="checkbox"
[(ngModel)]="$any(c).checked"
name="Collection[{{ i }}].Checked"
[disabled]="!cipher.canAssignToCollections"
/>
</div>
</div>

View File

@@ -42,6 +42,7 @@ export class VaultCipherRowComponent implements OnInit {
@Input() collections: CollectionView[];
@Input() viewingOrgVault: boolean;
@Input() canEditCipher: boolean;
@Input() canAssignCollections: boolean;
@Input() canManageCollection: boolean;
@Output() onEvent = new EventEmitter<VaultItemEvent>();
@@ -101,7 +102,7 @@ export class VaultCipherRowComponent implements OnInit {
}
protected get showAssignToCollections() {
return this.organizations?.length && this.canEditCipher && !this.cipher.isDeleted;
return this.organizations?.length && this.canAssignCollections && !this.cipher.isDeleted;
}
protected get showClone() {
@@ -208,6 +209,6 @@ export class VaultCipherRowComponent implements OnInit {
return true; // Always show checkbox in individual vault or for non-org items
}
return this.organization.canEditAllCiphers || this.cipher.edit;
return this.organization.canEditAllCiphers || (this.cipher.edit && this.cipher.viewPassword);
}
}

View File

@@ -144,6 +144,7 @@
[collections]="allCollections"
[checked]="selection.isSelected(item)"
[canEditCipher]="canEditCipher(item.cipher)"
[canAssignCollections]="canAssignCollections(item.cipher)"
[canManageCollection]="canManageCollection(item.cipher)"
(checkedToggled)="selection.toggle(item)"
(onEvent)="event($event)"

View File

@@ -236,6 +236,13 @@ export class VaultItemsComponent {
return (organization.canEditAllCiphers && this.viewingOrgVault) || cipher.edit;
}
protected canAssignCollections(cipher: CipherView) {
const organization = this.allOrganizations.find((o) => o.id === cipher.organizationId);
return (
(organization?.canEditAllCiphers && this.viewingOrgVault) || cipher.canAssignToCollections
);
}
protected canManageCollection(cipher: CipherView) {
// If the cipher is not part of an organization (personal item), user can manage it
if (cipher.organizationId == null) {
@@ -461,7 +468,7 @@ export class VaultItemsComponent {
private allCiphersHaveEditAccess(): boolean {
return this.selection.selected
.filter(({ cipher }) => cipher)
.every(({ cipher }) => cipher?.edit);
.every(({ cipher }) => cipher?.edit && cipher?.viewPassword);
}
private getUniqueOrganizationIds(): Set<string> {

View File

@@ -749,15 +749,6 @@
"itemName": {
"message": "Item name"
},
"cannotRemoveViewOnlyCollections": {
"message": "You cannot remove collections with View only permissions: $COLLECTIONS$",
"placeholders": {
"collections": {
"content": "$1",
"example": "Work, Personal"
}
}
},
"ex": {
"message": "ex.",
"description": "Short abbreviation for 'example'."
@@ -10143,6 +10134,15 @@
"descriptorCode": {
"message": "Descriptor code"
},
"cannotRemoveViewOnlyCollections": {
"message": "You cannot remove collections with View only permissions: $COLLECTIONS$",
"placeholders": {
"collections": {
"content": "$1",
"example": "Work, Personal"
}
}
},
"importantNotice": {
"message": "Important notice"
},