1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-10-28 07:49:41 +01:00

WIP updating callers

This commit is contained in:
Thomas Rittson 2024-10-28 11:06:27 +10:00
parent 902f49eb00
commit 5b0003b467
No known key found for this signature in database
GPG Key ID: CDDDA03861C35E27
20 changed files with 173 additions and 74 deletions

View File

@ -8,6 +8,7 @@ import { Observable, combineLatest, first, map, switchMap } from "rxjs";
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";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { OrganizationId } from "@bitwarden/common/types/guid"; import { OrganizationId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
@ -49,6 +50,8 @@ export class AssignCollections {
/** Params needed to populate the assign collections component */ /** Params needed to populate the assign collections component */
params: CollectionAssignmentParams; params: CollectionAssignmentParams;
private activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
constructor( constructor(
private location: Location, private location: Location,
private collectionService: CollectionService, private collectionService: CollectionService,
@ -70,7 +73,7 @@ export class AssignCollections {
), ),
); );
combineLatest([cipher$, this.collectionService.decryptedCollections$]) combineLatest([cipher$, this.collectionService.decryptedCollections$(this.activeUserId$)])
.pipe(takeUntilDestroyed(), first()) .pipe(takeUntilDestroyed(), first())
.subscribe(([cipherView, collections]) => { .subscribe(([cipherView, collections]) => {
let availableCollections = collections.filter((c) => !c.readOnly); let availableCollections = collections.filter((c) => !c.readOnly);

View File

@ -22,6 +22,9 @@ import { BrowserApi } from "../../../../platform/browser/browser-api";
import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils"; import BrowserPopupUtils from "../../../../platform/popup/browser-popup-utils";
import { VaultBrowserStateService } from "../../../services/vault-browser-state.service"; import { VaultBrowserStateService } from "../../../services/vault-browser-state.service";
import { VaultFilterService } from "../../../services/vault-filter.service"; import { VaultFilterService } from "../../../services/vault-filter.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { firstValueFrom } from "rxjs";
const ComponentId = "VaultItemsComponent"; const ComponentId = "VaultItemsComponent";
@ -49,6 +52,8 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn
private applySavedState = true; private applySavedState = true;
private scrollingContainer = "cdk-virtual-scroll-viewport"; private scrollingContainer = "cdk-virtual-scroll-viewport";
private activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
constructor( constructor(
searchService: SearchService, searchService: SearchService,
private organizationService: OrganizationService, private organizationService: OrganizationService,
@ -64,6 +69,7 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn
private platformUtilsService: PlatformUtilsService, private platformUtilsService: PlatformUtilsService,
cipherService: CipherService, cipherService: CipherService,
private vaultFilterService: VaultFilterService, private vaultFilterService: VaultFilterService,
private accountService: AccountService,
) { ) {
super(searchService, cipherService); super(searchService, cipherService);
this.applySavedState = this.applySavedState =
@ -133,7 +139,10 @@ export class VaultItemsComponent extends BaseVaultItemsComponent implements OnIn
this.showVaultFilter = false; this.showVaultFilter = false;
this.collectionId = params.collectionId; this.collectionId = params.collectionId;
this.searchPlaceholder = this.i18nService.t("searchCollection"); this.searchPlaceholder = this.i18nService.t("searchCollection");
const collectionNode = await this.collectionService.getNested(this.collectionId); const allCollections = await firstValueFrom(
this.collectionService.decryptedCollections$(this.activeUserId$),
);
const collectionNode = this.collectionService.getNested(allCollections, this.collectionId);
if (collectionNode != null && collectionNode.node != null) { if (collectionNode != null && collectionNode.node != null) {
this.groupingTitle = collectionNode.node.name; this.groupingTitle = collectionNode.node.name;
this.nestedCollections = this.nestedCollections =

View File

@ -8,8 +8,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { ProductTierType } from "@bitwarden/common/billing/enums"; import { ProductTierType } from "@bitwarden/common/billing/enums";
import { SyncService } from "@bitwarden/common/platform/sync"; import { SyncService } from "@bitwarden/common/platform/sync";
import { ObservableTracker } from "@bitwarden/common/spec"; import { mockAccountServiceWith, ObservableTracker } from "@bitwarden/common/spec";
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 { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service"; import { VaultSettingsService } from "@bitwarden/common/vault/abstractions/vault-settings/vault-settings.service";
import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherType } from "@bitwarden/common/vault/enums";
@ -20,6 +20,7 @@ import { BrowserApi } from "../../../platform/browser/browser-api";
import { VaultPopupAutofillService } from "./vault-popup-autofill.service"; import { VaultPopupAutofillService } from "./vault-popup-autofill.service";
import { VaultPopupItemsService } from "./vault-popup-items.service"; import { VaultPopupItemsService } from "./vault-popup-items.service";
import { VaultPopupListFiltersService } from "./vault-popup-list-filters.service"; import { VaultPopupListFiltersService } from "./vault-popup-list-filters.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
describe("VaultPopupItemsService", () => { describe("VaultPopupItemsService", () => {
let testBed: TestBed; let testBed: TestBed;
@ -39,6 +40,7 @@ describe("VaultPopupItemsService", () => {
const collectionService = mock<CollectionService>(); const collectionService = mock<CollectionService>();
const vaultAutofillServiceMock = mock<VaultPopupAutofillService>(); const vaultAutofillServiceMock = mock<VaultPopupAutofillService>();
const syncServiceMock = mock<SyncService>(); const syncServiceMock = mock<SyncService>();
const accountServiceMock = mockAccountServiceWith("UserId" as UserId);
beforeEach(() => { beforeEach(() => {
allCiphers = cipherFactory(10); allCiphers = cipherFactory(10);
@ -90,7 +92,7 @@ describe("VaultPopupItemsService", () => {
]; ];
organizationServiceMock.organizations$ = new BehaviorSubject([mockOrg]); organizationServiceMock.organizations$ = new BehaviorSubject([mockOrg]);
collectionService.decryptedCollections$ = new BehaviorSubject(mockCollections); collectionService.decryptedCollections$.mockReturnValue(new BehaviorSubject(mockCollections));
activeUserLastSync$ = new BehaviorSubject(new Date()); activeUserLastSync$ = new BehaviorSubject(new Date());
syncServiceMock.activeUserLastSync$.mockReturnValue(activeUserLastSync$); syncServiceMock.activeUserLastSync$.mockReturnValue(activeUserLastSync$);
@ -105,6 +107,7 @@ describe("VaultPopupItemsService", () => {
{ provide: CollectionService, useValue: collectionService }, { provide: CollectionService, useValue: collectionService },
{ provide: VaultPopupAutofillService, useValue: vaultAutofillServiceMock }, { provide: VaultPopupAutofillService, useValue: vaultAutofillServiceMock },
{ provide: SyncService, useValue: syncServiceMock }, { provide: SyncService, useValue: syncServiceMock },
{ provide: AccountService, useValue: accountServiceMock },
], ],
}); });

View File

@ -36,6 +36,8 @@ import { PopupCipherView } from "../views/popup-cipher.view";
import { VaultPopupAutofillService } from "./vault-popup-autofill.service"; import { VaultPopupAutofillService } from "./vault-popup-autofill.service";
import { MY_VAULT_ID, VaultPopupListFiltersService } from "./vault-popup-list-filters.service"; import { MY_VAULT_ID, VaultPopupListFiltersService } from "./vault-popup-list-filters.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
/** /**
* Service for managing the various item lists on the new Vault tab in the browser popup. * Service for managing the various item lists on the new Vault tab in the browser popup.
@ -45,6 +47,7 @@ import { MY_VAULT_ID, VaultPopupListFiltersService } from "./vault-popup-list-fi
}) })
export class VaultPopupItemsService { export class VaultPopupItemsService {
private _searchText$ = new BehaviorSubject<string>(""); private _searchText$ = new BehaviorSubject<string>("");
private activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
/** /**
* Subject that emits whenever new ciphers are being processed/filtered. * Subject that emits whenever new ciphers are being processed/filtered.
@ -90,7 +93,7 @@ export class VaultPopupItemsService {
switchMap((ciphers) => switchMap((ciphers) =>
combineLatest([ combineLatest([
this.organizationService.organizations$, this.organizationService.organizations$,
this.collectionService.decryptedCollections$, this.collectionService.decryptedCollections$(this.activeUserId$),
]).pipe( ]).pipe(
map(([organizations, collections]) => { map(([organizations, collections]) => {
const orgMap = Object.fromEntries(organizations.map((org) => [org.id, org])); const orgMap = Object.fromEntries(organizations.map((org) => [org.id, org]));
@ -260,6 +263,7 @@ export class VaultPopupItemsService {
private collectionService: CollectionService, private collectionService: CollectionService,
private vaultPopupAutofillService: VaultPopupAutofillService, private vaultPopupAutofillService: VaultPopupAutofillService,
private syncService: SyncService, private syncService: SyncService,
private accountService: AccountService,
) {} ) {}
applyFilter(newSearchText: string) { applyFilter(newSearchText: string) {

View File

@ -7,11 +7,15 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { ProductTierType } from "@bitwarden/common/billing/enums"; import { ProductTierType } from "@bitwarden/common/billing/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { mockAccountServiceWith } from "@bitwarden/common/spec";
import { UserId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherType } from "@bitwarden/common/vault/enums"; import { CipherType } from "@bitwarden/common/vault/enums";
import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
@ -26,8 +30,8 @@ describe("VaultPopupListFiltersService", () => {
const policyAppliesToActiveUser$ = new BehaviorSubject<boolean>(false); const policyAppliesToActiveUser$ = new BehaviorSubject<boolean>(false);
const collectionService = { const collectionService = {
decryptedCollections$, decryptedCollections$: () => decryptedCollections$,
getAllNested: () => Promise.resolve([]), getAllNested: () => [] as TreeNode<CollectionView>[],
} as unknown as CollectionService; } as unknown as CollectionService;
const folderService = { const folderService = {
@ -50,13 +54,15 @@ describe("VaultPopupListFiltersService", () => {
policyAppliesToActiveUser$: jest.fn(() => policyAppliesToActiveUser$), policyAppliesToActiveUser$: jest.fn(() => policyAppliesToActiveUser$),
}; };
const accountService = mockAccountServiceWith("userId" as UserId);
beforeEach(() => { beforeEach(() => {
memberOrganizations$.next([]); memberOrganizations$.next([]);
decryptedCollections$.next([]); decryptedCollections$.next([]);
policyAppliesToActiveUser$.next(false); policyAppliesToActiveUser$.next(false);
policyService.policyAppliesToActiveUser$.mockClear(); policyService.policyAppliesToActiveUser$.mockClear();
collectionService.getAllNested = () => Promise.resolve([]); collectionService.getAllNested = () => [] as TreeNode<CollectionView>[];
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [ providers: [
{ {
@ -84,6 +90,10 @@ describe("VaultPopupListFiltersService", () => {
useValue: policyService, useValue: policyService,
}, },
{ provide: FormBuilder, useClass: FormBuilder }, { provide: FormBuilder, useClass: FormBuilder },
{
provide: AccountService,
useValue: accountService,
},
], ],
}); });
@ -276,13 +286,11 @@ describe("VaultPopupListFiltersService", () => {
decryptedCollections$.next(testCollections); decryptedCollections$.next(testCollections);
collectionService.getAllNested = () => collectionService.getAllNested = () =>
Promise.resolve(
testCollections.map((c) => ({ testCollections.map((c) => ({
children: [], children: [],
node: c, node: c,
parent: null, parent: null,
})), }));
);
}); });
it("returns all collections", (done) => { it("returns all collections", (done) => {

View File

@ -1,15 +1,7 @@
import { Injectable } from "@angular/core"; import { Injectable } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop"; import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { FormBuilder } from "@angular/forms"; import { FormBuilder } from "@angular/forms";
import { import { combineLatest, distinctUntilChanged, map, Observable, startWith, tap } from "rxjs";
combineLatest,
distinctUntilChanged,
map,
Observable,
startWith,
switchMap,
tap,
} from "rxjs";
import { CollectionService, Collection, CollectionView } from "@bitwarden/admin-console/common"; import { CollectionService, Collection, CollectionView } from "@bitwarden/admin-console/common";
import { DynamicTreeNode } from "@bitwarden/angular/vault/vault-filter/models/dynamic-tree-node.model"; import { DynamicTreeNode } from "@bitwarden/angular/vault/vault-filter/models/dynamic-tree-node.model";
@ -17,6 +9,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; 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 { ProductTierType } from "@bitwarden/common/billing/enums"; import { ProductTierType } from "@bitwarden/common/billing/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { Utils } from "@bitwarden/common/platform/misc/utils"; import { Utils } from "@bitwarden/common/platform/misc/utils";
@ -81,6 +75,8 @@ export class VaultPopupListFiltersService {
map((ciphers) => Object.values(ciphers)), map((ciphers) => Object.values(ciphers)),
); );
private activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
constructor( constructor(
private folderService: FolderService, private folderService: FolderService,
private cipherService: CipherService, private cipherService: CipherService,
@ -89,6 +85,7 @@ export class VaultPopupListFiltersService {
private collectionService: CollectionService, private collectionService: CollectionService,
private formBuilder: FormBuilder, private formBuilder: FormBuilder,
private policyService: PolicyService, private policyService: PolicyService,
private accountService: AccountService,
) { ) {
this.filterForm.controls.organization.valueChanges this.filterForm.controls.organization.valueChanges
.pipe(takeUntilDestroyed()) .pipe(takeUntilDestroyed())
@ -302,7 +299,7 @@ export class VaultPopupListFiltersService {
previousFilter.organization?.id === currentFilter.organization?.id, previousFilter.organization?.id === currentFilter.organization?.id,
), ),
), ),
this.collectionService.decryptedCollections$, this.collectionService.decryptedCollections$(this.activeUserId$),
]).pipe( ]).pipe(
map(([filters, allCollections]) => { map(([filters, allCollections]) => {
const organizationId = filters.organization?.id ?? null; const organizationId = filters.organization?.id ?? null;
@ -314,8 +311,8 @@ export class VaultPopupListFiltersService {
return collections; return collections;
}), }),
switchMap(async (collections) => { map((collections) => {
const nestedCollections = await this.collectionService.getAllNested(collections); const nestedCollections = this.collectionService.getAllNested(collections);
return new DynamicTreeNode<CollectionView>({ return new DynamicTreeNode<CollectionView>({
fullList: collections, fullList: collections,

View File

@ -22,7 +22,7 @@ export class VaultFilterService extends BaseVaultFilterService {
collectionService: CollectionService, collectionService: CollectionService,
policyService: PolicyService, policyService: PolicyService,
stateProvider: StateProvider, stateProvider: StateProvider,
private accountService: AccountService, accountService: AccountService,
) { ) {
super( super(
organizationService, organizationService,
@ -31,6 +31,7 @@ export class VaultFilterService extends BaseVaultFilterService {
collectionService, collectionService,
policyService, policyService,
stateProvider, stateProvider,
accountService,
); );
this.vaultFilter.myVaultOnly = false; this.vaultFilter.myVaultOnly = false;
this.vaultFilter.selectedOrganizationId = null; this.vaultFilter.selectedOrganizationId = null;

View File

@ -1,10 +1,11 @@
import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core"; import { Directive, EventEmitter, Input, OnInit, Output } from "@angular/core";
import { firstValueFrom, map } from "rxjs"; import { firstValueFrom } from "rxjs";
import { CollectionService, CollectionView } from "@bitwarden/admin-console/common"; import { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; 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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@ -25,6 +26,8 @@ export class CollectionsComponent implements OnInit {
collections: CollectionView[] = []; collections: CollectionView[] = [];
organization: Organization; organization: Organization;
protected activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
protected cipherDomain: Cipher; protected cipherDomain: Cipher;
constructor( constructor(
@ -45,9 +48,7 @@ export class CollectionsComponent implements OnInit {
async load() { async load() {
this.cipherDomain = await this.loadCipher(); this.cipherDomain = await this.loadCipher();
this.collectionIds = this.loadCipherCollections(); this.collectionIds = this.loadCipherCollections();
const activeUserId = await firstValueFrom( const activeUserId = await firstValueFrom(this.activeUserId$);
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
this.cipher = await this.cipherDomain.decrypt( this.cipher = await this.cipherDomain.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(this.cipherDomain, activeUserId), await this.cipherService.getKeyForCipherKeyDecryption(this.cipherDomain, activeUserId),
); );
@ -113,7 +114,9 @@ export class CollectionsComponent implements OnInit {
} }
protected async loadCollections() { protected async loadCollections() {
const allCollections = await this.collectionService.getAllDecrypted(); const allCollections = await firstValueFrom(
this.collectionService.decryptedCollections$(this.activeUserId$),
);
return allCollections.filter( return allCollections.filter(
(c) => !c.readOnly && c.organizationId === this.cipher.organizationId, (c) => !c.readOnly && c.organizationId === this.cipher.organizationId,
); );

View File

@ -6,6 +6,7 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums"; import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; 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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
@ -26,6 +27,7 @@ export class ShareComponent implements OnInit, OnDestroy {
organizations$: Observable<Organization[]>; organizations$: Observable<Organization[]>;
protected writeableCollections: Checkable<CollectionView>[] = []; protected writeableCollections: Checkable<CollectionView>[] = [];
protected activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
private _destroy = new Subject<void>(); private _destroy = new Subject<void>();
@ -49,7 +51,9 @@ export class ShareComponent implements OnInit, OnDestroy {
} }
async load() { async load() {
const allCollections = await this.collectionService.getAllDecrypted(); const allCollections = await firstValueFrom(
this.collectionService.decryptedCollections$(this.activeUserId$),
);
this.writeableCollections = allCollections.map((c) => c).filter((c) => !c.readOnly); this.writeableCollections = allCollections.map((c) => c).filter((c) => !c.readOnly);
this.organizations$ = this.organizationService.memberOrganizations$.pipe( this.organizations$ = this.organizationService.memberOrganizations$.pipe(

View File

@ -39,6 +39,7 @@ import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note.
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
import { DialogService } from "@bitwarden/components"; import { DialogService } from "@bitwarden/components";
import { PasswordRepromptService } from "@bitwarden/vault"; import { PasswordRepromptService } from "@bitwarden/vault";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
@Directive() @Directive()
export class AddEditComponent implements OnInit, OnDestroy { export class AddEditComponent implements OnInit, OnDestroy {
@ -98,6 +99,8 @@ export class AddEditComponent implements OnInit, OnDestroy {
private personalOwnershipPolicyAppliesToActiveUser: boolean; private personalOwnershipPolicyAppliesToActiveUser: boolean;
private previousCipherId: string; private previousCipherId: string;
protected activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
get fido2CredentialCreationDateValue(): string { get fido2CredentialCreationDateValue(): string {
const dateCreated = this.i18nService.t("dateCreated"); const dateCreated = this.i18nService.t("dateCreated");
const creationDate = this.datePipe.transform( const creationDate = this.datePipe.transform(
@ -253,9 +256,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
if (this.cipher == null) { if (this.cipher == null) {
if (this.editMode) { if (this.editMode) {
const cipher = await this.loadCipher(); const cipher = await this.loadCipher();
const activeUserId = await firstValueFrom( const activeUserId = await firstValueFrom(this.activeUserId$);
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
this.cipher = await cipher.decrypt( this.cipher = await cipher.decrypt(
await this.cipherService.getKeyForCipherKeyDecryption(cipher, activeUserId), await this.cipherService.getKeyForCipherKeyDecryption(cipher, activeUserId),
); );
@ -391,9 +392,7 @@ export class AddEditComponent implements OnInit, OnDestroy {
this.cipher.id = null; this.cipher.id = null;
} }
const activeUserId = await firstValueFrom( const activeUserId = await firstValueFrom(this.activeUserId$);
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const cipher = await this.encryptCipher(activeUserId); const cipher = await this.encryptCipher(activeUserId);
try { try {
this.formPromise = this.saveCipher(cipher); this.formPromise = this.saveCipher(cipher);
@ -672,7 +671,9 @@ export class AddEditComponent implements OnInit, OnDestroy {
} }
protected async loadCollections() { protected async loadCollections() {
const allCollections = await this.collectionService.getAllDecrypted(); const allCollections = await firstValueFrom(
this.collectionService.decryptedCollections$(this.activeUserId$),
);
return allCollections.filter((c) => !c.readOnly); return allCollections.filter((c) => !c.readOnly);
} }

View File

@ -9,6 +9,8 @@ import {
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; 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 { ActiveUserState, StateProvider } from "@bitwarden/common/platform/state"; import { ActiveUserState, StateProvider } from "@bitwarden/common/platform/state";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
@ -30,6 +32,8 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti
private readonly collapsedGroupings$: Observable<Set<string>> = private readonly collapsedGroupings$: Observable<Set<string>> =
this.collapsedGroupingsState.state$.pipe(map((c) => new Set(c))); this.collapsedGroupingsState.state$.pipe(map((c) => new Set(c)));
protected activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
constructor( constructor(
protected organizationService: OrganizationService, protected organizationService: OrganizationService,
protected folderService: FolderService, protected folderService: FolderService,
@ -37,6 +41,7 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti
protected collectionService: CollectionService, protected collectionService: CollectionService,
protected policyService: PolicyService, protected policyService: PolicyService,
protected stateProvider: StateProvider, protected stateProvider: StateProvider,
protected accountService: AccountService,
) {} ) {}
async storeCollapsedFilterNodes(collapsedFilterNodes: Set<string>): Promise<void> { async storeCollapsedFilterNodes(collapsedFilterNodes: Set<string>): Promise<void> {
@ -85,14 +90,16 @@ export class VaultFilterService implements DeprecatedVaultFilterServiceAbstracti
} }
async buildCollections(organizationId?: string): Promise<DynamicTreeNode<CollectionView>> { async buildCollections(organizationId?: string): Promise<DynamicTreeNode<CollectionView>> {
const storedCollections = await this.collectionService.getAllDecrypted(); const storedCollections = await firstValueFrom(
this.collectionService.decryptedCollections$(this.activeUserId$),
);
let collections: CollectionView[]; let collections: CollectionView[];
if (organizationId != null) { if (organizationId != null) {
collections = storedCollections.filter((c) => c.organizationId === organizationId); collections = storedCollections.filter((c) => c.organizationId === organizationId);
} else { } else {
collections = storedCollections; collections = storedCollections;
} }
const nestedCollections = await this.collectionService.getAllNested(collections); const nestedCollections = this.collectionService.getAllNested(collections);
return new DynamicTreeNode<CollectionView>({ return new DynamicTreeNode<CollectionView>({
fullList: collections, fullList: collections,
nestedList: nestedCollections, nestedList: nestedCollections,

View File

@ -45,6 +45,24 @@ const LOGGED_OUT_INFO: AccountInfo = {
name: undefined, name: undefined,
}; };
/**
* An rxjs map operator that extracts the UserId from an account, or throws if the account or UserId are null.
*/
export const getUserId = map<{ id: UserId | undefined }, UserId>((account) => {
if (account?.id == null) {
throw new Error("Null account or account ID");
}
return account.id;
});
/**
* An rxjs map operator that extracts the UserId from an account, or returns undefined if the account or UserId are null.
*/
export const getOptionalUserId = map<{ id: UserId | undefined }, UserId | undefined>(
(account) => account?.id ?? undefined,
);
export class AccountServiceImplementation implements InternalAccountService { export class AccountServiceImplementation implements InternalAccountService {
private accountsState: GlobalState<Record<UserId, AccountInfo>>; private accountsState: GlobalState<Record<UserId, AccountInfo>>;
private activeAccountIdState: GlobalState<UserId | undefined>; private activeAccountIdState: GlobalState<UserId | undefined>;

View File

@ -6,6 +6,7 @@ import { ApiService } from "../../abstractions/api.service";
import { AccountService } from "../../auth/abstractions/account.service"; import { AccountService } from "../../auth/abstractions/account.service";
import { AuthService } from "../../auth/abstractions/auth.service"; import { AuthService } from "../../auth/abstractions/auth.service";
import { AuthenticationStatus } from "../../auth/enums/authentication-status"; import { AuthenticationStatus } from "../../auth/enums/authentication-status";
import { getUserId } from "../../auth/services/account.service";
import { import {
SyncCipherNotification, SyncCipherNotification,
SyncFolderNotification, SyncFolderNotification,
@ -149,7 +150,10 @@ export abstract class CoreSyncService implements SyncService {
notification.collectionIds != null && notification.collectionIds != null &&
notification.collectionIds.length > 0 notification.collectionIds.length > 0
) { ) {
const collections = await this.collectionService.getAll(); const activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
const collections = await firstValueFrom(
this.collectionService.encryptedCollections$(activeUserId$),
);
if (collections != null) { if (collections != null) {
for (let i = 0; i < collections.length; i++) { for (let i = 0; i < collections.length; i++) {
if (notification.collectionIds.indexOf(collections[i].id) > -1) { if (notification.collectionIds.indexOf(collections[i].id) > -1) {

View File

@ -134,9 +134,13 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
if (userId == null || userId === currentUserId) { if (userId == null || userId === currentUserId) {
await this.searchService.clearIndex(); await this.searchService.clearIndex();
await this.folderService.clearCache(); await this.folderService.clearCache();
await this.collectionService.clearActiveUserCache();
} }
// TODO: is the userId ever null here? Surely a null userId cannot be authenticated?
// Also MasterPasswordService throws an exception if the userId is null and hasn't caused any issues
// TODO: why do these other services clear lockingUserId and not userId?
await this.collectionService.clearDecryptedState(userId);
await this.masterPasswordService.clearMasterKey(lockingUserId); await this.masterPasswordService.clearMasterKey(lockingUserId);
await this.stateService.setUserKeyAutoUnlock(null, { userId: lockingUserId }); await this.stateService.setUserKeyAutoUnlock(null, { userId: lockingUserId });

View File

@ -72,6 +72,7 @@ import {
ImportSuccessDialogComponent, ImportSuccessDialogComponent,
} from "./dialog"; } from "./dialog";
import { ImportLastPassComponent } from "./lastpass"; import { ImportLastPassComponent } from "./lastpass";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
const safeProviders: SafeProvider[] = [ const safeProviders: SafeProvider[] = [
safeProvider({ safeProvider({
@ -129,6 +130,8 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit {
collections$: Observable<CollectionView[]>; collections$: Observable<CollectionView[]>;
organizations$: Observable<Organization[]>; organizations$: Observable<Organization[]>;
protected activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
private _organizationId: string; private _organizationId: string;
get organizationId(): string { get organizationId(): string {
@ -205,6 +208,7 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit {
@Optional() @Optional()
protected importCollectionService: ImportCollectionServiceAbstraction, protected importCollectionService: ImportCollectionServiceAbstraction,
protected toastService: ToastService, protected toastService: ToastService,
protected accountService: AccountService,
) {} ) {}
protected get importBlockedByPolicy(): boolean { protected get importBlockedByPolicy(): boolean {
@ -272,10 +276,10 @@ export class ImportComponent implements OnInit, OnDestroy, AfterViewInit {
} }
if (value) { if (value) {
this.collections$ = Utils.asyncToObservable(() => this.collections$ = this.collectionService
this.collectionService .decryptedCollections$(this.activeUserId$)
.getAllDecrypted() .pipe(
.then((decryptedCollections) => map((decryptedCollections) =>
decryptedCollections decryptedCollections
.filter((c2) => c2.organizationId === value && c2.manage) .filter((c2) => c2.organizationId === value && c2.manage)
.sort(Utils.getSortFunction(this.i18nService, "name")), .sort(Utils.getSortFunction(this.i18nService, "name")),

View File

@ -33,11 +33,14 @@ import {
import { BaseVaultExportService } from "./base-vault-export.service"; import { BaseVaultExportService } from "./base-vault-export.service";
import { OrganizationVaultExportServiceAbstraction } from "./org-vault-export.service.abstraction"; import { OrganizationVaultExportServiceAbstraction } from "./org-vault-export.service.abstraction";
import { ExportFormat } from "./vault-export.service.abstraction"; import { ExportFormat } from "./vault-export.service.abstraction";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
export class OrganizationVaultExportService export class OrganizationVaultExportService
extends BaseVaultExportService extends BaseVaultExportService
implements OrganizationVaultExportServiceAbstraction implements OrganizationVaultExportServiceAbstraction
{ {
protected activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
constructor( constructor(
private cipherService: CipherService, private cipherService: CipherService,
private apiService: ApiService, private apiService: ApiService,
@ -185,9 +188,13 @@ export class OrganizationVaultExportService
const promises = []; const promises = [];
promises.push( promises.push(
this.collectionService.getAllDecrypted().then(async (collections) => { firstValueFrom(this.collectionService.decryptedCollections$(this.activeUserId$)).then(
decCollections = collections.filter((c) => c.organizationId == organizationId && c.manage); (collections) => {
}), decCollections = collections.filter(
(c) => c.organizationId == organizationId && c.manage,
);
},
),
); );
promises.push( promises.push(
@ -217,9 +224,13 @@ export class OrganizationVaultExportService
const promises = []; const promises = [];
promises.push( promises.push(
this.collectionService.getAll().then((collections) => { firstValueFrom(this.collectionService.encryptedCollections$(this.activeUserId$)).then(
encCollections = collections.filter((c) => c.organizationId == organizationId && c.manage); (collections) => {
}), encCollections = collections.filter(
(c) => c.organizationId == organizationId && c.manage,
);
},
),
); );
promises.push( promises.push(

View File

@ -21,6 +21,8 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { PolicyType } from "@bitwarden/common/admin-console/enums"; import { PolicyType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; 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 { EventType } from "@bitwarden/common/enums"; import { EventType } from "@bitwarden/common/enums";
import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service"; import { FileDownloadService } from "@bitwarden/common/platform/abstractions/file-download/file-download.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -150,6 +152,8 @@ export class ExportComponent implements OnInit, OnDestroy, AfterViewInit {
{ name: ".json (Encrypted)", value: "encrypted_json" }, { name: ".json (Encrypted)", value: "encrypted_json" },
]; ];
protected activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
private onlyManagedCollections = true; private onlyManagedCollections = true;
@ -167,6 +171,7 @@ export class ExportComponent implements OnInit, OnDestroy, AfterViewInit {
protected dialogService: DialogService, protected dialogService: DialogService,
protected organizationService: OrganizationService, protected organizationService: OrganizationService,
private collectionService: CollectionService, private collectionService: CollectionService,
protected accountService: AccountService,
) {} ) {}
async ngOnInit() { async ngOnInit() {
@ -204,7 +209,7 @@ export class ExportComponent implements OnInit, OnDestroy, AfterViewInit {
} }
this.organizations$ = combineLatest({ this.organizations$ = combineLatest({
collections: this.collectionService.decryptedCollections$, collections: this.collectionService.decryptedCollections$(this.activeUserId$),
memberOrganizations: this.organizationService.memberOrganizations$, memberOrganizations: this.organizationService.memberOrganizations$,
}).pipe( }).pipe(
map(({ collections, memberOrganizations }) => { map(({ collections, memberOrganizations }) => {

View File

@ -5,6 +5,8 @@ import { CollectionService } from "@bitwarden/admin-console/common";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; 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 { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { OrganizationUserStatusType, PolicyType } from "@bitwarden/common/admin-console/enums"; import { OrganizationUserStatusType, PolicyType } from "@bitwarden/common/admin-console/enums";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { getUserId } from "@bitwarden/common/auth/services/account.service";
import { CipherId } from "@bitwarden/common/types/guid"; import { CipherId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
@ -29,6 +31,9 @@ export class DefaultCipherFormConfigService implements CipherFormConfigService {
private cipherService: CipherService = inject(CipherService); private cipherService: CipherService = inject(CipherService);
private folderService: FolderService = inject(FolderService); private folderService: FolderService = inject(FolderService);
private collectionService: CollectionService = inject(CollectionService); private collectionService: CollectionService = inject(CollectionService);
private accountService = inject(AccountService);
protected activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
async buildConfig( async buildConfig(
mode: CipherFormMode, mode: CipherFormMode,
@ -39,9 +44,9 @@ export class DefaultCipherFormConfigService implements CipherFormConfigService {
await firstValueFrom( await firstValueFrom(
combineLatest([ combineLatest([
this.organizations$, this.organizations$,
this.collectionService.encryptedCollections$.pipe( this.collectionService.encryptedCollections$(this.activeUserId$).pipe(
switchMap((c) => switchMap((c) =>
this.collectionService.decryptedCollections$.pipe( this.collectionService.decryptedCollections$(this.activeUserId$).pipe(
filter((d) => d.length === c.length), // Ensure all collections have been decrypted filter((d) => d.length === c.length), // Ensure all collections have been decrypted
), ),
), ),

View File

@ -1,13 +1,14 @@
import { CommonModule } from "@angular/common"; import { CommonModule } from "@angular/common";
import { Component, Input, OnChanges, OnDestroy } from "@angular/core"; 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 { CollectionService, CollectionView } from "@bitwarden/admin-console/common";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; 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 { isCardExpired } from "@bitwarden/common/autofill/utils"; 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"; import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view"; import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
@ -56,10 +57,13 @@ export class CipherViewComponent implements OnChanges, OnDestroy {
private destroyed$: Subject<void> = new Subject(); private destroyed$: Subject<void> = new Subject();
cardIsExpired: boolean = false; cardIsExpired: boolean = false;
private activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
constructor( constructor(
private organizationService: OrganizationService, private organizationService: OrganizationService,
private collectionService: CollectionService, private collectionService: CollectionService,
private folderService: FolderService, private folderService: FolderService,
private accountService: AccountService,
) {} ) {}
async ngOnChanges() { async ngOnChanges() {
@ -98,8 +102,12 @@ export class CipherViewComponent implements OnChanges, OnDestroy {
(!this.collections || this.collections.length === 0) (!this.collections || this.collections.length === 0)
) { ) {
this.collections = await firstValueFrom( this.collections = await firstValueFrom(
this.collectionService.decryptedCollectionViews$( this.collectionService
this.cipher.collectionIds as CollectionId[], .decryptedCollections$(this.activeUserId$)
.pipe(
map((allCollections) =>
allCollections.filter((c) => this.cipher.collectionIds.includes(c.id)),
),
), ),
); );
} }

View File

@ -28,8 +28,9 @@ import { OrganizationService } from "@bitwarden/common/admin-console/abstraction
import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums"; import { OrganizationUserStatusType } from "@bitwarden/common/admin-console/enums";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; 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 { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { CipherId, CollectionId, OrganizationId, UserId } from "@bitwarden/common/types/guid"; import { CipherId, CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { import {
@ -170,7 +171,7 @@ export class AssignCollectionsComponent implements OnInit, OnDestroy, AfterViewI
private get selectedOrgId(): OrganizationId { private get selectedOrgId(): OrganizationId {
return this.formGroup.getRawValue().selectedOrg || this.params.organizationId; return this.formGroup.getRawValue().selectedOrg || this.params.organizationId;
} }
private activeUserId: UserId; private activeUserId$ = this.accountService.activeAccount$.pipe(getUserId);
private destroy$ = new Subject<void>(); private destroy$ = new Subject<void>();
constructor( constructor(
@ -184,10 +185,6 @@ export class AssignCollectionsComponent implements OnInit, OnDestroy, AfterViewI
) {} ) {}
async ngOnInit() { async ngOnInit() {
this.activeUserId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const onlyPersonalItems = this.params.ciphers.every((c) => c.organizationId == null); const onlyPersonalItems = this.params.ciphers.every((c) => c.organizationId == null);
if (this.selectedOrgId === MY_VAULT_ID || onlyPersonalItems) { if (this.selectedOrgId === MY_VAULT_ID || onlyPersonalItems) {
@ -405,7 +402,7 @@ export class AssignCollectionsComponent implements OnInit, OnDestroy, AfterViewI
*/ */
private getCollectionsForOrganization(orgId: OrganizationId): Observable<CollectionView[]> { private getCollectionsForOrganization(orgId: OrganizationId): Observable<CollectionView[]> {
return combineLatest([ return combineLatest([
this.collectionService.decryptedCollections$, this.collectionService.decryptedCollections$(this.activeUserId$),
this.organizationService.organizations$, this.organizationService.organizations$,
]).pipe( ]).pipe(
map(([collections, organizations]) => { map(([collections, organizations]) => {
@ -429,7 +426,7 @@ export class AssignCollectionsComponent implements OnInit, OnDestroy, AfterViewI
shareableCiphers, shareableCiphers,
organizationId, organizationId,
selectedCollectionIds, selectedCollectionIds,
this.activeUserId, await firstValueFrom(this.activeUserId$),
); );
this.toastService.showToast({ this.toastService.showToast({
@ -470,7 +467,10 @@ export class AssignCollectionsComponent implements OnInit, OnDestroy, AfterViewI
private async updateAssignedCollections(cipherView: CipherView) { private async updateAssignedCollections(cipherView: CipherView) {
const { collections } = this.formGroup.getRawValue(); const { collections } = this.formGroup.getRawValue();
cipherView.collectionIds = collections.map((i) => i.id as CollectionId); cipherView.collectionIds = collections.map((i) => i.id as CollectionId);
const cipher = await this.cipherService.encrypt(cipherView, this.activeUserId); const cipher = await this.cipherService.encrypt(
cipherView,
await firstValueFrom(this.activeUserId$),
);
if (this.params.isSingleCipherAdmin) { if (this.params.isSingleCipherAdmin) {
await this.cipherService.saveCollectionsWithServerAdmin(cipher); await this.cipherService.saveCollectionsWithServerAdmin(cipher);
} else { } else {