mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +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:
@@ -3,8 +3,7 @@
|
|||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { booleanAttribute, Component, Input } from "@angular/core";
|
import { booleanAttribute, Component, Input } from "@angular/core";
|
||||||
import { Router, RouterModule } from "@angular/router";
|
import { Router, RouterModule } from "@angular/router";
|
||||||
import { BehaviorSubject, combineLatest, firstValueFrom, map, switchMap } from "rxjs";
|
import { BehaviorSubject, combineLatest, filter, firstValueFrom, map, switchMap } from "rxjs";
|
||||||
import { filter } from "rxjs/operators";
|
|
||||||
|
|
||||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||||
import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums";
|
import { CipherRepromptType, CipherType } from "@bitwarden/common/vault/enums";
|
||||||
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
|
||||||
|
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
|
||||||
import {
|
import {
|
||||||
CipherViewLike,
|
CipherViewLike,
|
||||||
CipherViewLikeUtils,
|
CipherViewLikeUtils,
|
||||||
@@ -70,9 +70,21 @@ export class ItemMoreOptionsComponent {
|
|||||||
* Observable that emits a boolean value indicating if the user is authorized to clone the cipher.
|
* Observable that emits a boolean value indicating if the user is authorized to clone the cipher.
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
protected canClone$ = this._cipher$.pipe(
|
protected canClone$ = combineLatest([
|
||||||
filter((c) => c != null),
|
this._cipher$,
|
||||||
switchMap((c) => this.cipherAuthorizationService.canCloneCipher$(c)),
|
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 */
|
/** 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 organizationService: OrganizationService,
|
||||||
private cipherAuthorizationService: CipherAuthorizationService,
|
private cipherAuthorizationService: CipherAuthorizationService,
|
||||||
private collectionService: CollectionService,
|
private collectionService: CollectionService,
|
||||||
|
private restrictedItemTypesService: RestrictedItemTypesService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
get canEdit() {
|
get canEdit() {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { SelectionModel } from "@angular/cdk/collections";
|
import { SelectionModel } from "@angular/cdk/collections";
|
||||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
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 { Observable, combineLatest, map, of, startWith, switchMap } from "rxjs";
|
||||||
|
|
||||||
import { CollectionView, Unassigned, CollectionAdminView } from "@bitwarden/admin-console/common";
|
import { CollectionView, Unassigned, CollectionAdminView } from "@bitwarden/admin-console/common";
|
||||||
@@ -64,6 +64,8 @@ export class VaultItemsComponent<C extends CipherViewLike> {
|
|||||||
@Input() addAccessToggle: boolean;
|
@Input() addAccessToggle: boolean;
|
||||||
@Input() activeCollection: CollectionView | undefined;
|
@Input() activeCollection: CollectionView | undefined;
|
||||||
|
|
||||||
|
private restrictedPolicies = toSignal(this.restrictedItemTypesService.restricted$);
|
||||||
|
|
||||||
private _ciphers?: C[] = [];
|
private _ciphers?: C[] = [];
|
||||||
@Input() get ciphers(): C[] {
|
@Input() get ciphers(): C[] {
|
||||||
return this._ciphers;
|
return this._ciphers;
|
||||||
@@ -94,7 +96,7 @@ export class VaultItemsComponent<C extends CipherViewLike> {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected cipherAuthorizationService: CipherAuthorizationService,
|
protected cipherAuthorizationService: CipherAuthorizationService,
|
||||||
private restrictedItemTypesService: RestrictedItemTypesService,
|
protected restrictedItemTypesService: RestrictedItemTypesService,
|
||||||
) {
|
) {
|
||||||
this.canDeleteSelected$ = this.selection.changed.pipe(
|
this.canDeleteSelected$ = this.selection.changed.pipe(
|
||||||
startWith(null),
|
startWith(null),
|
||||||
@@ -281,6 +283,14 @@ export class VaultItemsComponent<C extends CipherViewLike> {
|
|||||||
|
|
||||||
// TODO: PM-13944 Refactor to use cipherAuthorizationService.canClone$ instead
|
// TODO: PM-13944 Refactor to use cipherAuthorizationService.canClone$ instead
|
||||||
protected canClone(vaultItem: VaultItem<C>) {
|
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) {
|
if (vaultItem.cipher.organizationId == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user