mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
[PM-12047] Remove usage of ActiveUserState from cipher.service (#12814)
* Cipher service web changes * Updated browser client to pass user id to cipher service observable changes * Cli changes * desktop changes * Fixed test * Libs changes * Fixed merge conflicts * Fixed merge conflicts * removed duplicate reference fixed conflict * Fixed test * Fixed test * Fixed test * Fixed desturcturing issue on failed to decrypt ciphers cipher service * Updated abstraction to use method syntax * Fixed conflicts * Fixed test on add edit v2 Passed active userId to delete function * Used getUserId utility function * made vault changes * made suggestion changes * made suggestion changes * made suggestion changes * Replace getUserId function calls with pipe operator syntax for better consistency * fixed merge conflicts * revert mistake made of usinf account activity during merge conflict fix * fixed conflicts * fixed tests
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { AuditService } from "@bitwarden/common/abstractions/audit.service";
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
@@ -59,15 +60,13 @@ export class ExposedPasswordsReportComponent
|
||||
this.isAdminConsoleActive = true;
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
);
|
||||
this.manageableCiphers = await this.cipherService.getAll();
|
||||
this.manageableCiphers = await this.cipherService.getAll(userId);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import {
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
@@ -56,15 +57,13 @@ export class ReusedPasswordsReportComponent
|
||||
this.isAdminConsoleActive = true;
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
);
|
||||
this.manageableCiphers = await this.cipherService.getAll();
|
||||
this.manageableCiphers = await this.cipherService.getAll(userId);
|
||||
await super.ngOnInit();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import { firstValueFrom, map } from "rxjs";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import {
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
OrganizationService,
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PasswordStrengthServiceAbstraction } from "@bitwarden/common/tools/password-strength";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@@ -59,15 +60,14 @@ export class WeakPasswordsReportComponent
|
||||
this.isAdminConsoleActive = true;
|
||||
// eslint-disable-next-line rxjs-angular/prefer-takeuntil, rxjs/no-async-subscribe
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
const userId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
this.organization = await firstValueFrom(
|
||||
this.organizationService
|
||||
.organizations$(userId)
|
||||
.pipe(getOrganizationById(params.organizationId)),
|
||||
);
|
||||
this.manageableCiphers = await this.cipherService.getAll();
|
||||
this.manageableCiphers = await this.cipherService.getAll(userId);
|
||||
await super.ngOnInit();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -88,7 +88,9 @@ export class ChangePasswordComponent
|
||||
|
||||
async rotateUserKeyClicked() {
|
||||
if (this.rotateUserKey) {
|
||||
const ciphers = await this.cipherService.getAllDecrypted();
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
|
||||
const ciphers = await this.cipherService.getAllDecrypted(activeUserId);
|
||||
let hasOldAttachments = false;
|
||||
if (ciphers != null) {
|
||||
for (let i = 0; i < ciphers.length; i++) {
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Directive, ViewChild, ViewContainerRef, OnDestroy } from "@angular/core";
|
||||
import { BehaviorSubject, Observable, Subject, switchMap, takeUntil } from "rxjs";
|
||||
import { BehaviorSubject, Observable, Subject, firstValueFrom, switchMap, takeUntil } from "rxjs";
|
||||
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@@ -51,8 +52,10 @@ export class CipherReportComponent implements OnDestroy {
|
||||
private syncService: SyncService,
|
||||
) {
|
||||
this.organizations$ = this.accountService.activeAccount$.pipe(
|
||||
switchMap((account) => this.organizationService.organizations$(account?.id)),
|
||||
getUserId,
|
||||
switchMap((userId) => this.organizationService.organizations$(userId)),
|
||||
);
|
||||
|
||||
this.organizations$.pipe(takeUntil(this.destroyed$)).subscribe((orgs) => {
|
||||
this.organizations = orgs;
|
||||
});
|
||||
@@ -182,7 +185,8 @@ export class CipherReportComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
protected async getAllCiphers(): Promise<CipherView[]> {
|
||||
return await this.cipherService.getAllDecrypted();
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
return await this.cipherService.getAllDecrypted(activeUserId);
|
||||
}
|
||||
|
||||
protected filterCiphersByOrg(ciphersList: CipherView[]) {
|
||||
|
||||
@@ -25,15 +25,14 @@ describe("ExposedPasswordsReportComponent", () => {
|
||||
let auditService: MockProxy<AuditService>;
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith(userId);
|
||||
|
||||
beforeEach(() => {
|
||||
syncServiceMock = mock<SyncService>();
|
||||
auditService = mock<AuditService>();
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
|
||||
@@ -24,14 +24,13 @@ describe("InactiveTwoFactorReportComponent", () => {
|
||||
let fixture: ComponentFixture<InactiveTwoFactorReportComponent>;
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith(userId);
|
||||
|
||||
beforeEach(() => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
syncServiceMock = mock<SyncService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
|
||||
@@ -23,15 +23,13 @@ describe("ReusedPasswordsReportComponent", () => {
|
||||
let fixture: ComponentFixture<ReusedPasswordsReportComponent>;
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith(userId);
|
||||
|
||||
beforeEach(() => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
syncServiceMock = mock<SyncService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
|
||||
@@ -25,15 +25,14 @@ describe("UnsecuredWebsitesReportComponent", () => {
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let collectionService: MockProxy<CollectionService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith(userId);
|
||||
|
||||
beforeEach(() => {
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
syncServiceMock = mock<SyncService>();
|
||||
collectionService = mock<CollectionService>();
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
|
||||
@@ -25,15 +25,14 @@ describe("WeakPasswordsReportComponent", () => {
|
||||
let passwordStrengthService: MockProxy<PasswordStrengthServiceAbstraction>;
|
||||
let organizationService: MockProxy<OrganizationService>;
|
||||
let syncServiceMock: MockProxy<SyncService>;
|
||||
let accountService: FakeAccountService;
|
||||
const userId = Utils.newGuid() as UserId;
|
||||
const accountService: FakeAccountService = mockAccountServiceWith(userId);
|
||||
|
||||
beforeEach(() => {
|
||||
syncServiceMock = mock<SyncService>();
|
||||
passwordStrengthService = mock<PasswordStrengthServiceAbstraction>();
|
||||
organizationService = mock<OrganizationService>();
|
||||
organizationService.organizations$.mockReturnValue(of([]));
|
||||
accountService = mockAccountServiceWith(userId);
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
TestBed.configureTestingModule({
|
||||
|
||||
@@ -12,6 +12,7 @@ import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
|
||||
import { EventType } from "@bitwarden/common/enums";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -355,8 +356,8 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
|
||||
this.formConfig.mode = "edit";
|
||||
this.formConfig.initialValues = null;
|
||||
}
|
||||
|
||||
let cipher = await this.cipherService.get(cipherView.id);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
let cipher = await this.cipherService.get(cipherView.id, activeUserId);
|
||||
|
||||
// When the form config is used within the Admin Console, retrieve the cipher from the admin endpoint (if not found in local state)
|
||||
if (this.formConfig.isAdminConsole && (cipher == null || this.formConfig.admin)) {
|
||||
@@ -448,10 +449,13 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
|
||||
result.action === AttachmentDialogResult.Removed ||
|
||||
result.action === AttachmentDialogResult.Uploaded
|
||||
) {
|
||||
const updatedCipher = await this.cipherService.get(this.formConfig.originalCipher?.id);
|
||||
const activeUserId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
const updatedCipher = await this.cipherService.get(
|
||||
this.formConfig.originalCipher?.id,
|
||||
activeUserId,
|
||||
);
|
||||
|
||||
const updatedCipherView = await updatedCipher.decrypt(
|
||||
await this.cipherService.getKeyForCipherKeyDecryption(updatedCipher, activeUserId),
|
||||
@@ -490,9 +494,7 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
|
||||
if (config.originalCipher == null) {
|
||||
return;
|
||||
}
|
||||
const activeUserId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
return await config.originalCipher.decrypt(
|
||||
await this.cipherService.getKeyForCipherKeyDecryption(config.originalCipher, activeUserId),
|
||||
);
|
||||
@@ -574,10 +576,14 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy {
|
||||
// - The cipher is unassigned
|
||||
const asAdmin = this.organization?.canEditAllCiphers || cipherIsUnassigned;
|
||||
|
||||
const activeUserId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
|
||||
if (this.cipher.isDeleted) {
|
||||
await this.cipherService.deleteWithServer(this.cipher.id, asAdmin);
|
||||
await this.cipherService.deleteWithServer(this.cipher.id, activeUserId, asAdmin);
|
||||
} else {
|
||||
await this.cipherService.softDeleteWithServer(this.cipher.id, asAdmin);
|
||||
await this.cipherService.softDeleteWithServer(this.cipher.id, activeUserId, asAdmin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
// @ts-strict-ignore
|
||||
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
||||
import { Component, Inject } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@@ -61,6 +64,7 @@ export class BulkDeleteDialogComponent {
|
||||
private apiService: ApiService,
|
||||
private collectionService: CollectionService,
|
||||
private toastService: ToastService,
|
||||
private accountService: AccountService,
|
||||
) {
|
||||
this.cipherIds = params.cipherIds ?? [];
|
||||
this.permanent = params.permanent;
|
||||
@@ -115,10 +119,12 @@ export class BulkDeleteDialogComponent {
|
||||
|
||||
private async deleteCiphers(): Promise<any> {
|
||||
const asAdmin = this.organization?.canEditAllCiphers;
|
||||
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
if (this.permanent) {
|
||||
await this.cipherService.deleteManyWithServer(this.cipherIds, asAdmin);
|
||||
await this.cipherService.deleteManyWithServer(this.cipherIds, activeUserId, asAdmin);
|
||||
} else {
|
||||
await this.cipherService.softDeleteManyWithServer(this.cipherIds, asAdmin);
|
||||
await this.cipherService.softDeleteManyWithServer(this.cipherIds, activeUserId, asAdmin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
import { DialogConfig, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { Component, Inject, OnInit } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { firstValueFrom, map, Observable } from "rxjs";
|
||||
import { firstValueFrom, Observable } from "rxjs";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
@@ -48,8 +49,6 @@ export class BulkMoveDialogComponent implements OnInit {
|
||||
});
|
||||
folders$: Observable<FolderView[]>;
|
||||
|
||||
private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id));
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) params: BulkMoveDialogParams,
|
||||
private dialogRef: DialogRef<BulkMoveDialogResult>,
|
||||
@@ -65,7 +64,7 @@ export class BulkMoveDialogComponent implements OnInit {
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
const activeUserId = await firstValueFrom(this.activeUserId$);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
this.folders$ = this.folderService.folderViews$(activeUserId);
|
||||
this.formGroup.patchValue({
|
||||
folderId: (await firstValueFrom(this.folders$))[0].id,
|
||||
@@ -81,7 +80,12 @@ export class BulkMoveDialogComponent implements OnInit {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.cipherService.moveManyWithServer(this.cipherIds, this.formGroup.value.folderId);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
await this.cipherService.moveManyWithServer(
|
||||
this.cipherIds,
|
||||
this.formGroup.value.folderId,
|
||||
activeUserId,
|
||||
);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
|
||||
@@ -71,7 +71,7 @@ describe("vault filter service", () => {
|
||||
policyService.policyAppliesToActiveUser$
|
||||
.calledWith(PolicyType.SingleOrg)
|
||||
.mockReturnValue(singleOrgPolicy);
|
||||
cipherService.cipherViews$ = cipherViews;
|
||||
cipherService.cipherViews$.mockReturnValue(cipherViews);
|
||||
|
||||
vaultFilterService = new VaultFilterService(
|
||||
organizationService,
|
||||
|
||||
@@ -68,7 +68,7 @@ export class VaultFilterService implements VaultFilterServiceAbstraction {
|
||||
switchMap((userId) =>
|
||||
combineLatest([
|
||||
this.folderService.folderViews$(userId),
|
||||
this.cipherService.cipherViews$,
|
||||
this.cipherService.cipherViews$(userId),
|
||||
this._organizationFilter,
|
||||
]),
|
||||
),
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
} from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
|
||||
@@ -166,7 +167,6 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
protected selectedCollection: TreeNode<CollectionView> | undefined;
|
||||
protected canCreateCollections = false;
|
||||
protected currentSearchText$: Observable<string>;
|
||||
private activeUserId: UserId;
|
||||
private searchText$ = new Subject<string>();
|
||||
private refresh$ = new BehaviorSubject<void>(null);
|
||||
private destroy$ = new Subject<void>();
|
||||
@@ -271,9 +271,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
: "trashCleanupWarning",
|
||||
);
|
||||
|
||||
this.activeUserId = await firstValueFrom(
|
||||
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
|
||||
);
|
||||
const activeUserId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
|
||||
const firstSetup$ = this.route.queryParams.pipe(
|
||||
first(),
|
||||
@@ -337,13 +335,15 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
this.currentSearchText$ = this.route.queryParams.pipe(map((queryParams) => queryParams.search));
|
||||
|
||||
const ciphers$ = combineLatest([
|
||||
this.cipherService.cipherViews$.pipe(filter((c) => c !== null)),
|
||||
this.cipherService.cipherViews$(activeUserId).pipe(filter((c) => c !== null)),
|
||||
filter$,
|
||||
this.currentSearchText$,
|
||||
]).pipe(
|
||||
filter(([ciphers, filter]) => ciphers != undefined && filter != undefined),
|
||||
concatMap(async ([ciphers, filter, searchText]) => {
|
||||
const failedCiphers = await firstValueFrom(this.cipherService.failedToDecryptCiphers$);
|
||||
const failedCiphers = await firstValueFrom(
|
||||
this.cipherService.failedToDecryptCiphers$(activeUserId),
|
||||
);
|
||||
const filterFunction = createFilterFunction(filter);
|
||||
// Append any failed to decrypt ciphers to the top of the cipher list
|
||||
const allCiphers = [...failedCiphers, ...ciphers];
|
||||
@@ -416,7 +416,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
switchMap(async (params) => {
|
||||
const cipherId = getCipherIdFromParams(params);
|
||||
if (cipherId) {
|
||||
if (await this.cipherService.get(cipherId)) {
|
||||
if (await this.cipherService.get(cipherId, activeUserId)) {
|
||||
let action = params.action;
|
||||
// Default to "view"
|
||||
if (action == null) {
|
||||
@@ -459,7 +459,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
firstSetup$
|
||||
.pipe(
|
||||
switchMap(() => this.cipherService.failedToDecryptCiphers$),
|
||||
switchMap(() => this.cipherService.failedToDecryptCiphers$(activeUserId)),
|
||||
map((ciphers) => ciphers.filter((c) => !c.isDeleted)),
|
||||
filter((ciphers) => ciphers.length > 0),
|
||||
take(1),
|
||||
@@ -480,7 +480,7 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
switchMap(() =>
|
||||
combineLatest([
|
||||
filter$,
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$(this.activeUserId),
|
||||
this.billingAccountProfileStateService.hasPremiumFromAnySource$(activeUserId),
|
||||
allCollections$,
|
||||
this.organizations$,
|
||||
ciphers$,
|
||||
@@ -732,7 +732,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
* @returns
|
||||
*/
|
||||
async editCipherId(id: string, cloneMode?: boolean) {
|
||||
const cipher = await this.cipherService.get(id);
|
||||
const activeUserId = await firstValueFrom(getUserId(this.accountService.activeAccount$));
|
||||
const cipher = await this.cipherService.get(id, activeUserId);
|
||||
|
||||
if (
|
||||
cipher &&
|
||||
@@ -768,7 +769,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
* @returns Promise<void>
|
||||
*/
|
||||
async viewCipherById(id: string) {
|
||||
const cipher = await this.cipherService.get(id);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
const cipher = await this.cipherService.get(id, activeUserId);
|
||||
// If cipher exists (cipher is null when new) and MP reprompt
|
||||
// is on for this cipher, then show password reprompt.
|
||||
if (
|
||||
@@ -959,7 +961,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
try {
|
||||
await this.cipherService.restoreWithServer(c.id);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
await this.cipherService.restoreWithServer(c.id, activeUserId);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
@@ -1041,7 +1044,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
try {
|
||||
await this.deleteCipherWithServer(c.id, permanent);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
await this.deleteCipherWithServer(c.id, activeUserId, permanent);
|
||||
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
@@ -1176,10 +1180,10 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
protected deleteCipherWithServer(id: string, permanent: boolean) {
|
||||
protected deleteCipherWithServer(id: string, userId: UserId, permanent: boolean) {
|
||||
return permanent
|
||||
? this.cipherService.deleteWithServer(id)
|
||||
: this.cipherService.softDeleteWithServer(id);
|
||||
? this.cipherService.deleteWithServer(id, userId)
|
||||
: this.cipherService.softDeleteWithServer(id, userId);
|
||||
}
|
||||
|
||||
protected async repromptCipher(ciphers: CipherView[]) {
|
||||
|
||||
@@ -165,10 +165,11 @@ export class ViewComponent implements OnInit {
|
||||
*/
|
||||
protected async deleteCipher(): Promise<void> {
|
||||
const asAdmin = this.organization?.canEditAllCiphers;
|
||||
const userId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
if (this.cipher.isDeleted) {
|
||||
await this.cipherService.deleteWithServer(this.cipher.id, asAdmin);
|
||||
await this.cipherService.deleteWithServer(this.cipher.id, userId, asAdmin);
|
||||
} else {
|
||||
await this.cipherService.softDeleteWithServer(this.cipher.id, asAdmin);
|
||||
await this.cipherService.softDeleteWithServer(this.cipher.id, userId, asAdmin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// @ts-strict-ignore
|
||||
import { DatePipe } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { CollectionService } from "@bitwarden/admin-console/common";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
@@ -10,6 +11,7 @@ import { EventCollectionService } from "@bitwarden/common/abstractions/event/eve
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -98,8 +100,9 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
|
||||
protected async loadCipher() {
|
||||
this.isAdminConsoleAction = true;
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
// Calling loadCipher first to assess if the cipher is unassigned. If null use apiService getCipherAdmin
|
||||
const firstCipherCheck = await super.loadCipher();
|
||||
const firstCipherCheck = await super.loadCipher(activeUserId);
|
||||
|
||||
if (!this.organization.canEditAllCiphers && firstCipherCheck != null) {
|
||||
return firstCipherCheck;
|
||||
@@ -123,7 +126,8 @@ export class AddEditComponent extends BaseAddEditComponent {
|
||||
|
||||
protected async deleteCipher() {
|
||||
if (!this.organization.canEditAllCiphers) {
|
||||
return super.deleteCipher();
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
return super.deleteCipher(activeUserId);
|
||||
}
|
||||
return this.cipher.isDeleted
|
||||
? this.apiService.deleteCipherAdmin(this.cipherId)
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import { firstValueFrom } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions/account/billing-account-profile-state.service";
|
||||
import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service";
|
||||
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
|
||||
@@ -74,7 +76,8 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
||||
|
||||
protected async loadCipher() {
|
||||
if (!this.organization.canEditAllCiphers) {
|
||||
return await super.loadCipher();
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
return await super.loadCipher(activeUserId);
|
||||
}
|
||||
const response = await this.apiService.getCipherAdmin(this.cipherId);
|
||||
return new Cipher(new CipherData(response));
|
||||
@@ -89,9 +92,9 @@ export class AttachmentsComponent extends BaseAttachmentsComponent implements On
|
||||
);
|
||||
}
|
||||
|
||||
protected deleteCipherAttachment(attachmentId: string) {
|
||||
protected deleteCipherAttachment(attachmentId: string, userId: UserId) {
|
||||
if (!this.organization.canEditAllCiphers) {
|
||||
return super.deleteCipherAttachment(attachmentId);
|
||||
return super.deleteCipherAttachment(attachmentId, userId);
|
||||
}
|
||||
return this.apiService.deleteCipherAttachmentAdmin(this.cipherId, attachmentId);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
|
||||
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
|
||||
import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { mockAccountServiceWith } from "@bitwarden/common/spec";
|
||||
import { CipherId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
|
||||
@@ -26,6 +27,7 @@ describe("AdminConsoleCipherFormConfigService", () => {
|
||||
isMember: true,
|
||||
enabled: true,
|
||||
status: OrganizationUserStatusType.Confirmed,
|
||||
userId: "UserId",
|
||||
};
|
||||
const testOrg2 = {
|
||||
id: "333-999-888",
|
||||
@@ -34,6 +36,7 @@ describe("AdminConsoleCipherFormConfigService", () => {
|
||||
isMember: true,
|
||||
enabled: true,
|
||||
status: OrganizationUserStatusType.Confirmed,
|
||||
userId: "UserId",
|
||||
};
|
||||
const policyAppliesToActiveUser$ = new BehaviorSubject<boolean>(true);
|
||||
const collection = {
|
||||
@@ -80,17 +83,7 @@ describe("AdminConsoleCipherFormConfigService", () => {
|
||||
},
|
||||
{ provide: ApiService, useValue: { getCipherAdmin } },
|
||||
{ provide: CipherService, useValue: { get: getCipher } },
|
||||
{
|
||||
provide: AccountService,
|
||||
useValue: {
|
||||
activeAccount$: new BehaviorSubject<Account>({
|
||||
id: "123-456-789" as UserId,
|
||||
email: "test@email.com",
|
||||
emailVerified: true,
|
||||
name: "Test User",
|
||||
}),
|
||||
},
|
||||
},
|
||||
{ provide: AccountService, useValue: mockAccountServiceWith("UserId" as UserId) },
|
||||
],
|
||||
});
|
||||
adminConsoleConfigService = TestBed.inject(AdminConsoleCipherFormConfigService);
|
||||
@@ -207,7 +200,7 @@ describe("AdminConsoleCipherFormConfigService", () => {
|
||||
await adminConsoleConfigService.buildConfig("edit", cipherId);
|
||||
|
||||
expect(getCipherAdmin).not.toHaveBeenCalled();
|
||||
expect(getCipher).toHaveBeenCalledWith(cipherId);
|
||||
expect(getCipher).toHaveBeenCalledWith(cipherId, "UserId");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import { PolicyService } from "@bitwarden/common/admin-console/abstractions/poli
|
||||
import { OrganizationUserStatusType, PolicyType } from "@bitwarden/common/admin-console/enums";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { CipherId } from "@bitwarden/common/types/guid";
|
||||
import { CipherId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
import { CipherData } from "@bitwarden/common/vault/models/data/cipher.data";
|
||||
@@ -100,7 +100,7 @@ export class AdminConsoleCipherFormConfigService implements CipherFormConfigServ
|
||||
return null;
|
||||
}
|
||||
|
||||
const localCipher = await this.cipherService.get(id);
|
||||
const localCipher = await this.cipherService.get(id, organization.userId as UserId);
|
||||
|
||||
// Fetch from the API because we don't need the permissions in local state OR the cipher was not found (e.g. unassigned)
|
||||
if (organization.canEditAllCiphers || localCipher == null) {
|
||||
|
||||
@@ -40,6 +40,7 @@ import { OrganizationApiServiceAbstraction } from "@bitwarden/common/admin-conso
|
||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||
import { OrganizationBillingServiceAbstraction } from "@bitwarden/common/billing/abstractions";
|
||||
import { BillingApiServiceAbstraction } from "@bitwarden/common/billing/abstractions/billing-api.service.abstraction";
|
||||
import { EventType } from "@bitwarden/common/enums";
|
||||
@@ -52,7 +53,7 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { SyncService } from "@bitwarden/common/platform/sync";
|
||||
import { CipherId, CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
|
||||
import { CipherId, CollectionId, OrganizationId, UserId } from "@bitwarden/common/types/guid";
|
||||
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
||||
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
|
||||
import { CipherType } from "@bitwarden/common/vault/enums";
|
||||
@@ -952,8 +953,9 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
|
||||
// Allow restore of an Unassigned Item
|
||||
try {
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
const asAdmin = this.organization?.canEditAnyCollection || c.isUnassigned;
|
||||
await this.cipherService.restoreWithServer(c.id, asAdmin);
|
||||
await this.cipherService.restoreWithServer(c.id, activeUserId, asAdmin);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
@@ -1044,7 +1046,8 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
try {
|
||||
await this.deleteCipherWithServer(c.id, permanent, c.isUnassigned);
|
||||
const activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||
await this.deleteCipherWithServer(c.id, activeUserId, permanent, c.isUnassigned);
|
||||
this.toastService.showToast({
|
||||
variant: "success",
|
||||
title: null,
|
||||
@@ -1332,11 +1335,16 @@ export class VaultComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
protected deleteCipherWithServer(id: string, permanent: boolean, isUnassigned: boolean) {
|
||||
protected deleteCipherWithServer(
|
||||
id: string,
|
||||
userId: UserId,
|
||||
permanent: boolean,
|
||||
isUnassigned: boolean,
|
||||
) {
|
||||
const asAdmin = this.organization?.canEditAllCiphers || isUnassigned;
|
||||
return permanent
|
||||
? this.cipherService.deleteWithServer(id, asAdmin)
|
||||
: this.cipherService.softDeleteWithServer(id, asAdmin);
|
||||
? this.cipherService.deleteWithServer(id, userId, asAdmin)
|
||||
: this.cipherService.softDeleteWithServer(id, userId, asAdmin);
|
||||
}
|
||||
|
||||
protected async repromptCipher(ciphers: CipherView[]) {
|
||||
|
||||
Reference in New Issue
Block a user