1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-14 23:33:31 +00:00

[PM-23788] [PM-23793] Prevent Card Clone when Restricted (#15685)

* add restricted policy check to vault items in web and browser
This commit is contained in:
Jason Ng
2025-07-23 12:04:31 -04:00
committed by GitHub
parent aa2c5a0087
commit d0082981a3
2 changed files with 30 additions and 7 deletions

View File

@@ -3,8 +3,7 @@
import { CommonModule } from "@angular/common";
import { booleanAttribute, Component, Input } from "@angular/core";
import { Router, RouterModule } from "@angular/router";
import { BehaviorSubject, combineLatest, firstValueFrom, map, switchMap } from "rxjs";
import { filter } from "rxjs/operators";
import { BehaviorSubject, combineLatest, filter, firstValueFrom, map, switchMap } from "rxjs";
import { CollectionService } from "@bitwarden/admin-console/common";
import { JslibModule } from "@bitwarden/angular/jslib.module";
@@ -15,6 +14,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums";
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
import {
CipherViewLike,
CipherViewLikeUtils,
@@ -70,9 +70,21 @@ export class ItemMoreOptionsComponent {
* Observable that emits a boolean value indicating if the user is authorized to clone the cipher.
* @protected
*/
protected canClone$ = this._cipher$.pipe(
filter((c) => c != null),
switchMap((c) => this.cipherAuthorizationService.canCloneCipher$(c)),
protected canClone$ = combineLatest([
this._cipher$,
this.restrictedItemTypesService.restricted$,
]).pipe(
filter(([c]) => c != null),
switchMap(([c, restrictedTypes]) => {
// This will check for restrictions from org policies before allowing cloning.
const isItemRestricted = restrictedTypes.some(
(restrictType) => restrictType.cipherType === c.type,
);
if (!isItemRestricted) {
return this.cipherAuthorizationService.canCloneCipher$(c);
}
return new BehaviorSubject(false);
}),
);
/** Observable Boolean dependent on the current user having access to an organization and editable collections */
@@ -103,6 +115,7 @@ export class ItemMoreOptionsComponent {
private organizationService: OrganizationService,
private cipherAuthorizationService: CipherAuthorizationService,
private collectionService: CollectionService,
private restrictedItemTypesService: RestrictedItemTypesService,
) {}
get canEdit() {

View File

@@ -2,7 +2,7 @@
// @ts-strict-ignore
import { SelectionModel } from "@angular/cdk/collections";
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { toSignal, takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { Observable, combineLatest, map, of, startWith, switchMap } from "rxjs";
import { CollectionView, Unassigned, CollectionAdminView } from "@bitwarden/admin-console/common";
@@ -64,6 +64,8 @@ export class VaultItemsComponent<C extends CipherViewLike> {
@Input() addAccessToggle: boolean;
@Input() activeCollection: CollectionView | undefined;
private restrictedPolicies = toSignal(this.restrictedItemTypesService.restricted$);
private _ciphers?: C[] = [];
@Input() get ciphers(): C[] {
return this._ciphers;
@@ -94,7 +96,7 @@ export class VaultItemsComponent<C extends CipherViewLike> {
constructor(
protected cipherAuthorizationService: CipherAuthorizationService,
private restrictedItemTypesService: RestrictedItemTypesService,
protected restrictedItemTypesService: RestrictedItemTypesService,
) {
this.canDeleteSelected$ = this.selection.changed.pipe(
startWith(null),
@@ -281,6 +283,14 @@ export class VaultItemsComponent<C extends CipherViewLike> {
// TODO: PM-13944 Refactor to use cipherAuthorizationService.canClone$ instead
protected canClone(vaultItem: VaultItem<C>) {
// This will check for restrictions from org policies before allowing cloning.
const isItemRestricted = this.restrictedPolicies().some(
(rt) => rt.cipherType === vaultItem.cipher.type,
);
if (isItemRestricted) {
return false;
}
if (vaultItem.cipher.organizationId == null) {
return true;
}