From 258475953914103690de6015bd6a9f7188134c3e Mon Sep 17 00:00:00 2001 From: gbubemismith Date: Wed, 6 Nov 2024 16:30:21 -0500 Subject: [PATCH] Update callers in libs --- .../src/services/jslib-services.module.ts | 2 +- .../vault/components/add-edit.component.ts | 12 ++++++---- .../components/folder-add-edit.component.ts | 9 +++++--- .../src/vault/components/view.component.ts | 4 +++- .../services/vault-filter.service.ts | 12 ++++++---- .../src/platform/sync/core-sync.service.ts | 23 +++++++++++++++---- .../vault-timeout.service.spec.ts | 2 +- .../vault-timeout/vault-timeout.service.ts | 2 +- .../folder/folder.service.abstraction.ts | 5 ++++ .../services/folder/folder-api.service.ts | 13 ++++++++--- .../src/components/import.component.ts | 9 +++++--- .../individual-vault-export.service.spec.ts | 10 ++++---- .../individual-vault-export.service.ts | 6 +++-- .../default-cipher-form-config.service.ts | 8 +++++-- .../src/cipher-view/cipher-view.component.ts | 8 +++++-- 15 files changed, 87 insertions(+), 38 deletions(-) diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 5d8822866d6..28a12c0fdc2 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -513,7 +513,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: FolderApiServiceAbstraction, useClass: FolderApiService, - deps: [InternalFolderService, ApiServiceAbstraction], + deps: [InternalFolderService, ApiServiceAbstraction, AccountServiceAbstraction], }), safeProvider({ provide: AccountApiServiceAbstraction, diff --git a/libs/angular/src/vault/components/add-edit.component.ts b/libs/angular/src/vault/components/add-edit.component.ts index 44eaec03a68..f009a170cf0 100644 --- a/libs/angular/src/vault/components/add-edit.component.ts +++ b/libs/angular/src/vault/components/add-edit.component.ts @@ -98,6 +98,8 @@ export class AddEditComponent implements OnInit, OnDestroy { private personalOwnershipPolicyAppliesToActiveUser: boolean; private previousCipherId: string; + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); + get fido2CredentialCreationDateValue(): string { const dateCreated = this.i18nService.t("dateCreated"); const creationDate = this.datePipe.transform( @@ -253,11 +255,11 @@ export class AddEditComponent implements OnInit, OnDestroy { if (this.cipher == null) { if (this.editMode) { const cipher = await this.loadCipher(); - const activeUserId = await firstValueFrom( - this.accountService.activeAccount$.pipe(map((a) => a?.id)), - ); this.cipher = await cipher.decrypt( - await this.cipherService.getKeyForCipherKeyDecryption(cipher, activeUserId), + await this.cipherService.getKeyForCipherKeyDecryption( + cipher, + await firstValueFrom(this.activeUserId$), + ), ); // Adjust Cipher Name if Cloning @@ -313,7 +315,7 @@ export class AddEditComponent implements OnInit, OnDestroy { this.cipher.login.fido2Credentials = null; } - this.folders$ = this.folderService.folderViews$; + this.folders$ = this.folderService.folderViews$(this.activeUserId$); if (this.editMode && this.previousCipherId !== this.cipherId) { void this.eventCollectionService.collectMany(EventType.Cipher_ClientViewed, [this.cipher]); diff --git a/libs/angular/src/vault/components/folder-add-edit.component.ts b/libs/angular/src/vault/components/folder-add-edit.component.ts index 71d7b32bafb..448209aa6f1 100644 --- a/libs/angular/src/vault/components/folder-add-edit.component.ts +++ b/libs/angular/src/vault/components/folder-add-edit.component.ts @@ -1,6 +1,6 @@ import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { Validators, FormBuilder } from "@angular/forms"; -import { firstValueFrom } from "rxjs"; +import { firstValueFrom, map } from "rxjs"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -25,6 +25,8 @@ export class FolderAddEditComponent implements OnInit { deletePromise: Promise; protected componentName = ""; + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); + formGroup = this.formBuilder.group({ name: ["", [Validators.required]], }); @@ -105,8 +107,9 @@ export class FolderAddEditComponent implements OnInit { if (this.editMode) { this.editMode = true; this.title = this.i18nService.t("editFolder"); - const folder = await this.folderService.get(this.folderId); - this.folder = await folder.decrypt(); + this.folder = await firstValueFrom( + this.folderService.getDecrypted$(this.folderId, this.activeUserId$), + ); } else { this.title = this.i18nService.t("addFolder"); } diff --git a/libs/angular/src/vault/components/view.component.ts b/libs/angular/src/vault/components/view.component.ts index c2666056705..19674586cc7 100644 --- a/libs/angular/src/vault/components/view.component.ts +++ b/libs/angular/src/vault/components/view.component.ts @@ -76,6 +76,8 @@ export class ViewComponent implements OnDestroy, OnInit { private previousCipherId: string; private passwordReprompted = false; + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); + get fido2CredentialCreationDateValue(): string { const dateCreated = this.i18nService.t("dateCreated"); const creationDate = this.datePipe.transform( @@ -155,7 +157,7 @@ export class ViewComponent implements OnDestroy, OnInit { if (this.cipher.folderId) { this.folder = await ( - await firstValueFrom(this.folderService.folderViews$) + await firstValueFrom(this.folderService.folderViews$(this.activeUserId$)) ).find((f) => f.id == this.cipher.folderId); } diff --git a/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts b/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts index 34310610ca3..2ecff42a7f2 100644 --- a/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts +++ b/libs/angular/src/vault/vault-filter/services/vault-filter.service.ts @@ -9,6 +9,7 @@ import { import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { 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 { ActiveUserState, StateProvider } from "@bitwarden/common/platform/state"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -30,6 +31,8 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti private readonly collapsedGroupings$: Observable> = this.collapsedGroupingsState.state$.pipe(map((c) => new Set(c))); + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); + constructor( protected organizationService: OrganizationService, protected folderService: FolderService, @@ -37,6 +40,7 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti protected collectionService: CollectionService, protected policyService: PolicyService, protected stateProvider: StateProvider, + protected accountService: AccountService, ) {} async storeCollapsedFilterNodes(collapsedFilterNodes: Set): Promise { @@ -79,9 +83,9 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti }); }; - return this.folderService.folderViews$.pipe( - mergeMap((folders) => from(transformation(folders))), - ); + return this.folderService + .folderViews$(this.activeUserId$) + .pipe(mergeMap((folders) => from(transformation(folders)))); } async buildCollections(organizationId?: string): Promise> { @@ -125,7 +129,7 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti async getFolderNested(id: string): Promise> { const folders = await this.getAllFoldersNested( - await firstValueFrom(this.folderService.folderViews$), + await firstValueFrom(this.folderService.folderViews$(this.activeUserId$)), ); return ServiceUtils.getTreeNodeObjectFromList(folders, id) as TreeNode; } diff --git a/libs/common/src/platform/sync/core-sync.service.ts b/libs/common/src/platform/sync/core-sync.service.ts index 13f1525afd4..7a3be90350a 100644 --- a/libs/common/src/platform/sync/core-sync.service.ts +++ b/libs/common/src/platform/sync/core-sync.service.ts @@ -37,6 +37,8 @@ const LAST_SYNC_DATE = new UserKeyDefinition(SYNC_DISK, "lastSync", { export abstract class CoreSyncService implements SyncService { syncInProgress = false; + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); + constructor( protected readonly stateService: StateService, protected readonly folderService: InternalFolderService, @@ -85,16 +87,23 @@ export abstract class CoreSyncService implements SyncService { async syncUpsertFolder(notification: SyncFolderNotification, isEdit: boolean): Promise { this.syncStarted(); - if (await this.stateService.getIsAuthenticated()) { + const authStatus = await firstValueFrom( + this.authService.authStatusFor$(await firstValueFrom(this.activeUserId$)), + ); + + if (authStatus >= AuthenticationStatus.Locked) { try { - const localFolder = await this.folderService.get(notification.id); + const localFolder = await this.folderService.get(notification.id, this.activeUserId$); if ( (!isEdit && localFolder == null) || (isEdit && localFolder != null && localFolder.revisionDate < notification.revisionDate) ) { const remoteFolder = await this.folderApiService.get(notification.id); if (remoteFolder != null) { - await this.folderService.upsert(new FolderData(remoteFolder)); + await this.folderService.upsert( + new FolderData(remoteFolder), + await firstValueFrom(this.activeUserId$), + ); this.messageSender.send("syncedUpsertedFolder", { folderId: notification.id }); return this.syncCompleted(true); } @@ -108,8 +117,12 @@ export abstract class CoreSyncService implements SyncService { async syncDeleteFolder(notification: SyncFolderNotification): Promise { this.syncStarted(); - if (await this.stateService.getIsAuthenticated()) { - await this.folderService.delete(notification.id); + const authStatus = await firstValueFrom( + this.authService.authStatusFor$(await firstValueFrom(this.activeUserId$)), + ); + + if (authStatus >= AuthenticationStatus.Locked) { + await this.folderService.delete(notification.id, await firstValueFrom(this.activeUserId$)); this.messageSender.send("syncedDeletedFolder", { folderId: notification.id }); this.syncCompleted(true); return true; diff --git a/libs/common/src/services/vault-timeout/vault-timeout.service.spec.ts b/libs/common/src/services/vault-timeout/vault-timeout.service.spec.ts index 71341a98a62..1350010f849 100644 --- a/libs/common/src/services/vault-timeout/vault-timeout.service.spec.ts +++ b/libs/common/src/services/vault-timeout/vault-timeout.service.spec.ts @@ -334,7 +334,7 @@ describe("VaultTimeoutService", () => { // Active users should have additional steps ran expect(searchService.clearIndex).toHaveBeenCalled(); - expect(folderService.clearCache).toHaveBeenCalled(); + expect(folderService.clearDecryptedFolderState).toHaveBeenCalled(); expectUserToHaveLoggedOut("3"); // They have chosen logout as their action and it's available, log them out expectUserToHaveLoggedOut("4"); // They may have had lock as their chosen action but it's not available to them so logout diff --git a/libs/common/src/services/vault-timeout/vault-timeout.service.ts b/libs/common/src/services/vault-timeout/vault-timeout.service.ts index 07c3cd56f18..57125973aba 100644 --- a/libs/common/src/services/vault-timeout/vault-timeout.service.ts +++ b/libs/common/src/services/vault-timeout/vault-timeout.service.ts @@ -133,10 +133,10 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction { if (userId == null || userId === currentUserId) { await this.searchService.clearIndex(); - await this.folderService.clearCache(); await this.collectionService.clearActiveUserCache(); } + await this.folderService.clearDecryptedFolderState(userId); await this.masterPasswordService.clearMasterKey(lockingUserId); await this.stateService.setUserKeyAutoUnlock(null, { userId: lockingUserId }); diff --git a/libs/common/src/vault/abstractions/folder/folder.service.abstraction.ts b/libs/common/src/vault/abstractions/folder/folder.service.abstraction.ts index 745ebb3b47d..8cb9a0b296b 100644 --- a/libs/common/src/vault/abstractions/folder/folder.service.abstraction.ts +++ b/libs/common/src/vault/abstractions/folder/folder.service.abstraction.ts @@ -18,6 +18,11 @@ export abstract class FolderService implements UserKeyRotationDataProvider Promise; get: (id: string, userId$: Observable) => Promise; getDecrypted$: (id: string, userId$: Observable) => Observable; + /** + * @deprecated Use firstValueFrom(folders$) directly instead + * @param userId$ The observable of user ID + * @returns Promise of folders array + */ getAllFromState: (userId$: Observable) => Promise; /** * @deprecated Only use in CLI! diff --git a/libs/common/src/vault/services/folder/folder-api.service.ts b/libs/common/src/vault/services/folder/folder-api.service.ts index e46df37c176..84bfa7a60e4 100644 --- a/libs/common/src/vault/services/folder/folder-api.service.ts +++ b/libs/common/src/vault/services/folder/folder-api.service.ts @@ -1,3 +1,7 @@ +import { firstValueFrom, map } from "rxjs"; + +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; + import { ApiService } from "../../../abstractions/api.service"; import { FolderApiServiceAbstraction } from "../../../vault/abstractions/folder/folder-api.service.abstraction"; import { InternalFolderService } from "../../../vault/abstractions/folder/folder.service.abstraction"; @@ -7,9 +11,12 @@ import { FolderRequest } from "../../../vault/models/request/folder.request"; import { FolderResponse } from "../../../vault/models/response/folder.response"; export class FolderApiService implements FolderApiServiceAbstraction { + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); + constructor( private folderService: InternalFolderService, private apiService: ApiService, + private accountService: AccountService, ) {} async save(folder: Folder): Promise { @@ -24,17 +31,17 @@ export class FolderApiService implements FolderApiServiceAbstraction { } const data = new FolderData(response); - await this.folderService.upsert(data); + await this.folderService.upsert(data, await firstValueFrom(this.activeUserId$)); } async delete(id: string): Promise { await this.deleteFolder(id); - await this.folderService.delete(id); + await this.folderService.delete(id, await firstValueFrom(this.activeUserId$)); } async deleteAll(): Promise { await this.apiService.send("DELETE", "/folders/all", null, true, false); - await this.folderService.clear(); + await this.folderService.clear(await firstValueFrom(this.activeUserId$)); } async get(id: string): Promise { diff --git a/libs/importer/src/components/import.component.ts b/libs/importer/src/components/import.component.ts index 1ffe2728b05..e746460b153 100644 --- a/libs/importer/src/components/import.component.ts +++ b/libs/importer/src/components/import.component.ts @@ -152,6 +152,8 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { private _importBlockedByPolicy = false; protected isFromAC = false; + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); + formGroup = this.formBuilder.group({ vaultSelector: [ "myVault", @@ -205,6 +207,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { @Optional() protected importCollectionService: ImportCollectionServiceAbstraction, protected toastService: ToastService, + protected accountService: AccountService, ) {} protected get importBlockedByPolicy(): boolean { @@ -256,9 +259,9 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit { private handleImportInit() { // Filter out the no folder-item from folderViews$ - this.folders$ = this.folderService.folderViews$.pipe( - map((folders) => folders.filter((f) => f.id != null)), - ); + this.folders$ = this.folderService + .folderViews$(this.activeUserId$) + .pipe(map((folders) => folders.filter((f) => f.id != null))); this.formGroup.controls.targetSelector.disable(); diff --git a/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.spec.ts b/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.spec.ts index d264991ae40..aaddc1b2cae 100644 --- a/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.spec.ts +++ b/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.spec.ts @@ -1,5 +1,5 @@ import { mock, MockProxy } from "jest-mock-extended"; -import { BehaviorSubject } from "rxjs"; +import { BehaviorSubject, of } from "rxjs"; import { PinServiceAbstraction } from "@bitwarden/auth/common"; import { AccountInfo, AccountService } from "@bitwarden/common/auth/abstractions/account.service"; @@ -178,8 +178,8 @@ describe("VaultExportService", () => { const activeAccount = { id: userId, ...accountInfo }; accountService.activeAccount$ = new BehaviorSubject(activeAccount); - folderService.getAllDecryptedFromState.mockResolvedValue(UserFolderViews); - folderService.getAllFromState.mockResolvedValue(UserFolders); + folderService.folderViews$.mockReturnValue(of(UserFolderViews)); + folderService.folders$.mockReturnValue(of(UserFolders)); kdfConfigService.getKdfConfig.mockResolvedValue(DEFAULT_KDF_CONFIG); encryptService.encrypt.mockResolvedValue(new EncString("encrypted")); @@ -295,7 +295,7 @@ describe("VaultExportService", () => { it("exported unencrypted object contains folders", async () => { cipherService.getAllDecrypted.mockResolvedValue(UserCipherViews.slice(0, 1)); - await folderService.getAllDecryptedFromState(); + folderService.folderViews$.mockReturnValue(of(UserFolderViews)); const actual = await exportService.getExport("json"); expectEqualFolderViews(UserFolderViews, actual); @@ -303,7 +303,7 @@ describe("VaultExportService", () => { it("exported encrypted json contains folders", async () => { cipherService.getAll.mockResolvedValue(UserCipherDomains.slice(0, 1)); - await folderService.getAllFromState(); + folderService.folders$.mockReturnValue(of(UserFolders)); const actual = await exportService.getExport("encrypted_json"); expectEqualFolders(UserFolders, actual); diff --git a/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.ts b/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.ts index 04dba1299d7..d55e43cb9a3 100644 --- a/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.ts +++ b/libs/tools/export/vault-export/vault-export-core/src/services/individual-vault-export.service.ts @@ -31,6 +31,8 @@ export class IndividualVaultExportService extends BaseVaultExportService implements IndividualVaultExportServiceAbstraction { + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); + constructor( private folderService: FolderService, private cipherService: CipherService, @@ -62,7 +64,7 @@ export class IndividualVaultExportService const promises = []; promises.push( - this.folderService.getAllDecryptedFromState().then((folders) => { + firstValueFrom(this.folderService.folderViews$(this.activeUserId$)).then((folders) => { decFolders = folders; }), ); @@ -88,7 +90,7 @@ export class IndividualVaultExportService const promises = []; promises.push( - this.folderService.getAllFromState().then((f) => { + firstValueFrom(this.folderService.folders$(this.activeUserId$)).then((f) => { folders = f; }), ); diff --git a/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts b/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts index 6b607e3048b..d77e06b13c8 100644 --- a/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts +++ b/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts @@ -5,6 +5,7 @@ import { CollectionService } from "@bitwarden/admin-console/common"; 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 { OrganizationUserStatusType, PolicyType } from "@bitwarden/common/admin-console/enums"; +import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { CipherId } from "@bitwarden/common/types/guid"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -29,6 +30,9 @@ export class DefaultCipherFormConfigService implements CipherFormConfigService { private cipherService: CipherService = inject(CipherService); private folderService: FolderService = inject(FolderService); private collectionService: CollectionService = inject(CollectionService); + private accountService = inject(AccountService); + + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); async buildConfig( mode: CipherFormMode, @@ -47,9 +51,9 @@ export class DefaultCipherFormConfigService implements CipherFormConfigService { ), ), this.allowPersonalOwnership$, - this.folderService.folders$.pipe( + this.folderService.folders$(this.activeUserId$).pipe( switchMap((f) => - this.folderService.folderViews$.pipe( + this.folderService.folderViews$(this.activeUserId$).pipe( filter((d) => d.length - 1 === f.length), // -1 for "No Folder" in folderViews$ ), ), diff --git a/libs/vault/src/cipher-view/cipher-view.component.ts b/libs/vault/src/cipher-view/cipher-view.component.ts index 324b2358a8c..0d544db4dfa 100644 --- a/libs/vault/src/cipher-view/cipher-view.component.ts +++ b/libs/vault/src/cipher-view/cipher-view.component.ts @@ -1,11 +1,12 @@ import { CommonModule } from "@angular/common"; import { Component, Input, OnChanges, OnDestroy } from "@angular/core"; -import { firstValueFrom, Observable, Subject, takeUntil } from "rxjs"; +import { firstValueFrom, map, Observable, Subject, takeUntil } from "rxjs"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; import { JslibModule } from "@bitwarden/angular/jslib.module"; 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 { isCardExpired } from "@bitwarden/common/autofill/utils"; import { CollectionId } from "@bitwarden/common/types/guid"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; @@ -46,6 +47,8 @@ import { ViewIdentitySectionsComponent } from "./view-identity-sections/view-ide export class CipherViewComponent implements OnChanges, OnDestroy { @Input({ required: true }) cipher: CipherView; + private activeUserId$ = this.accountService.activeAccount$.pipe(map((a) => a?.id)); + /** * Optional list of collections the cipher is assigned to. If none are provided, they will be fetched using the * `CipherService` and the `collectionIds` property of the cipher. @@ -60,6 +63,7 @@ export class CipherViewComponent implements OnChanges, OnDestroy { private organizationService: OrganizationService, private collectionService: CollectionService, private folderService: FolderService, + private accountService: AccountService, ) {} async ngOnChanges() { @@ -112,7 +116,7 @@ export class CipherViewComponent implements OnChanges, OnDestroy { if (this.cipher.folderId) { this.folder$ = this.folderService - .getDecrypted$(this.cipher.folderId) + .getDecrypted$(this.cipher.folderId, this.activeUserId$) .pipe(takeUntil(this.destroyed$)); } }