diff --git a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts index 8763b75ffca..add75cb2002 100644 --- a/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts +++ b/apps/web/src/app/admin-console/organizations/shared/components/collection-dialog/collection-dialog.component.ts @@ -39,6 +39,7 @@ import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; +import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; import { DIALOG_DATA, DialogConfig, @@ -87,8 +88,8 @@ enum ButtonType { } export interface CollectionDialogParams { - collectionId?: string; - organizationId: string; + collectionId?: CollectionId; + organizationId: OrganizationId; initialTab?: CollectionDialogTabType; parentCollectionId?: string; showOrgSelector?: boolean; @@ -136,7 +137,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy { externalId: { value: "", disabled: true }, parent: undefined as string | undefined, access: [[] as AccessItemValue[]], - selectedOrg: "", + selectedOrg: "" as OrganizationId, }); protected PermissionMode = PermissionMode; protected showDeleteButton = false; diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service.ts b/apps/web/src/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service.ts index a42b5228272..b490e9339f4 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/services/routed-vault-filter.service.ts @@ -2,6 +2,8 @@ import { Injectable, OnDestroy } from "@angular/core"; import { ActivatedRoute, NavigationExtras } from "@angular/router"; import { combineLatest, map, Observable, Subject, takeUntil } from "rxjs"; +import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; + import { isRoutedVaultFilterItemType, RoutedVaultFilterModel, @@ -31,10 +33,11 @@ export class RoutedVaultFilterService implements OnDestroy { const type = isRoutedVaultFilterItemType(unsafeType) ? unsafeType : undefined; return { - collectionId: queryParams.get("collectionId") ?? undefined, + collectionId: (queryParams.get("collectionId") ?? undefined) as CollectionId, folderId: queryParams.get("folderId") ?? undefined, - organizationId: - params.get("organizationId") ?? queryParams.get("organizationId") ?? undefined, + organizationId: (params.get("organizationId") ?? + queryParams.get("organizationId") ?? + undefined) as OrganizationId, organizationIdParamType: params.get("organizationId") != undefined ? ("path" as const) : ("query" as const), type, diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter-bridge.model.ts b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter-bridge.model.ts index fe236a089e0..93a7f81d08d 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter-bridge.model.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter-bridge.model.ts @@ -1,4 +1,5 @@ import { Unassigned } from "@bitwarden/admin-console/common"; +import { CollectionId } from "@bitwarden/common/types/guid"; import { CipherType } from "@bitwarden/common/vault/enums"; import { TreeNode } from "@bitwarden/common/vault/models/domain/tree-node"; @@ -65,7 +66,7 @@ export class RoutedVaultFilterBridge implements VaultFilter { let type: RoutedVaultFilterItemType | undefined; if (value?.node.id === "AllItems" && this.routedFilter.organizationIdParamType === "path") { - type = "all"; + type = All; } else if ( value?.node.id === "AllItems" && this.routedFilter.organizationIdParamType === "query" @@ -98,7 +99,7 @@ export class RoutedVaultFilterBridge implements VaultFilter { return this.legacyFilter.selectedCollectionNode; } set selectedCollectionNode(value: TreeNode) { - let collectionId: string | undefined; + let collectionId: CollectionId | undefined; if (value != null && value.node.id === null) { collectionId = Unassigned; diff --git a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter.model.ts b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter.model.ts index 866ba1d9848..b85a5c32354 100644 --- a/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter.model.ts +++ b/apps/web/src/app/vault/individual-vault/vault-filter/shared/models/routed-vault-filter.model.ts @@ -1,4 +1,9 @@ -export const All = "all"; +import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; + +/** + * Represents viewing all collections for an organization + */ +export const All = "all" as CollectionId; // TODO: Remove `All` when moving to vertical navigation. const itemTypes = [ @@ -19,9 +24,9 @@ export function isRoutedVaultFilterItemType(value: unknown): value is RoutedVaul } export interface RoutedVaultFilterModel { - collectionId?: string; + collectionId?: CollectionId; folderId?: string; - organizationId?: string; + organizationId?: OrganizationId; type?: RoutedVaultFilterItemType; organizationIdParamType?: "path" | "query"; diff --git a/libs/admin-console/src/common/collections/models/collection-admin.view.ts b/libs/admin-console/src/common/collections/models/collection-admin.view.ts index dd7a57013ca..363eb7d8721 100644 --- a/libs/admin-console/src/common/collections/models/collection-admin.view.ts +++ b/libs/admin-console/src/common/collections/models/collection-admin.view.ts @@ -1,10 +1,14 @@ import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; +import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; import { CollectionAccessSelectionView } from "./collection-access-selection.view"; import { CollectionAccessDetailsResponse } from "./collection.response"; import { CollectionView } from "./collection.view"; -export const Unassigned = "unassigned"; +// TODO: this is used to represent the pseudo "Unassigned" collection +// AND ALSO the user's personal vault - this should be separated out to different consts. +// The type union allows this to be glossed over for now. +export const Unassigned = "unassigned" as CollectionId & OrganizationId; export class CollectionAdminView extends CollectionView { groups: CollectionAccessSelectionView[] = []; diff --git a/libs/admin-console/src/common/collections/models/collection.ts b/libs/admin-console/src/common/collections/models/collection.ts index 75d68222b38..4c016543712 100644 --- a/libs/admin-console/src/common/collections/models/collection.ts +++ b/libs/admin-console/src/common/collections/models/collection.ts @@ -2,6 +2,7 @@ // @ts-strict-ignore import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; import Domain from "@bitwarden/common/platform/models/domain/domain-base"; +import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; import { OrgKey } from "@bitwarden/common/types/key"; import { CollectionData } from "./collection.data"; @@ -15,8 +16,8 @@ export const CollectionTypes = { export type CollectionType = (typeof CollectionTypes)[keyof typeof CollectionTypes]; export class Collection extends Domain { - id: string; - organizationId: string; + id: CollectionId; + organizationId: OrganizationId; name: EncString; externalId: string; readOnly: boolean; diff --git a/libs/admin-console/src/common/collections/models/collection.view.ts b/libs/admin-console/src/common/collections/models/collection.view.ts index bce1d558f96..18ecf2f5528 100644 --- a/libs/admin-console/src/common/collections/models/collection.view.ts +++ b/libs/admin-console/src/common/collections/models/collection.view.ts @@ -2,6 +2,7 @@ import { Jsonify } from "type-fest"; import { Organization } from "@bitwarden/common/admin-console/models/domain/organization"; import { View } from "@bitwarden/common/models/view/view"; +import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; import { ITreeNodeObject } from "@bitwarden/common/vault/models/domain/tree-node"; import { Collection, CollectionType, CollectionTypes } from "./collection"; @@ -10,8 +11,8 @@ import { CollectionAccessDetailsResponse } from "./collection.response"; export const NestingDelimiter = "/"; export class CollectionView implements View, ITreeNodeObject { - id: string | undefined; - organizationId: string | undefined; + id: CollectionId | undefined; + organizationId: OrganizationId | undefined; name: string | undefined; externalId: string | undefined; // readOnly applies to the items within a collection diff --git a/libs/common/src/models/export/collection-with-id.export.ts b/libs/common/src/models/export/collection-with-id.export.ts index a93f07b54e5..1f98e7eed69 100644 --- a/libs/common/src/models/export/collection-with-id.export.ts +++ b/libs/common/src/models/export/collection-with-id.export.ts @@ -4,18 +4,20 @@ // eslint-disable-next-line no-restricted-imports import { Collection as CollectionDomain, CollectionView } from "@bitwarden/admin-console/common"; +import { CollectionId } from "../../types/guid"; + import { CollectionExport } from "./collection.export"; export class CollectionWithIdExport extends CollectionExport { id: string; static toView(req: CollectionWithIdExport, view = new CollectionView()) { - view.id = req.id; + view.id = req.id as CollectionId; return super.toView(req, view); } static toDomain(req: CollectionWithIdExport, domain = new CollectionDomain()) { - domain.id = req.id; + domain.id = req.id as CollectionId; return super.toDomain(req, domain); } diff --git a/libs/common/src/models/export/collection.export.ts b/libs/common/src/models/export/collection.export.ts index 88b68c08c58..c58ea05e089 100644 --- a/libs/common/src/models/export/collection.export.ts +++ b/libs/common/src/models/export/collection.export.ts @@ -5,6 +5,7 @@ import { Collection as CollectionDomain, CollectionView } from "@bitwarden/admin-console/common"; import { EncString } from "../../key-management/crypto/models/enc-string"; +import { OrganizationId } from "../../types/guid"; import { safeGetString } from "./utils"; @@ -21,7 +22,7 @@ export class CollectionExport { view.name = req.name; view.externalId = req.externalId; if (view.organizationId == null) { - view.organizationId = req.organizationId; + view.organizationId = req.organizationId as OrganizationId; } return view; } @@ -30,7 +31,7 @@ export class CollectionExport { domain.name = req.name != null ? new EncString(req.name) : null; domain.externalId = req.externalId; if (domain.organizationId == null) { - domain.organizationId = req.organizationId; + domain.organizationId = req.organizationId as OrganizationId; } return domain; } diff --git a/libs/importer/src/importers/base-importer.ts b/libs/importer/src/importers/base-importer.ts index 463d61dbbdf..ab5d3078720 100644 --- a/libs/importer/src/importers/base-importer.ts +++ b/libs/importer/src/importers/base-importer.ts @@ -9,6 +9,7 @@ import { normalizeExpiryYearFormat } from "@bitwarden/common/autofill/utils"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { Utils } from "@bitwarden/common/platform/misc/utils"; import { ConsoleLogService } from "@bitwarden/common/platform/services/console-log.service"; +import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid"; import { FieldType, SecureNoteType, CipherType } from "@bitwarden/common/vault/enums"; import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; import { FieldView } from "@bitwarden/common/vault/models/view/field.view"; @@ -20,7 +21,7 @@ import { SecureNoteView } from "@bitwarden/common/vault/models/view/secure-note. import { ImportResult } from "../models/import-result"; export abstract class BaseImporter { - organizationId: string = null; + organizationId: OrganizationId = null; // FIXME: This should be replaced by injecting the log service. protected logService: LogService = new ConsoleLogService(false); @@ -279,7 +280,7 @@ export abstract class BaseImporter { result.collections = result.folders.map((f) => { const collection = new CollectionView(); collection.name = f.name; - collection.id = f.id ?? undefined; // folder id may be null, which is not suitable for collections. + collection.id = (f.id as CollectionId) ?? undefined; // folder id may be null, which is not suitable for collections. return collection; }); result.folderRelationships = []; diff --git a/libs/importer/src/services/import.service.ts b/libs/importer/src/services/import.service.ts index c9cb325d10b..e7bf88b5bf5 100644 --- a/libs/importer/src/services/import.service.ts +++ b/libs/importer/src/services/import.service.ts @@ -102,6 +102,7 @@ import { import { ImportResult } from "../models/import-result"; import { ImportApiServiceAbstraction } from "../services/import-api.service.abstraction"; import { ImportServiceAbstraction } from "../services/import.service.abstraction"; +import { OrganizationId } from "@bitwarden/common/types/guid"; export class ImportService implements ImportServiceAbstraction { featuredImportOptions = featuredImportOptions as readonly ImportOption[]; @@ -128,7 +129,7 @@ export class ImportService implements ImportServiceAbstraction { async import( importer: Importer, fileContents: string, - organizationId: string = null, + organizationId: OrganizationId = null, selectedImportTarget: FolderView | CollectionView = null, canAccessImportExport: boolean, ): Promise { @@ -191,7 +192,7 @@ export class ImportService implements ImportServiceAbstraction { getImporter( format: ImportType | "bitwardenpasswordprotected", promptForPassword_callback: () => Promise, - organizationId: string = null, + organizationId: OrganizationId = null, ): Importer { if (promptForPassword_callback == null) { return null; @@ -380,7 +381,10 @@ export class ImportService implements ImportServiceAbstraction { return await this.importApiService.postImportCiphers(request); } - private async handleOrganizationalImport(importResult: ImportResult, organizationId: string) { + private async handleOrganizationalImport( + importResult: ImportResult, + organizationId: OrganizationId, + ) { const request = new ImportOrganizationCiphersRequest(); const activeUserId = await firstValueFrom( this.accountService.activeAccount$.pipe(map((a) => a?.id)),