1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 00:03:56 +00:00

[PM-19746] Add new permission check to browser (#14075)

* add new permisssions check to browser

* add permission logic to view

* fix tests

* cleanup

* fix permissions model for CLI and desktop

* feedback
This commit is contained in:
Brandon Treston
2025-04-02 12:49:08 -04:00
committed by GitHub
parent 0d9794e968
commit 9b3c28fcea
11 changed files with 82 additions and 9 deletions

View File

@@ -5,7 +5,7 @@
<app-cipher-view *ngIf="cipher" [cipher]="cipher"></app-cipher-view>
<popup-footer slot="footer" *ngIf="showFooter()">
<popup-footer slot="footer" *ngIf="showFooter$ | async">
<button
*ngIf="!cipher.isDeleted"
buttonType="primary"
@@ -17,7 +17,11 @@
</button>
<button
*ngIf="cipher.isDeleted && cipher.edit"
*ngIf="
(limitItemDeletion$ | async)
? cipher.isDeleted && cipher.permissions.restore
: cipher.isDeleted && cipher.edit
"
buttonType="primary"
type="button"
bitButton

View File

@@ -1,7 +1,7 @@
import { ComponentFixture, fakeAsync, flush, TestBed } from "@angular/core/testing";
import { ActivatedRoute, Router } from "@angular/router";
import { mock } from "jest-mock-extended";
import { Subject } from "rxjs";
import { of, Subject } from "rxjs";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
@@ -51,6 +51,7 @@ describe("ViewV2Component", () => {
const openSimpleDialog = jest.fn().mockResolvedValue(true);
const stop = jest.fn();
const showToast = jest.fn();
const getFeatureFlag$ = jest.fn().mockReturnValue(of(true));
const mockCipher = {
id: "122-333-444",
@@ -105,6 +106,7 @@ describe("ViewV2Component", () => {
{ provide: VaultPopupScrollPositionService, useValue: { stop } },
{ provide: VaultPopupAutofillService, useValue: mockVaultPopupAutofillService },
{ provide: ToastService, useValue: { showToast } },
{ provide: ConfigService, useValue: { getFeatureFlag$ } },
{
provide: I18nService,
useValue: {

View File

@@ -5,7 +5,7 @@ import { Component } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { FormsModule } from "@angular/forms";
import { ActivatedRoute, Router } from "@angular/router";
import { firstValueFrom, Observable, switchMap } from "rxjs";
import { firstValueFrom, map, Observable, switchMap } from "rxjs";
import { CollectionView } from "@bitwarden/admin-console/common";
import { JslibModule } from "@bitwarden/angular/jslib.module";
@@ -21,6 +21,8 @@ import {
SHOW_AUTOFILL_BUTTON,
} from "@bitwarden/common/autofill/constants";
import { EventType } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { UserId } from "@bitwarden/common/types/guid";
@@ -107,6 +109,9 @@ export class ViewV2Component {
loadAction: LoadAction;
senderTabId?: number;
protected limitItemDeletion$ = this.configService.getFeatureFlag$(FeatureFlag.LimitItemDeletion);
protected showFooter$: Observable<boolean>;
constructor(
private route: ActivatedRoute,
private router: Router,
@@ -122,6 +127,7 @@ export class ViewV2Component {
protected cipherAuthorizationService: CipherAuthorizationService,
private copyCipherFieldService: CopyCipherFieldService,
private popupScrollPositionService: VaultPopupScrollPositionService,
private configService: ConfigService,
) {
this.subscribeToParams();
}
@@ -150,6 +156,19 @@ export class ViewV2Component {
this.canDeleteCipher$ = this.cipherAuthorizationService.canDeleteCipher$(cipher);
this.showFooter$ = this.limitItemDeletion$.pipe(
map((enabled) => {
if (enabled) {
return (
cipher &&
(!cipher.isDeleted ||
(cipher.isDeleted && (cipher.permissions.restore || cipher.permissions.delete)))
);
}
return this.showFooterLegacy();
}),
);
await this.eventCollectionService.collect(
EventType.Cipher_ClientViewed,
cipher.id,
@@ -247,7 +266,8 @@ export class ViewV2Component {
: this.cipherService.softDeleteWithServer(this.cipher.id, this.activeUserId);
}
protected showFooter(): boolean {
//@TODO: remove this when the LimitItemDeletion feature flag is removed
protected showFooterLegacy(): boolean {
return (
this.cipher &&
(!this.cipher.isDeleted ||

View File

@@ -31,7 +31,14 @@
></i>
<span slot="secondary">{{ cipher.subTitle }}</span>
</button>
<ng-container slot="end" *ngIf="cipher.edit && cipher.viewPassword">
<ng-container
slot="end"
*ngIf="
(limitItemDeletion$ | async)
? cipher.permissions.restore
: cipher.edit && cipher.viewPassword
"
>
<bit-item-action>
<button
type="button"

View File

@@ -8,6 +8,8 @@ import { firstValueFrom } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { CipherId } from "@bitwarden/common/types/guid";
@@ -70,8 +72,11 @@ export class TrashListItemsContainerComponent {
private passwordRepromptService: PasswordRepromptService,
private accountService: AccountService,
private router: Router,
private configService: ConfigService,
) {}
protected limitItemDeletion$ = this.configService.getFeatureFlag$(FeatureFlag.LimitItemDeletion);
/**
* The tooltip text for the organization icon for ciphers that belong to an organization.
*/